diff options
Diffstat (limited to 'stuff.go')
| -rw-r--r-- | stuff.go | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/stuff.go b/stuff.go new file mode 100644 index 0000000..b1e8283 --- /dev/null +++ b/stuff.go @@ -0,0 +1,226 @@ +package main + +import ( + "bufio" + "bytes" + "compress/gzip" + "crypto/md5" + "crypto/sha1" + "crypto/sha256" + "fmt" + "io" + "log" + "os" + "os/exec" + "path/filepath" + "strings" + "time" +) + +// 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: WIT.COM Debian Sid\n") + fmt.Fprintf(&content, "Label: WIT.COM Debian Sid\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: Tooling for RiscV, Semiconductor Designs & Private Clouds\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 +} |
