diff options
| -rw-r--r-- | Makefile | 1 | ||||
| -rw-r--r-- | apt.makedistro.go | 332 |
2 files changed, 1 insertions, 332 deletions
@@ -31,6 +31,7 @@ goimports: clean: rm -f go.* + go-mod-clean purge gpl: wit-test --witcom diff --git a/apt.makedistro.go b/apt.makedistro.go deleted file mode 100644 index 510bbd0..0000000 --- a/apt.makedistro.go +++ /dev/null @@ -1,332 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "compress/gzip" - "crypto/md5" - "crypto/sha1" - "crypto/sha256" - "fmt" - "io" - "log" - "os" - "os/exec" - "path/filepath" - "strings" - "time" -) - -// --- Configuration --- -// !!! IMPORTANT: Set your GPG Key ID here! -// Find it with: gpg --list-secret-keys --keyid-format=long -const gpgKeyID = "YOUR_GPG_KEY_ID" - -const dist = "sid" -const component = "main" -const poolDir = "pool" -const distsDir = "dists" - -var architectures = []string{"amd64", "riscv64", "all"} - -// DebInfo holds the control information for a single .deb package. -type DebInfo struct { - ControlData map[string]string - Filename string - Size int64 - MD5Sum string - SHA1Sum string - SHA256Sum string -} - -func makeDistroFiles() { - log.Println("--- Starting Debian repository generation in Go ---") - - if gpgKeyID == "YOUR_GPG_KEY_ID" || gpgKeyID == "" { - log.Fatal("ERROR: Please set the 'gpgKeyID' constant at the top of the script.") - } - - // 1. Clean and create directory structure - distPath := filepath.Join(distsDir, dist) - log.Printf("Cleaning up old dists directory: %s", distPath) - if err := os.RemoveAll(distPath); err != nil { - log.Fatalf("Failed to remove old dists directory: %v", err) - } - - log.Println("Creating new directory structure...") - for _, arch := range architectures { - binPath := filepath.Join(distPath, component, "binary-"+arch) - if err := os.MkdirAll(binPath, 0755); err != nil { - log.Fatalf("Failed to create directory %s: %v", binPath, err) - } - } - - // 2. Scan pool directory for .deb files and gather info - log.Printf("Scanning for .deb files in %s/ જુ", poolDir) - debInfos, err := scanDebs(poolDir) - if err != nil { - log.Fatalf("Failed to scan .deb files: %v", err) - } - log.Printf("Found %d total .deb packages.", len(debInfos)) - - // 3. Group packages by architecture - debsByArch := make(map[string][]DebInfo) - for _, deb := range debInfos { - arch := deb.ControlData["Architecture"] - debsByArch[arch] = append(debsByArch[arch], deb) - } - // Add the 'all' packages to each specific architecture list as well, as is standard. - for _, arch := range architectures { - if arch != "all" { - debsByArch[arch] = append(debsByArch[arch], debsByArch["all"]...) - } - } - - // 4. Generate Packages files - log.Println("Generating Packages files...") - for _, arch := range architectures { - binPath := filepath.Join(distPath, component, "binary-"+arch) - packagesFile := filepath.Join(binPath, "Packages") - - var content strings.Builder - for _, deb := range debsByArch[arch] { - for key, val := range deb.ControlData { - fmt.Fprintf(&content, "%s: %s\n", key, val) - } - fmt.Fprintf(&content, "Filename: %s\n", deb.Filename) - fmt.Fprintf(&content, "Size: %d\n", deb.Size) - fmt.Fprintf(&content, "MD5sum: %s\n", deb.MD5Sum) - fmt.Fprintf(&content, "SHA1: %s\n", deb.SHA1Sum) - fmt.Fprintf(&content, "SHA256: %s\n", deb.SHA256Sum) - fmt.Fprintln(&content) - } - - if err := os.WriteFile(packagesFile, []byte(content.String()), 0644); err != nil { - log.Fatalf("Failed to write Packages file for %s: %v", arch, err) - } - - // Compress the Packages file - if err := compressFile(packagesFile, "gz"); err != nil { - log.Fatalf("Failed to gzip Packages file for %s: %v", arch, err) - } - if err := compressFile(packagesFile, "bz2"); err != nil { - log.Fatalf("Failed to bzip2 Packages file for %s: %v", arch, err) - } - } - - // 5. Generate and sign the Release file - log.Println("Generating and signing Release file...") - if err := generateAndSignReleaseFile(distPath); err != nil { - log.Fatalf("Failed to generate or sign Release file: %v", err) - } - - log.Println("--- Repository generation complete! ---") -} - -// scanDebs finds all .deb files and extracts their metadata. -func scanDebs(root string) ([]DebInfo, error) { - var debs []DebInfo - err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() && strings.HasSuffix(info.Name(), ".deb") { - log.Printf(" -> Processing %s", path) - - // Get control info - cmd := exec.Command("dpkg-deb", "-I", path) - var out bytes.Buffer - cmd.Stdout = &out - if err := cmd.Run(); err != nil { - return fmt.Errorf("failed to run dpkg-deb on %s: %v", path, err) - } - - controlData := parseControlData(out.String()) - - // Get checksums - md5sum, sha1sum, sha256sum, err := getChecksums(path) - if err != nil { - return err - } - - relativePath, err := filepath.Rel(".", path) - if err != nil { - return err - } - - debs = append(debs, DebInfo{ - ControlData: controlData, - Filename: relativePath, - Size: info.Size(), - MD5Sum: md5sum, - SHA1Sum: sha1sum, - SHA256Sum: sha256sum, - }) - } - return nil - }) - return debs, err -} - -// parseControlData converts the text output of dpkg-deb into a map. -func parseControlData(data string) map[string]string { - control := make(map[string]string) - scanner := bufio.NewScanner(strings.NewReader(data)) - for scanner.Scan() { - line := strings.TrimSpace(scanner.Text()) - parts := strings.SplitN(line, ":", 2) - if len(parts) == 2 { - control[strings.TrimSpace(parts[0])] = strings.TrimSpace(parts[1]) - } - } - return control -} - -// getChecksums calculates all required hashes for a file. -// FIX 1: Renamed return variables to avoid shadowing package names. -func getChecksums(filePath string) (md5sum, sha1sum, sha256sum string, err error) { - file, err := os.Open(filePath) - if err != nil { - return "", "", "", err - } - defer file.Close() - - hMD5 := md5.New() - hSHA1 := sha1.New() - hSHA256 := sha256.New() - - // TeeReader allows writing to multiple hashers at once - multiWriter := io.MultiWriter(hMD5, hSHA1, hSHA256) - if _, err := io.Copy(multiWriter, file); err != nil { - return "", "", "", err - } - - return fmt.Sprintf("%x", hMD5.Sum(nil)), - fmt.Sprintf("%x", hSHA1.Sum(nil)), - fmt.Sprintf("%x", hSHA256.Sum(nil)), - nil -} - -// compressFile creates a compressed version of a file (gz or bz2). -func compressFile(sourcePath, format string) error { - if format == "gz" { - sourceFile, err := os.Open(sourcePath) - if err != nil { - return err - } - defer sourceFile.Close() - - destPath := sourcePath + ".gz" - destFile, err := os.Create(destPath) - if err != nil { - return err - } - defer destFile.Close() - - writer := gzip.NewWriter(destFile) - defer writer.Close() - - _, err = io.Copy(writer, sourceFile) - return err - } else if format == "bz2" { - // FIX 2: Shell out to the bzip2 command for compression. - destPath := sourcePath + ".bz2" - cmd := exec.Command("bzip2", "-c", sourcePath) - - outfile, err := os.Create(destPath) - if err != nil { - return fmt.Errorf("failed to create destination file for bzip2: %v", err) - } - defer outfile.Close() - cmd.Stdout = outfile - - return runCommand(cmd) - } - - return fmt.Errorf("unsupported compression format: %s", format) -} - -// generateAndSignReleaseFile creates the main Release file and signs it. -func generateAndSignReleaseFile(distPath string) error { - releasePath := filepath.Join(distPath, "Release") - var content strings.Builder - - // Add headers - fmt.Fprintf(&content, "Origin: Your Repository\n") - fmt.Fprintf(&content, "Label: Your Repository\n") - fmt.Fprintf(&content, "Suite: %s\n", dist) - fmt.Fprintf(&content, "Codename: %s\n", dist) - fmt.Fprintf(&content, "Date: %s\n", time.Now().UTC().Format(time.RFC1123Z)) - fmt.Fprintf(&content, "Architectures: %s\n", strings.Join(architectures, " ")) - fmt.Fprintf(&content, "Components: %s\n", component) - fmt.Fprintf(&content, "Description: A cool repository\n") - - // Add checksums - addChecksums := func(name string) { - fmt.Fprintf(&content, "%s:\n", name) - err := filepath.Walk(distPath, func(path string, info os.FileInfo, err error) error { - if err != nil { - return err - } - if !info.IsDir() && info.Name() != "Release" && info.Name() != "InRelease" && info.Name() != "Release.gpg" { - relativePath, _ := filepath.Rel(distPath, path) - - fileBytes, err := os.ReadFile(path) - if err != nil { - return err - } - - var sum string - switch name { - case "MD5Sum": - sum = fmt.Sprintf("%x", md5.Sum(fileBytes)) - case "SHA1": - sum = fmt.Sprintf("%x", sha1.Sum(fileBytes)) - case "SHA256": - // FIX 3: Use the correct sha256.Sum256 function. - sum = fmt.Sprintf("%x", sha256.Sum256(fileBytes)) - } - fmt.Fprintf(&content, " %s %d %s\n", sum, info.Size(), relativePath) - } - return nil - }) - if err != nil { - log.Printf("Warning: could not walk path for checksums: %v", err) - } - } - - addChecksums("MD5Sum") - addChecksums("SHA1") - addChecksums("SHA256") - - if err := os.WriteFile(releasePath, []byte(content.String()), 0644); err != nil { - return fmt.Errorf("failed to write Release file: %v", err) - } - - // Sign the file - log.Println("Signing with GPG key:", gpgKeyID) - - // Create InRelease - cmdClearSign := exec.Command("gpg", "--default-key", gpgKeyID, "--clearsign", "-o", filepath.Join(distPath, "InRelease"), releasePath) - if err := runCommand(cmdClearSign); err != nil { - return fmt.Errorf("failed to create InRelease: %v", err) - } - - // Create Release.gpg - cmdDetachedSign := exec.Command("gpg", "--default-key", gpgKeyID, "-abs", "-o", filepath.Join(distPath, "Release.gpg"), releasePath) - if err := runCommand(cmdDetachedSign); err != nil { - return fmt.Errorf("failed to create Release.gpg: %v", err) - } - - return nil -} - -func runCommand(cmd *exec.Cmd) error { - var stderr bytes.Buffer - cmd.Stderr = &stderr - err := cmd.Run() - if err != nil { - return fmt.Errorf("command '%s' failed: %v\nStderr: %s", cmd.String(), err, stderr.String()) - } - return nil -} |
