diff --git a/README.md b/README.md index ff19e26..54b3411 100644 --- a/README.md +++ b/README.md @@ -124,24 +124,28 @@ go run . -h ## APPINDEX example: ``` -C:905cd0cc2dea9e400e1ecd099462b6b19188a9f1 -P:Spitfire +C:a6af7ebb5c1382084704be0b5714ab026c819d63 +P:spitfire-browser R:nightly -V:2024.09.08 +V:2024.12.23 A:amd64 -S:788506622 -I:3324483350 -T:Spitfire build +S:838594187 +I:3595780372 +T:Spitfire U:https://spitfirebrowser.xyz/ L:AGPL-3.0 o:browser m:Internet Addict -t:1725830641 -c:905cd0cc2dea9e400e1ecd099462b6b19188a9f1 +t:1734949294 D: p:linux q: -Z:905cd0cc2dea9e400e1ecd099462b6b19188a9f1 +d:https://downloads.sourceforge.net/project/spitfire-browser/browser/amd64/nightly/2024.12.23/browser-amd64-nightly-linux.tar.gz +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:a6af7ebb5c1382084704be0b5714ab026c819d63 ``` ## Repository structure diff --git a/main.go b/main.go index 010ba28..ebbad89 100644 --- a/main.go +++ b/main.go @@ -39,6 +39,7 @@ var ( url = "https://spitfirebrowser.xyz/" licence = "AGPL-3.0" name = "Spitfire" + packageName = "spitfire-browser" maintainer = "Internet Addict" initialDir string ) @@ -260,15 +261,20 @@ func PackageAndUploadProcess() { log.Fatalf("Error: no valid build or upload path provided.") } - // Calculate and display uncompressed size + // Calculate & display uncompressed size uncompressedSize, err := spitfire.GetDirectorySize(pathToUse) if err != nil { log.Fatalf("Failed to calculate uncompressed size: %v", err) } fmt.Printf("Uncompressed directory size: %s\n", spitfire.BytesToHumanReadable(uncompressedSize)) - // Compress the build directory - outputCompressedFile := filepath.Join(".", fmt.Sprintf("%s-%s-%s-%s.tar.gz", component, arch, release, platform)) + // Create the tar.gz name, e.g. "browser-amd64-nightly-linux.tar.gz" + outputCompressedFile := filepath.Join(".", fmt.Sprintf( + "%s-%s-%s-%s.tar.gz", + component, arch, release, platform, + )) + + // Compress if requested if compress { err := spitfire.CompressDirectory(pathToUse, outputCompressedFile) if err != nil { @@ -277,61 +283,85 @@ func PackageAndUploadProcess() { fmt.Printf("Build directory compressed to: %s\n", outputCompressedFile) } - // Calculate and display compressed size + // Compressed size compressedSize, err := spitfire.GetFileSize(outputCompressedFile) if err != nil { log.Fatalf("Failed to get compressed file size: %v", err) } fmt.Printf("Compressed file size: %s\n", spitfire.BytesToHumanReadable(compressedSize)) - // Calculate and display compression efficiency + // Show compression ratio & efficiency compressionRatio, efficiency := spitfire.CalculateCompressionEfficiency(uncompressedSize, compressedSize) fmt.Printf("Compression ratio: %.2f:1\n", compressionRatio) fmt.Printf("Compression efficiency: %.2f%%\n", efficiency) - // Handle uploading - if upload { - config, err := spitfire.LoadConfig() - if err != nil { - log.Fatalf("Failed to load SourceForge config: %v", err) - } - - if _, err := os.Stat(outputCompressedFile); err == nil { - err = spitfire.Upload(config, outputCompressedFile, "/home/frs/project/spitfire-browser/"+component+"/"+arch+"/"+release+"/"+version+"/") - if err != nil { - log.Fatalf("Failed to upload compressed file: %v", err) - } - fmt.Println("Compressed file uploaded successfully.") - } else { - log.Fatalf("No compressed file found to upload.") - } - - err = spitfire.DownloadAPPINDEX(config, "/home/frs/project/spitfire-browser/") - if err != nil { - fmt.Println("Failed to download APPINDEX. A new APPINDEX will be created and uploaded.") - } - - err = spitfire.PackageAPPINDEX( - name, release, version, arch, - fmt.Sprintf("%d", compressedSize), - fmt.Sprintf("%d", uncompressedSize), - "Spitfire build", url, licence, component, maintainer, "", platform, - ) - if err != nil { - log.Fatalf("Failed to update APPINDEX: %v", err) - } - fmt.Println("APPINDEX updated successfully.") - - if err := spitfire.CleanAppIndex(); err != nil { - log.Fatalf("Failed to clean APPINDEX: %v", err) - } - - err = spitfire.UploadAPPINDEX(config, "/home/frs/project/spitfire-browser/") - if err != nil { - log.Fatalf("Failed to upload updated APPINDEX: %v", err) - } - fmt.Println("APPINDEX uploaded successfully.") + // If not uploading, we're done + if !upload { + return } + + // Load SourceForge config + config, err := spitfire.LoadConfig() + if err != nil { + log.Fatalf("Failed to load SourceForge config: %v", err) + } + + // Check tarball existence + if _, err := os.Stat(outputCompressedFile); err != nil { + log.Fatalf("No compressed file found to upload: %v", err) + } + + // The subdirectory path in the SF project + // e.g. "browser/amd64/nightly/2024.12.23" + uploadDir := fmt.Sprintf("%s/%s/%s/%s", component, arch, release, version) + + // 1) Upload the file to SourceForge once + err = spitfire.Upload(config, outputCompressedFile, + "/home/frs/project/spitfire-browser/"+uploadDir+"/") + if err != nil { + log.Fatalf("Failed to upload compressed file: %v", err) + } + fmt.Println("Compressed file uploaded successfully.") + + // 2) Download existing APPINDEX or create new + err = spitfire.DownloadAPPINDEX(config, "/home/frs/project/spitfire-browser/") + if err != nil { + fmt.Println("Failed to download APPINDEX. A new one will be created and uploaded.") + } + + // 3) Update the APPINDEX + err = spitfire.PackageAPPINDEX( + packageName, // e.g. "spitfire-browser" + release, // e.g. "nightly" + version, // e.g. "2024.12.23" + arch, + fmt.Sprintf("%d", compressedSize), + fmt.Sprintf("%d", uncompressedSize), + name, // e.g. "Spitfire" + url, + licence, + component, + maintainer, + "", // dependencies + platform, + uploadDir, + ) + if err != nil { + log.Fatalf("Failed to update APPINDEX: %v", err) + } + fmt.Println("APPINDEX updated successfully.") + + // 4) Clean + if err := spitfire.CleanAppIndex(); err != nil { + log.Fatalf("Failed to clean APPINDEX: %v", err) + } + + // 5) Upload the updated APPINDEX + err = spitfire.UploadAPPINDEX(config, "/home/frs/project/spitfire-browser/") + if err != nil { + log.Fatalf("Failed to upload updated APPINDEX: %v", err) + } + fmt.Println("APPINDEX uploaded successfully.") } // restoreWorkingDirectory restores the initial working directory after any operation that might change it. diff --git a/spitfire/appindex.go b/spitfire/appindex.go index 50a9131..a25e305 100644 --- a/spitfire/appindex.go +++ b/spitfire/appindex.go @@ -11,20 +11,38 @@ import ( ) // Package the APPINDEX update process -func PackageAPPINDEX(name, release, version, arch, size, installedSize, description, url, license, origin, maintainer, dependencies, platform string) error { - // Mock package file name - pkgFile := fmt.Sprintf("%s-%s", name, version) +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 { - // Calculate checksums - checksum := calcChecksum(pkgFile) - contentChecksum := calcChecksum(pkgFile) + // 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) - // Timestamp - timestamp := time.Now().Unix() + // 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, and o fields + // Remove existing entry based on P, R, A, o (if you want to deduplicate). removeExistingEntry(name, release, arch, origin) + // Use current Unix timestamp + 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 { @@ -32,30 +50,42 @@ func PackageAPPINDEX(name, release, version, arch, size, installedSize, descript } defer file.Close() - // Write the new entry + // Build the SourceForge-based download URL: + // https://downloads.sourceforge.net/project/spitfire-browser// + downloadURL := fmt.Sprintf("https://downloads.sourceforge.net/project/spitfire-browser/%s/%s", remoteDir, fileName) + + // Format the entry. entry := fmt.Sprintf(` -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 -c:%s -D:%s -p:%s -q: -Z:%s + 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) -`, checksum, name, release, version, arch, size, installedSize, description, url, license, origin, maintainer, timestamp, contentChecksum, dependencies, platform, checksum) + // Trim leading newline to keep it clean + entry = strings.TrimPrefix(entry, "\n") - if _, err := file.WriteString(entry); err != nil { + if _, err := file.WriteString(entry + "\n"); err != nil { log.Fatalf("Failed to write to APPINDEX file: %v", err) } @@ -70,7 +100,7 @@ func calcChecksum(input string) string { return fmt.Sprintf("%x", h.Sum(nil)) } -// removeExistingEntry removes an existing entry from APPINDEX based on P, R, A, and o fields +// removeExistingEntry removes an existing entry from APPINDEX if it matches P, R, A, and o fields. func removeExistingEntry(name, release, arch, origin string) { // Read file contents content, err := os.ReadFile("./APPINDEX") @@ -81,39 +111,78 @@ func removeExistingEntry(name, release, arch, origin string) { log.Fatalf("Failed to read APPINDEX: %v", err) } - // Remove lines matching the package with the same P, R, A, and o fields lines := strings.Split(string(content), "\n") + var newLines []string - remove := false + 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 + for _, line := range lines { - // Detect start of an entry by matching on P, R, A, and o - if strings.HasPrefix(line, "P:"+name) { - remove = true - } - if remove && strings.HasPrefix(line, "R:"+release) { - remove = true - } - if remove && strings.HasPrefix(line, "A:"+arch) { - remove = true - } - if remove && strings.HasPrefix(line, "o:"+origin) { - remove = true + 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 } - // Stop removal at the end of an entry - if remove && line == "" { - remove = false - continue // Skip the line - } + if inEntry { + // Collect lines for this entry + currentEntry = append(currentEntry, trimmed) - // Append lines that are not part of the matching entry - if !remove { - newLines = append(newLines, line) + // 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) + } } } - // Write the updated contents back to the file - err = os.WriteFile("./APPINDEX", []byte(strings.Join(newLines, "\n")), 0644) + // 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...) + } + } + + // 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) if err != nil { log.Fatalf("Failed to update APPINDEX: %v", err) }