func TestDependsUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Depends: foo, bar `))) assert(t, foo.Value == "foo") assert(t, foo.Depends.Relations[0].Possibilities[0].Name == "foo") /* Actually invalid below */ notok(t, control.Unmarshal(&foo, strings.NewReader(`Depends: foo (>= 1.0) (<= 1.0) `))) }
func TestBasicUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Foo-Bar: baz `))) assert(t, foo.Value == "foo") }
// Load a Debian 2.x series .deb control file and write it out to // the deb.Deb.Control member. func loadDeb2Control(archive *Ar, deb *Deb) error { for { member, err := archive.Next() if err == io.EOF { return fmt.Errorf("Missing or out of order .deb member 'control'") } if err != nil { return err } if strings.HasPrefix(member.Name, "control.") { archive, err := member.Tarfile() if err != nil { return err } for { member, err := archive.Next() if err != nil { return err } if path.Clean(member.Name) == "control" { return control.Unmarshal(&deb.Control, archive) } } } } }
func TestNestedUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Fnord-Foo-Bar: Thing `))) assert(t, foo.Value == "foo") assert(t, foo.Fnord.FooBar == "Thing") }
func TestArchUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Arch: amd64 `))) assert(t, foo.Value == "foo") assert(t, foo.Arch.CPU == "amd64") foo = TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Arches: amd64 sparc any `))) assert(t, foo.Value == "foo") assert(t, foo.Arches[0].CPU == "amd64") assert(t, foo.Arches[1].CPU == "sparc") assert(t, foo.Arches[2].CPU == "any") }
func TestVersionUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Version: 1.0-1 `))) assert(t, foo.Value == "foo") assert(t, foo.Version.Revision == "1") }
func TestTagUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Value-Two: baz `))) assert(t, foo.Value == "foo") assert(t, foo.ValueTwo == "baz") }
func TestListUnmarshal(t *testing.T) { foo := TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo ValueThree: foo bar baz `))) assert(t, foo.Value == "foo") assert(t, foo.ValueThree[0] == "foo") }
func TestBasicArrayUnmarshal(t *testing.T) { foo := []TestStruct{} isok(t, control.Unmarshal(&foo, strings.NewReader(`Value: foo Foo-Bar: baz Value: Bar Value: Baz `))) assert(t, len(foo) == 3) assert(t, foo[0].Value == "foo") }
func Load(name string, data interface{}) error { localUser, err := user.Current() if err != nil { return nil } rcPath := path.Join(localUser.HomeDir, fmt.Sprintf(".%src", name)) fd, err := os.Open(rcPath) if err != nil { return nil } defer fd.Close() err = control.Unmarshal(data, fd) return err }
func TestExtraMarshal(t *testing.T) { el := TestParaMarshalStruct{} isok(t, control.Unmarshal(&el, strings.NewReader(`Foo: test X-A-Test: Foo `))) assert(t, el.Foo == "test") writer := bytes.Buffer{} isok(t, control.Marshal(&writer, el)) assert(t, writer.String() == `Foo: test X-A-Test: Foo `) }
func TestExternalMarshal(t *testing.T) { testStruct := SomeComplexStruct{} isok(t, control.Unmarshal(&testStruct, strings.NewReader(`Version: 1.0-1 Dependency: foo, bar X-Foo: bar `))) writer := bytes.Buffer{} err := control.Marshal(&writer, testStruct) isok(t, err) assert(t, testStruct.Dependency.Relations[0].Possibilities[0].Name == "foo") assert(t, writer.String() == `Version: 1.0-1 Dependency: foo, bar X-Foo: bar `) }
func ParseNew(reader *bufio.Reader) ([]NewEntry, error) { ret := []NewEntry{} err := control.Unmarshal(&ret, reader) return ret, err }
func TestRequiredUnmarshal(t *testing.T) { foo := TestStruct{} notok(t, control.Unmarshal(&foo, strings.NewReader(`Foo-Bar: baz `))) }
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() var inRelease struct { Suite string } if err := control.Unmarshal(&inRelease, bufio.NewReader(r)); err != nil { log.Fatal(err) } if inRelease.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 { var doseCeves []struct { Package string Version version.Version } r := bufio.NewReader(strings.NewReader(string(out))) if err := control.Unmarshal(&doseCeves, r); err != nil { log.Fatal(err) } for _, doseCeve := range doseCeves { rebuild[doseCeve.Package] = append(rebuild[doseCeve.Package], doseCeve.Version) } } 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)) } }