Builder/spitfire/appindex.go

251 lines
7.2 KiB
Go
Raw Normal View History

2024-09-09 01:25:07 +02:00
package spitfire
import (
"crypto/sha1"
"fmt"
"io"
"log"
"os"
"strings"
"time"
)
// Package the APPINDEX update process
2024-12-23 11:24:42 +01:00
func PackageAPPINDEX(
name, // e.g. "spitfire-browser"
release, // e.g. "nightly"
version, // e.g. "2024.12.21"
arch, // e.g. "amd64"
size, // e.g. "838205457" (compressed size)
installedSize, // e.g. "3595495684" (uncompressed size)
description, // e.g. "Spitfire build"
url, // e.g. "https://spitfirebrowser.xyz/"
license, // e.g. "AGPL-3.0"
origin, // e.g. "browser"
maintainer, // e.g. "Internet Addict"
dependencies, // usually blank ..."
platform, // e.g. "linux"
remoteDir string, // e.g. "nightly/linux/amd64"
) error {
// Construct a filename that matches what you compress & upload
// Adjust this naming convention to match your compress step exactly!
// Example: "spitfire-browser-nightly-amd64-linux.tar.gz"
fileName := fmt.Sprintf("%s-%s-%s-%s.tar.gz", origin, arch, release, platform)
// If you have a real file on disk, you might call `calcChecksum(fileName)`.
// For demo, we call `calcChecksum` with a mock package name.
checksum := calcChecksum(fileName)
// Remove existing entry based on P, R, A, o (if you want to deduplicate).
removeExistingEntry(name, release, arch, origin)
2024-09-09 01:25:07 +02:00
2024-12-23 11:24:42 +01:00
// Use current Unix timestamp
2024-09-09 01:25:07 +02:00
timestamp := time.Now().Unix()
// Open or create the APPINDEX file for appending
file, err := os.OpenFile("./APPINDEX", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Fatalf("Failed to open APPINDEX file: %v", err)
}
defer file.Close()
2024-12-23 11:24:42 +01:00
// Build the SourceForge-based download URL:
// https://downloads.sourceforge.net/project/spitfire-browser/<remoteDir>/<fileName>
downloadURL := fmt.Sprintf("https://downloads.sourceforge.net/project/spitfire-browser/%s/%s", remoteDir, fileName)
// Format the entry.
2024-09-09 01:25:07 +02:00
entry := fmt.Sprintf(`
2024-12-23 11:24:42 +01:00
C:%s
P:%s
R:%s
V:%s
A:%s
S:%s
I:%s
T:%s
U:%s
L:%s
o:%s
m:%s
t:%d
D:%s
p:%s
q:
d:%s
I:https://weforge.xyz/Spitfire/Branding/raw/branch/main/active/browser/icon.svg
S:https://spitfirebrowser.xyz/static/images/screenshots/1.png
T:browser,experimental,testing
r: Automated Nightly build of Spitfire
c:%s
`, checksum, name, release, version, arch, size, installedSize,
description, url, license, origin, maintainer, timestamp, dependencies,
platform, downloadURL, checksum)
// Trim leading newline to keep it clean
entry = strings.TrimPrefix(entry, "\n")
if _, err := file.WriteString(entry + "\n"); err != nil {
2024-09-09 01:25:07 +02:00
log.Fatalf("Failed to write to APPINDEX file: %v", err)
}
fmt.Println("APPINDEX has been updated successfully.")
return nil
}
// calcChecksum calculates a checksum (SHA-1) for a given input string
func calcChecksum(input string) string {
h := sha1.New()
_, _ = io.WriteString(h, input)
return fmt.Sprintf("%x", h.Sum(nil))
}
2024-12-23 11:24:42 +01:00
// removeExistingEntry removes an existing entry from APPINDEX if it matches P, R, A, and o fields.
2024-09-09 01:25:07 +02:00
func removeExistingEntry(name, release, arch, origin string) {
// Read file contents
content, err := os.ReadFile("./APPINDEX")
if err != nil {
if os.IsNotExist(err) {
return // If file does not exist, no need to remove anything
}
log.Fatalf("Failed to read APPINDEX: %v", err)
}
lines := strings.Split(string(content), "\n")
2024-12-23 11:24:42 +01:00
2024-09-09 01:25:07 +02:00
var newLines []string
2024-12-23 11:24:42 +01:00
var currentEntry []string
inEntry := false // true when we're reading lines for a single entry
// Use these to store the P, R, A, o values within the current entry
var pVal, rVal, aVal, oVal string
2024-09-09 01:25:07 +02:00
for _, line := range lines {
2024-12-23 11:24:42 +01:00
trimmed := strings.TrimSpace(line)
// Detect the start of an entry (a line that starts with "C:")
if strings.HasPrefix(trimmed, "C:") {
// If we were in an entry previously, check if it should be removed or kept
if inEntry && len(currentEntry) > 0 {
// Decide whether to keep the previous entry
if !(pVal == name && rVal == release && aVal == arch && oVal == origin) {
newLines = append(newLines, currentEntry...)
newLines = append(newLines, "") // Blank line to separate entries
}
}
// Start a new entry
currentEntry = []string{trimmed}
inEntry = true
// Reset these values for the new entry
pVal, rVal, aVal, oVal = "", "", "", ""
continue
2024-09-09 01:25:07 +02:00
}
2024-12-23 11:24:42 +01:00
if inEntry {
// Collect lines for this entry
currentEntry = append(currentEntry, trimmed)
// Extract P, R, A, o for matching later
switch {
case strings.HasPrefix(trimmed, "P:"):
pVal = strings.TrimPrefix(trimmed, "P:")
case strings.HasPrefix(trimmed, "R:"):
rVal = strings.TrimPrefix(trimmed, "R:")
case strings.HasPrefix(trimmed, "A:"):
aVal = strings.TrimPrefix(trimmed, "A:")
case strings.HasPrefix(trimmed, "o:"):
oVal = strings.TrimPrefix(trimmed, "o:")
}
} else {
// Lines outside of entries just get appended directly
// (e.g. if there's extraneous text before the first "C:" or after the last)
if trimmed != "" {
newLines = append(newLines, trimmed)
}
2024-09-09 01:25:07 +02:00
}
2024-12-23 11:24:42 +01:00
}
2024-09-09 01:25:07 +02:00
2024-12-23 11:24:42 +01:00
// Handle the last entry if we ended inEntry
if inEntry && len(currentEntry) > 0 {
// Decide whether to keep the final entry
if !(pVal == name && rVal == release && aVal == arch && oVal == origin) {
newLines = append(newLines, currentEntry...)
2024-09-09 01:25:07 +02:00
}
}
2024-12-23 11:24:42 +01:00
// Join everything back and ensure at least one trailing newline
finalContent := strings.Join(newLines, "\n")
if !strings.HasSuffix(finalContent, "\n") {
finalContent += "\n"
}
err = os.WriteFile("./APPINDEX", []byte(finalContent), 0644)
2024-09-09 01:25:07 +02:00
if err != nil {
log.Fatalf("Failed to update APPINDEX: %v", err)
}
}
// CleanAppIndex cleans up any orphaned "C:" entries and collapses excessive newlines
func CleanAppIndex() error {
// Read file contents
content, err := os.ReadFile("./APPINDEX")
if err != nil {
return fmt.Errorf("failed to read APPINDEX: %v", err)
}
// Split the file content into lines
lines := strings.Split(string(content), "\n")
var newLines []string
var currentEntry []string
inEntry := false
for _, line := range lines {
line = strings.TrimSpace(line)
// Start of an entry when we encounter a checksum
if strings.HasPrefix(line, "C:") {
// If we already have a valid entry, add it to newLines
if inEntry && len(currentEntry) > 1 {
newLines = append(newLines, currentEntry...)
}
currentEntry = []string{line}
inEntry = true
} else if inEntry && line == "" {
// End of an entry
if len(currentEntry) > 1 {
newLines = append(newLines, currentEntry...)
newLines = append(newLines, "") // Add a blank line to separate entries
}
currentEntry = nil
inEntry = false
} else if inEntry {
// Continue adding lines to the current entry
currentEntry = append(currentEntry, line)
} else if line != "" {
// Add non-entry lines (for extra safety)
newLines = append(newLines, line)
}
}
// In case the last entry was valid
if inEntry && len(currentEntry) > 1 {
newLines = append(newLines, currentEntry...)
}
// Collapse consecutive blank lines
cleanedContent := strings.Join(newLines, "\n")
cleanedContent = strings.ReplaceAll(cleanedContent, "\n\n\n", "\n\n")
// Write the cleaned content back to the file
err = os.WriteFile("./APPINDEX", []byte(cleanedContent), 0644)
if err != nil {
return fmt.Errorf("failed to write cleaned APPINDEX: %v", err)
}
fmt.Println("APPINDEX cleaned successfully.")
return nil
}