func TestChangesParse(t *testing.T) { // Test Paragraph {{{ reader := bufio.NewReader(strings.NewReader(`Format: 1.8 Date: Wed, 29 Apr 2015 21:29:13 -0400 Source: dput-ng Binary: dput-ng python-dput dput-ng-doc Architecture: source Version: 1.9 Distribution: unstable Urgency: medium Maintainer: dput-ng Maintainers <*****@*****.**> Changed-By: Paul Tagliamonte <*****@*****.**> Description: dput-ng - next generation Debian package upload tool dput-ng-doc - next generation Debian package upload tool (documentation) python-dput - next generation Debian package upload tool (Python library) Closes: 783746 Changes: dput-ng (1.9) unstable; urgency=medium . * The "< jessfraz> ya!!!! jessie FTW" release . [ Sebastian Ramacher ] * Remove obsolete conffile /etc/dput.d/profiles/backports.json. Thanks to Jakub Wilk for spotting the obsolete conffile. . [ Luca Falavigna ] * Add support for Deb-o-Matic binnmu command. . [ Tristan Seligmann ] * Add jessie-backports to list of Debian codenames (closes: #783746). Checksums-Sha1: cb136f28a8c971d4299cc68e8fdad93a8ca7daf3 1131 dput-ng_1.9.dsc 77e97879793f57ee93cb3d59d8c5d16361f75b37 82504 dput-ng_1.9.tar.xz Checksums-Sha256: 2489ed1a2e052ccc4c321719a2394ac4b6958209f05b1531305d2a52173aa5c1 1131 dput-ng_1.9.dsc 5ef401d9b67b009443f249aa79b952839c69a2b5437fbe957832599b655e1df0 82504 dput-ng_1.9.tar.xz Files: a74c9e3e9fe05d480d24cd43b225ee0c 1131 devel extra dput-ng_1.9.dsc 67e67e85a267c0c8110001b1a6cfc293 82504 devel extra dput-ng_1.9.tar.xz `)) // }}} changes, err := control.ParseChanges(reader, "") isok(t, err) assert(t, changes.Format == "1.8") assert(t, changes.ChangedBy == "Paul Tagliamonte <*****@*****.**>") assert(t, len(changes.Binaries) == 3) assert(t, changes.Binaries[2] == "dput-ng-doc") assert(t, len(changes.Closes) == 1) assert(t, changes.Closes[0] == "783746") }
func main() { flag.Parse() if flag.NArg() != 1 { log.Fatalf("Usage: %s [options] <path-to-changes-file>\n", os.Args[0]) } changesPath := flag.Arg(0) log.Printf("Loading changes file %q\n", changesPath) c, err := os.Open(changesPath) if err != nil { log.Fatal(err) } defer c.Close() changes, err := control.ParseChanges(bufio.NewReader(c), changesPath) if err != nil && err != io.EOF { log.Fatal(err) } binaries := make(map[string]bool) var debs []string for _, file := range changes.Files { if filepath.Ext(file.Filename) == ".deb" { debs = append(debs, file.Filename) } } for _, binary := range changes.Binaries { binaries[binary] = true } log.Printf(" - %d binary packages: %s\n", len(changes.Binaries), strings.Join(changes.Binaries, " ")) log.Printf(" - corresponding .debs (will be injected when building):\n") for _, deb := range debs { log.Printf(" %s\n", deb) } var sourcesPaths []string var packagesPaths []string indexTargets := exec.Command("apt-get", "indextargets", "--format", "$(FILENAME)", "Codename: sid", "ShortDesc: Sources") if lines, err := indexTargets.Output(); err == nil { for _, line := range strings.Split(string(lines), "\n") { trimmed := strings.TrimSpace(line) if trimmed != "" { sourcesPaths = append(sourcesPaths, line) } } binaryIndexTargets := exec.Command( "apt-get", "indextargets", "--format", "$(FILENAME)", "Codename: sid", "ShortDesc: Packages") lines, err = binaryIndexTargets.Output() if err != nil { log.Fatal("Could not get packages files using %+v: %v", binaryIndexTargets.Args, err) } for _, line := range strings.Split(string(lines), "\n") { trimmed := strings.TrimSpace(line) if trimmed != "" { packagesPaths = append(packagesPaths, line) } } } else { // Fallback for older versions of apt-get. See // https://bugs.debian.org/801594 for context. releaseMatches, err := filepath.Glob("/var/lib/apt/lists/*_InRelease") if err != nil { log.Fatal(err) } for _, releasepath := range releaseMatches { r, err := os.Open(releasepath) if err != nil { log.Fatal(err) } defer r.Close() release, err := control.ParseParagraph(bufio.NewReader(r)) if err != nil && err != io.EOF { log.Fatal(err) } if release.Values["Suite"] != "unstable" { continue } listsPrefix := listsPrefixRe.FindStringSubmatch(releasepath) if len(listsPrefix) != 2 { log.Fatalf("release file path %q does not match regexp %q\n", releasepath, listsPrefixRe) } sourceMatches, err := filepath.Glob(fmt.Sprintf("/var/lib/apt/lists/%s_*_Sources", listsPrefix[1])) if err != nil { log.Fatal(err) } sourcesPaths = append(sourcesPaths, sourceMatches...) packagesMatches, err := filepath.Glob(fmt.Sprintf("/var/lib/apt/lists/%s_*_Packages", listsPrefix[1])) if err != nil { log.Fatal(err) } packagesPaths = append(packagesPaths, packagesMatches...) } } if len(sourcesPaths) == 0 { log.Fatal("Could not find InRelease file for unstable. Are you missing unstable in your /etc/apt/sources.list?") } rebuild := make(map[string][]version.Version) archCmd := exec.Command( "dpkg-architecture", "--query=DEB_BUILD_ARCH") archOut, err := archCmd.Output() if err != nil { log.Fatal(err) } arch := strings.TrimSpace(string(archOut)) // TODO: Cache this output based on the .changes file. dose-ceve takes quite a while. ceve := exec.Command( "dose-ceve", "--deb-native-arch="+arch, "-T", "debsrc", "-r", strings.Join(changes.Binaries, ","), "-G", "pkg") for _, packagesPath := range packagesPaths { ceve.Args = append(ceve.Args, "deb://"+packagesPath) } for _, sourcesPath := range sourcesPaths { ceve.Args = append(ceve.Args, "debsrc://"+sourcesPath) } log.Printf("Figuring out reverse build dependencies using dose-ceve(1). This might take a while\n") if out, err := ceve.Output(); err == nil { r := bufio.NewReader(strings.NewReader(string(out))) for { paragraph, err := control.ParseParagraph(r) if paragraph == nil || err == io.EOF { break } pkg := paragraph.Values["Package"] ver, err := version.Parse(paragraph.Values["Version"]) if err != nil { log.Fatalf("Cannot parse version number %q in dose-ceve(1) output: %v", paragraph.Values["Version"], err) } rebuild[pkg] = append(rebuild[pkg], ver) } } else { log.Printf("dose-ceve(1) failed (%v), falling back to interpreting Sources directly\n", err) for _, sourcesPath := range sourcesPaths { if err := addReverseBuildDeps(sourcesPath, binaries, rebuild); err != nil { log.Fatal(err) } } } // TODO: add -recursive flag to also cover dependencies which are not DIRECT dependencies. use http://godoc.org/pault.ag/go/debian/control#OrderDSCForBuild (topsort) to build dependencies in the right order (saving CPU time). // TODO: what’s a good integration method for doing this in more setups, e.g. on a cloud provider or something? mapreri from #debian-qa says jenkins.debian.net is suitable. if strings.TrimSpace(*sbuildDist) == "" { *sbuildDist = changes.Distribution log.Printf("Setting -sbuild_dist=%s (from .changes file)\n", *sbuildDist) } buildresults := make(map[string]bool) for src, versions := range rebuild { sort.Sort(sort.Reverse(version.Slice(versions))) newest := versions[0] target := fmt.Sprintf("%s_%s", src, newest) // TODO: discard resulting package immediately? args := []string{ "--arch-all", "--dist=" + *sbuildDist, "--nolog", target, } for _, filename := range debs { args = append(args, fmt.Sprintf("--extra-package=%s", filename)) } cmd := exec.Command("sbuild", args...) if err := os.MkdirAll(*logDir, 0755); err != nil { log.Fatal(err) } log.Printf("Building %s (commandline: %v)\n", target, cmd.Args) if *dryRun { continue } buildlog, err := os.Create(filepath.Join(*logDir, target)) if err != nil { log.Fatal(err) } defer buildlog.Close() cmd.Stdout = buildlog cmd.Stderr = buildlog if err := cmd.Run(); err != nil { log.Printf("building %s failed: %v\n", target, err) buildresults[target] = false } else { buildresults[target] = true } } log.Printf("Build results:\n") // Print all successful builds first (not as interesting), then failed ones. for target, result := range buildresults { if !result { continue } log.Printf("PASSED: %s\n", target) } for target, result := range buildresults { if result { continue } log.Printf("FAILED: %s (see %s)\n", target, filepath.Join(*logDir, target)) } }
func main() { flag.Parse() if flag.NArg() != 1 { log.Fatalf("Usage: %s [options] <path-to-changes-file>\n", os.Args[0]) } changesPath := flag.Arg(0) log.Printf("Loading changes file %q\n", changesPath) c, err := os.Open(changesPath) if err != nil { log.Fatal(err) } defer c.Close() changes, err := control.ParseChanges(bufio.NewReader(c), changesPath) if err != nil { log.Fatal(err) } binaries := make(map[string]bool) var debs []string for _, file := range changes.Files { if filepath.Ext(file.Filename) == ".deb" { debs = append(debs, file.Filename) } } for _, binary := range changes.Binaries { binaries[binary] = true } log.Printf(" - %d binary packages: %s\n", len(changes.Binaries), strings.Join(changes.Binaries, " ")) log.Printf(" - corresponding .debs (will be injected when building):\n") for _, deb := range debs { log.Printf(" %s\n", deb) } var sourcesPaths []string releaseMatches, err := filepath.Glob("/var/lib/apt/lists/*_InRelease") if err != nil { log.Fatal(err) } for _, releasepath := range releaseMatches { r, err := os.Open(releasepath) if err != nil { log.Fatal(err) } defer r.Close() release, err := control.ParseParagraph(bufio.NewReader(r)) if err != nil { log.Fatal(err) } if release.Values["Suite"] != "unstable" { continue } listsPrefix := listsPrefixRe.FindStringSubmatch(releasepath) if len(listsPrefix) != 2 { log.Fatalf("release file path %q does not match regexp %q\n", releasepath, listsPrefixRe) } sourceMatches, err := filepath.Glob(fmt.Sprintf("/var/lib/apt/lists/%s_*_Sources", listsPrefix[1])) if err != nil { log.Fatal(err) } sourcesPaths = append(sourcesPaths, sourceMatches...) } if len(sourcesPaths) == 0 { log.Fatal("Could not find InRelease file for unstable. Are you missing unstable in your /etc/apt/sources.list?") } rebuild := make(map[string][]version.Version) for _, sourcesPath := range sourcesPaths { if err := addReverseBuildDeps(sourcesPath, binaries, rebuild); err != nil { log.Fatal(err) } } // TODO: add -recursive flag to also cover dependencies which are not DIRECT dependencies. use http://godoc.org/pault.ag/go/debian/control#OrderDSCForBuild (topsort) to build dependencies in the right order (saving CPU time). // TODO: what’s a good integration method for doing this in more setups, e.g. on a cloud provider or something? mapreri from #debian-qa says jenkins.debian.net is suitable. buildresults := make(map[string]bool) for src, versions := range rebuild { sort.Sort(sort.Reverse(version.Slice(versions))) newest := versions[0] target := fmt.Sprintf("%s_%s", src, newest) // TODO: discard resulting package immediately? args := []string{ "--arch-all", "--dist=sid", "--nolog", target, } for _, filename := range debs { args = append(args, fmt.Sprintf("--extra-package=%s", filename)) } cmd := exec.Command("sbuild", args...) if err := os.MkdirAll(*logDir, 0755); err != nil { log.Fatal(err) } log.Printf("Building %s (commandline: %v)\n", target, cmd.Args) if *dryRun { continue } buildlog, err := os.Create(filepath.Join(*logDir, target)) if err != nil { log.Fatal(err) } defer buildlog.Close() cmd.Stdout = buildlog cmd.Stderr = buildlog if err := cmd.Run(); err != nil { log.Printf("building %s failed: %v\n", target, err) buildresults[target] = false } else { buildresults[target] = true } } log.Printf("Build results:\n") // Print all successful builds first (not as interesting), then failed ones. for target, result := range buildresults { if !result { continue } log.Printf("PASSED: %s\n", target) } for target, result := range buildresults { if result { continue } log.Printf("FAILED: %s (see %s)\n", target, filepath.Join(*logDir, target)) } }