Beispiel #1
0
func TestResolverVersion(t *testing.T) {
	arch, err := dependency.ParseArch("amd64")
	isok(t, err)

	candidates, err := resolver.ReadFromBinaryIndex(
		strings.NewReader(testBinaryIndex),
	)
	isok(t, err)
	assert(t, len(*candidates) == 3)

	dep, err := dependency.Parse("android-tools-fsutils (>= 1.0)")
	isok(t, err)
	possi := dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == true)

	dep, err = dependency.Parse("android-tools-fsutils (>= 1:1.0)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == false)

	dep, err = dependency.Parse("android-tools-fsutils (<= 1:1.0)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == true)

	dep, err = dependency.Parse("android-tools-fsutils (<= 0:0)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == false)

	dep, err = dependency.Parse("android-tools-fsutils (= 4.2.2+git20130529-5.1)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == true)

	dep, err = dependency.Parse("android-tools-fsutils (= 2.2.2+git20130529-5.1)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == false)

	dep, err = dependency.Parse("android-tools-fsutils (<< 4.2.2+git20130529-5.1)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == false)

	dep, err = dependency.Parse("android-tools-fsutils (<< 4.2.2+git20130529-6.1)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == true)

	dep, err = dependency.Parse("android-tools-fsutils (>> 4.2.2+git20130529-5.1)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == false)

	dep, err = dependency.Parse("android-tools-fsutils (>> 4.2.2+git20130529-4.1)")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == true)
}
Beispiel #2
0
func TestDoubleInvalidNotArch(t *testing.T) {
	_, err := dependency.Parse("foo [arch !foo]")
	notok(t, err)

	_, err = dependency.Parse("foo [arch!foo]")
	notok(t, err)
}
Beispiel #3
0
func TestMultiarchParse(t *testing.T) {
	dep, err := dependency.Parse("foo:amd64")
	isok(t, err)

	assert(t, dep.Relations[0].Possibilities[0].Name == "foo")
	assert(t, dep.Relations[0].Possibilities[0].Arch.CPU == "amd64")

	dep, err = dependency.Parse("foo:amd64 [amd64 sparc]")
	isok(t, err)

	assert(t, dep.Relations[0].Possibilities[0].Name == "foo")
	assert(t, dep.Relations[0].Possibilities[0].Arch.CPU == "amd64")

	assert(t, dep.Relations[0].Possibilities[0].Architectures.Architectures[0].CPU == "amd64")
	assert(t, dep.Relations[0].Possibilities[0].Architectures.Architectures[1].CPU == "sparc")
}
func TestInsaneRoundTrip(t *testing.T) {
	dep, err := dependency.Parse("foo:armhf <stage1 !cross> [amd64 i386] (>= 1.2:3.4~5.6-7.8~9.0) <!stage1 cross>")
	isok(t, err)

	assert(t, dep.String() == "foo:armhf [amd64 i386] (>= 1.2:3.4~5.6-7.8~9.0) <stage1 !cross> <!stage1 cross>")

	rtDep, err := dependency.Parse(dep.String())
	isok(t, err)
	assert(t, dep.String() == rtDep.String())

	dep.Relations[0].Possibilities[0].Architectures.Not = true
	assert(t, dep.String() == "foo:armhf [!amd64 !i386] (>= 1.2:3.4~5.6-7.8~9.0) <stage1 !cross> <!stage1 cross>")

	rtDep, err = dependency.Parse(dep.String())
	isok(t, err)
	assert(t, dep.String() == rtDep.String())
}
func (para *Paragraph) getOptionalDependencyField(field string) dependency.Dependency {
	val := para.Values[field]
	dep, err := dependency.Parse(val)
	if err != nil {
		return dependency.Dependency{}
	}
	return *dep
}
Beispiel #6
0
func TestSingleParse(t *testing.T) {
	dep, err := dependency.Parse("foo")
	isok(t, err)

	if dep.Relations[0].Possibilities[0].Name != "foo" {
		t.Fail()
	}
}
Beispiel #7
0
func TestResolverDependsVersion(t *testing.T) {
	candidates, err := resolver.ReadFromBinaryIndex(
		strings.NewReader(testBinaryIndex),
	)
	isok(t, err)
	assert(t, len(*candidates) == 3)

	arch, err := dependency.ParseArch("amd64")
	isok(t, err)

	dep, err := dependency.Parse("android-tools-fsutils (>= 1.0)")
	isok(t, err)
	assert(t, candidates.SatisfiesBuildDepends(*arch, *dep) == true)

	dep, err = dependency.Parse("android-tools-fsutils (>= 1.0), quix")
	isok(t, err)
	assert(t, candidates.SatisfiesBuildDepends(*arch, *dep) == false)
}
Beispiel #8
0
func TestVersioning(t *testing.T) {
	dep, err := dependency.Parse("foo (>= 1.0)")
	isok(t, err)
	assert(t, len(dep.Relations) == 1)

	possi := dep.Relations[0].Possibilities[0]
	version := possi.Version

	assert(t, version.Operator == ">=")
	assert(t, version.Number == "1.0")
}
Beispiel #9
0
func TestResolverBasics(t *testing.T) {
	arch, err := dependency.ParseArch("amd64")
	isok(t, err)

	candidates, err := resolver.ReadFromBinaryIndex(
		strings.NewReader(testBinaryIndex),
	)
	isok(t, err)
	assert(t, len(*candidates) == 3)

	dep, err := dependency.Parse("baz")
	isok(t, err)
	possi := dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == false)

	dep, err = dependency.Parse("android-tools-fsutils")
	isok(t, err)
	possi = dep.GetAllPossibilities()[0]
	assert(t, candidates.Satisfies(*arch, possi) == true)
}
Beispiel #10
0
func TestTwoPossibilities(t *testing.T) {
	dep, err := dependency.Parse("foo, bar | baz")
	isok(t, err)
	assert(t, len(dep.Relations) == 2)

	possi := dep.Relations[1].Possibilities
	assert(t, len(possi) == 2)

	assert(t, possi[0].Name == "bar")
	assert(t, possi[1].Name == "baz")
}
Beispiel #11
0
func TestSliceAllParse(t *testing.T) {
	dep, err := dependency.Parse("foo, bar | baz")
	isok(t, err)

	els := dep.GetAllPossibilities()
	assert(t, len(els) == 3)

	assert(t, els[0].Name == "foo")
	assert(t, els[1].Name == "bar")
	assert(t, els[2].Name == "baz")
}
Beispiel #12
0
func TestSingleArch(t *testing.T) {
	dep, err := dependency.Parse("foo [arch]")
	isok(t, err)
	assert(t, len(dep.Relations) == 1)

	possi := dep.Relations[0].Possibilities[0]
	arches := possi.Architectures.Architectures

	assert(t, len(arches) == 1)
	assert(t, arches[0].CPU == "arch")
}
Beispiel #13
0
func TestArchSliceParse(t *testing.T) {
	dep, err := dependency.Parse("foo, bar [sparc] | baz")
	isok(t, err)
	arch, err := dependency.ParseArch("amd64")
	isok(t, err)

	els := dep.GetPossibilities(*arch)
	assert(t, len(els) == 2)

	assert(t, els[0].Name == "foo")
	assert(t, els[1].Name == "baz")
}
Beispiel #14
0
func TestSingleSubstvar(t *testing.T) {
	dep, err := dependency.Parse("${foo:Depends}, bar, baz")
	isok(t, err)
	assert(t, len(dep.Relations) == 3)

	assert(t, dep.Relations[0].Possibilities[0].Name == "foo:Depends")
	assert(t, dep.Relations[1].Possibilities[0].Name == "bar")
	assert(t, dep.Relations[2].Possibilities[0].Name == "baz")

	assert(t, dep.Relations[0].Possibilities[0].Substvar)

	assert(t, !dep.Relations[1].Possibilities[0].Substvar)
	assert(t, !dep.Relations[2].Possibilities[0].Substvar)
}
Beispiel #15
0
func TestBadArch(t *testing.T) {
	vers := []string{
		"foo [amd64",
		"foo [amd6",
		"foo [amd",
		"foo [am",
		"foo [a",
		"foo [",
	}

	for _, ver := range vers {
		_, err := dependency.Parse(ver)
		notok(t, err)
	}
}
Beispiel #16
0
func TestBadVersion(t *testing.T) {
	vers := []string{
		"foo (>= 1.0",
		"foo (>= 1",
		"foo (>= ",
		"foo (>=",
		"foo (>",
		"foo (",
	}

	for _, ver := range vers {
		_, err := dependency.Parse(ver)
		notok(t, err)
	}
}
Beispiel #17
0
func TestSliceSubParse(t *testing.T) {
	dep, err := dependency.Parse("${foo:Depends}, foo, bar | baz, ${bar:Depends}")
	isok(t, err)

	els := dep.GetAllPossibilities()
	assert(t, len(els) == 3)

	assert(t, els[0].Name == "foo")
	assert(t, els[1].Name == "bar")
	assert(t, els[2].Name == "baz")

	els = dep.GetSubstvars()
	assert(t, len(els) == 2)

	assert(t, els[0].Name == "foo:Depends")
	assert(t, els[1].Name == "bar:Depends")
}
Beispiel #18
0
func TestVersioningOperators(t *testing.T) {
	opers := map[string]string{
		">=": "foo (>= 1.0)",
		"<=": "foo (<= 1.0)",
		">>": "foo (>> 1.0)",
		"<<": "foo (<< 1.0)",
		"=":  "foo (= 1.0)",
	}

	for operator, vstring := range opers {
		dep, err := dependency.Parse(vstring)
		isok(t, err)
		assert(t, len(dep.Relations) == 1)
		possi := dep.Relations[0].Possibilities[0]
		version := possi.Version
		assert(t, version.Operator == operator)
		assert(t, version.Number == "1.0")
	}
}
func TestArchSetCompare(t *testing.T) {
	dep, err := dependency.Parse("foo [amd64], bar [!sparc]")
	isok(t, err)

	iAm, err := dependency.ParseArch("amd64")
	isok(t, err)

	fooArch := dep.Relations[0].Possibilities[0].Architectures
	barArch := dep.Relations[1].Possibilities[0].Architectures

	assert(t, fooArch.Matches(iAm))
	assert(t, barArch.Matches(iAm))

	iAmNot, err := dependency.ParseArch("armhf")
	isok(t, err)

	assert(t, !fooArch.Matches(iAmNot))
	assert(t, barArch.Matches(iAmNot))
}
func TestDoubleArch(t *testing.T) {
	for depStr, not := range map[string]bool{
		"foo [arch arch2]":   false,
		"foo [!arch !arch2]": true,
	} {
		dep, err := dependency.Parse(depStr)
		isok(t, err)
		assert(t, len(dep.Relations) == 1)

		possi := dep.Relations[0].Possibilities[0]
		arches := possi.Architectures.Architectures

		assert(t, possi.Architectures.Not == not)

		assert(t, len(arches) == 2)
		assert(t, arches[0].CPU == "arch")
		assert(t, arches[1].CPU == "arch2")
	}
}
func TestTwoStages(t *testing.T) {
	dep, err := dependency.Parse("foo <stage1 !cross> <!stage1 cross>")
	isok(t, err)

	possi := dep.Relations[0].Possibilities[0]

	assert(t, len(possi.StageSets) == 2)

	// <stage1 !cross>
	assert(t, len(possi.StageSets[0].Stages) == 2)
	assert(t, !possi.StageSets[0].Stages[0].Not)
	assert(t, possi.StageSets[0].Stages[0].Name == "stage1")
	assert(t, possi.StageSets[0].Stages[1].Not)
	assert(t, possi.StageSets[0].Stages[1].Name == "cross")

	// <!stage1 cross>
	assert(t, len(possi.StageSets[1].Stages) == 2)
	assert(t, possi.StageSets[1].Stages[0].Not)
	assert(t, possi.StageSets[1].Stages[0].Name == "stage1")
	assert(t, !possi.StageSets[1].Stages[1].Not)
	assert(t, possi.StageSets[1].Stages[1].Name == "cross")
}
func TestBadStages(t *testing.T) {
	vers := []string{
		"foo <stage1> <!cross",
		"foo <stage1> <!cros",
		"foo <stage1> <!cro",
		"foo <stage1> <!cr",
		"foo <stage1> <!c",
		"foo <stage1> <!",
		"foo <stage1> <",
		"foo <stage1",
		"foo <stag",
		"foo <sta",
		"foo <st",
		"foo <s",
		"foo <",
	}

	for _, ver := range vers {
		_, err := dependency.Parse(ver)
		notok(t, err)
	}
}
Beispiel #23
0
func TestTwoArchitectures(t *testing.T) {
	_, err := dependency.Parse("foo [amd64] [sparc]")
	notok(t, err)
}
Beispiel #24
0
func TestTwoVersions(t *testing.T) {
	_, err := dependency.Parse("foo (>= 1.0) (<= 2.0)")
	notok(t, err)
}
Beispiel #25
0
func TestNoComma(t *testing.T) {
	_, err := dependency.Parse("foo bar")
	notok(t, err)
}
Beispiel #26
0
func TestTwoRelations(t *testing.T) {
	dep, err := dependency.Parse("foo, bar")
	isok(t, err)
	assert(t, len(dep.Relations) == 2)
}
func (para *Paragraph) getDependencyField(field string) (*dependency.Dependency, error) {
	if val, ok := para.Values[field]; ok {
		return dependency.Parse(val)
	}
	return nil, fmt.Errorf("Field `%s' Missing", field)
}
Beispiel #28
0
func (s Source) BuildDepends() (*dependency.Dependency, error) {
	return dependency.Parse(s.Paragraph.Values["Build-Depends"])
}
Beispiel #29
0
func buildBin(dscFile string) (control.DSC, string) {
	dscDir := filepath.Dir(dscFile)
	dsc, err := control.ParseDscFile(dscFile)
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}

	if err := dsc.Validate(); err != nil {
		log.Fatalf("error, validation failed: %v\n", err)
	}

	hasArch := false
	hasIndep := false
	for _, arch := range dsc.Architectures {
		if arch.CPU == "all" {
			hasIndep = true
		} else {
			hasArch = true
		}
	}

	img := fmt.Sprintf("gdbuild/bin:%s_%s", dsc.Source, scrubForDockerTag(dsc.Version.String()))

	// TODO parse this information from an image?  optional commandline parameters?
	suite := "unstable"
	sources := aptsources.DebianSources(suite, "main")
	arch := "amd64"

	// prepend incoming so we get the latest and greatest
	sources = sources.Prepend(aptsources.Source{
		Types:      []string{"deb", "deb-src"},
		URIs:       []string{"http://incoming.debian.org/debian-buildd"},
		Suites:     []string{"buildd-" + suite},
		Components: []string{"main"},
	})

	index, err := sources.FetchCandidates(arch)
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}

	depArch, err := dependency.ParseArch(arch)
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}

	buildEssential, err := dependency.Parse("build-essential, dpkg-dev, fakeroot")
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}

	allCan := true
	bins := map[string]control.BinaryIndex{}
	binsSlice := []string{} // ugh Go
RelLoop:
	for _, rel := range append(buildEssential.Relations, dsc.BuildDepends.Relations...) {
		canRel := false
		for _, possi := range rel.Possibilities {
			if possi.Substvar {
				continue
			}
			if bin, ok := bins[possi.Name]; ok && binSatPossi(depArch, bin, possi) {
				continue RelLoop
			}
		}
	PossiLoop:
		for _, possi := range rel.Possibilities {
			if possi.Substvar {
				continue
			}
			entries, ok := map[string][]control.BinaryIndex(*index)[possi.Name]
			if !ok {
				continue
			}
			for _, bin := range entries {
				if binSatPossi(depArch, bin, possi) {
					if existBin, ok := bins[bin.Package]; ok {
						log.Printf("uh oh, already chose %s=%s but want %s=%s for %q\n", existBin.Package, existBin.Version, bin.Package, bin.Version, possi)
						continue PossiLoop
					}
					bins[bin.Package] = bin
					binsSlice = append(binsSlice, bin.Package)
					canRel = true
					break PossiLoop
				}
			}
		}
		if !canRel {
			log.Printf("warning: unable to satisfy %q\n", rel)
			allCan = false
		}
	}
	sort.Strings(binsSlice)

	if !allCan {
		//log.Fatalf("Unsatisfied possi; exiting.\n")
		log.Println()
		log.Println("WARNING: Unsatisfied possi!")
		log.Println()
	}

	dockerfile := fmt.Sprintf("FROM debian:%s\n", suite)
	// TODO allow this to instead be "FROM scratch\nADD some-chroot-tarball.tar.* /\n"

	// see https://sources.debian.net/src/pbuilder/jessie/pbuilder-modules/#L306
	// and https://sources.debian.net/src/pbuilder/jessie/pbuilder-modules/#L408
	dockerfile += `
# setup environment configuration
RUN { echo '#!/bin/sh'; echo 'exit 101'; } > /usr/sbin/policy-rc.d \
	&& chmod +x /usr/sbin/policy-rc.d
RUN echo 'APT::Install-Recommends "false";' > /etc/apt/apt.conf.d/15gdbuild

# put /tmp in a volume so it's always ephemeral (and performant)
VOLUME /tmp
`

	// setup sources.list explicitly -- don't trust the tarball/base image
	dockerfile += fmt.Sprintf(`
# setup sources.list
RUN find /etc/apt/sources.list.d -type f -exec rm -v '{}' + \
	&& echo %q | tee /etc/apt/sources.list >&2
`, sources.ListString())

	eatMyDataPrefix := ""
	if doEatMyData {
		eatMyDataPrefix = "eatmydata "
		dockerfile += `
RUN apt-get update && apt-get install -y \
		eatmydata \
	&& rm -rf /var/lib/apt/lists/*
`
	}

	dockerfile += fmt.Sprintf(`
RUN %sapt-get update && %sapt-get install -y \
`, eatMyDataPrefix, eatMyDataPrefix)
	for _, pkg := range binsSlice {
		bin := bins[pkg]
		dockerfile += fmt.Sprintf("\t\t%s=%s \\\n", bin.Package, bin.Version)
	}
	dockerfile += "\t&& rm -rf /var/lib/apt/lists/*\n"

	files := []string{dsc.Filename}
	for _, f := range dsc.Files {
		files = append(files, filepath.Join(dscDir, f.Filename))
	}

	dockerfile += "COPY"
	for _, f := range files {
		dockerfile += " " + filepath.Base(f)
	}
	dockerfile += " /usr/src/.in/\n"

	if debBuildOptions := os.Getenv("DEB_BUILD_OPTIONS"); debBuildOptions != "" {
		dockerfile += fmt.Sprintf("\nENV DEB_BUILD_OPTIONS %s\n", debBuildOptions)
	}

	buildCommand := fmt.Sprintf("%sdpkg-buildpackage -uc -us -d -sa", eatMyDataPrefix)

	if doSASBS {
		buildCommandParts := []string{}
		if hasIndep {
			buildCommandParts = append(
				buildCommandParts,
				buildCommand+" -S",
				buildCommand+" -A",
			)
		}
		if hasArch {
			buildCommandParts = append(
				buildCommandParts,
				buildCommand+" -S",
				buildCommand+" -B",
			)
		}
		buildCommandParts = append(
			buildCommandParts,
			buildCommand+" -S",
			// end with a full build of "ALL THE THINGS" so we have good, consistent .changes and .dsc
			"rm ../*.changes ../*.dsc ../*.deb",
			buildCommand,
		)
		buildCommand = strings.Join(buildCommandParts, " && ")
	}

	dockerfile += fmt.Sprintf(`
WORKDIR /usr/src
RUN chown -R nobody:nogroup .
USER nobody:nogroup
RUN dpkg-source -x %q pkg

# work around overlayfs bugs (data inconsistency issues; see https://github.com/docker/docker/issues/10180)
VOLUME /usr/src/pkg
# rm: cannot remove 'pkg/.pc/xyz.patch': Directory not empty

RUN (cd pkg && set -x && %s) \
	&& mkdir .out \
	&& { \
		echo *.changes; \
		awk '$1 == "Files:" { files = 1; next } /^ / && files { print $5 } /^[^ ]/ { files = 0 }' *.changes; \
		echo .out/; \
	} | xargs ln -v
`, ".in/"+filepath.Base(dsc.Filename), buildCommand)

	err = dockerBuild(img, dockerfile, files...)
	if err != nil {
		log.Fatalf("error: %v\n", err)
	}

	return *dsc, img
}