summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Carr <[email protected]>2025-10-05 06:27:50 -0500
committerJeff Carr <[email protected]>2025-10-05 06:27:50 -0500
commitb65fe9b53c549ba63ec390b2fb2950345ed1fdb9 (patch)
tree8c4cb87671f766d0e860ae42988b244b3fe9acfe
day1v0.0.1
-rw-r--r--Makefile41
-rwxr-xr-xbuild4
-rw-r--r--control12
-rw-r--r--main.go115
-rw-r--r--stuff.go226
-rw-r--r--wit-sid.asc41
-rw-r--r--wit.list4
7 files changed, 443 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0e253ca
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,41 @@
+.PHONY: build
+
+VERSION = $(shell git describe --tags)
+GUIVERSION = $(shell git describe --tags)
+# BUILDTIME = $(shell date +%Y.%m.%d)
+BUILDTIME = $(shell date +%s)
+
+all: install
+
+go-build: goimports
+ GO111MODULE=off go build \
+ -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
+
+verbose:
+ GO111MODULE=off go build -v -x \
+ -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
+
+install: goimports
+ GO111MODULE=off go install \
+ -ldflags "-X main.VERSION=${VERSION} -X main.BUILDTIME=${BUILDTIME} -X gui.GUIVERSION=${VERSION}"
+
+vet:
+ GO111MODULE=off go vet
+# this is how the mirrors.wit.com debian package is created
+
+go-deb:
+ go-deb --repo .
+
+goimports:
+ goimports -w *.go
+ # // to globally reset paths:
+ # // gofmt -w -r '"go.wit.com/gui/gadgets" -> "go.wit.com/lib/gadgets"' *.go
+
+clean:
+ rm -f go.*
+
+gpl:
+ wit-test --witcom
+
+check-git-clean:
+ @git diff-index --quiet HEAD -- || (echo "Git repository is dirty, please commit your changes first"; exit 1)
diff --git a/build b/build
new file mode 100755
index 0000000..eba7c70
--- /dev/null
+++ b/build
@@ -0,0 +1,4 @@
+#!/bin/bash -x
+
+mkdir -p files/usr/share/bash-completion/completions/
+mirrors --bash > files/usr/share/bash-completion/completions/mirrors
diff --git a/control b/control
new file mode 100644
index 0000000..9974c56
--- /dev/null
+++ b/control
@@ -0,0 +1,12 @@
+Source:
+Package: mirrors.wit.com
+Build-Depends:
+Maintainer: Jeff Carr <[email protected]>
+Packager: Jeff Carr <[email protected]>
+Architecture: all
+Depends:
+URL: https://mirrors.wit.com/
+Recommends:
+Version: 0.0.7
+Description: apt keys and source file
+ This was packaged with go-deb from go.wit.com
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..5c6846b
--- /dev/null
+++ b/main.go
@@ -0,0 +1,115 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+// --- Configuration ---
+// !!! IMPORTANT: Set your GPG Key ID here!
+// Find it with: gpg --list-secret-keys --keyid-format=long
+const gpgKeyID = "5D7C9BE47836D2FA48F83C2B4A854AEAF7E0E16D"
+
+const dist = "sid"
+const component = "main"
+const poolDir = "pool"
+const distsDir = "dists"
+
+var architectures = []string{"amd64", "riscv64", "arm64", "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 main() {
+ 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! ---")
+}
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
+}
diff --git a/wit-sid.asc b/wit-sid.asc
new file mode 100644
index 0000000..8648d6c
--- /dev/null
+++ b/wit-sid.asc
@@ -0,0 +1,41 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+yGA=
+=tw/F
+-----END PGP PUBLIC KEY BLOCK-----
diff --git a/wit.list b/wit.list
new file mode 100644
index 0000000..f1b6db6
--- /dev/null
+++ b/wit.list
@@ -0,0 +1,4 @@
+deb http://mirrors.wit.com/wit/ sid main
+# deb-src http://mirrors.wit.com/wit/ sid main
+
+# cp apt-wit.list /etc/apt/sources.list.d/