Ejemplo n.º 1
0
func TestTopsortLongCycle(t *testing.T) {
	network := topsort.NewNetwork()

	network.AddNode("A", nil)
	network.AddNode("B", nil)
	network.AddNode("C", nil)
	network.AddNode("D", nil)
	network.AddNode("E", nil)
	network.AddNode("F", nil)
	network.AddNode("G", nil)
	network.AddNode("H", nil)
	network.AddNode("I", nil)

	network.AddEdge("A", "B")
	network.AddEdge("B", "C")
	network.AddEdge("C", "D")
	network.AddEdge("D", "E")
	network.AddEdge("E", "F")
	network.AddEdge("F", "G")
	network.AddEdge("G", "H")
	network.AddEdge("H", "I")
	network.AddEdge("I", "A")

	_, err := network.Sort()
	notok(t, err)
}
Ejemplo n.º 2
0
func TestTopsortLong(t *testing.T) {
	/*
		A --> B -> C -> D -> E
		 \    ^
		  \-> F
	*/
	network := topsort.NewNetwork()

	network.AddNode("A", nil)
	network.AddNode("B", nil)
	network.AddNode("C", nil)
	network.AddNode("D", nil)
	network.AddNode("E", nil)
	network.AddNode("F", nil)

	network.AddEdge("A", "B")
	network.AddEdge("A", "F")
	network.AddEdge("F", "B")
	network.AddEdge("B", "C")
	network.AddEdge("C", "D")
	network.AddEdge("D", "E")

	series, err := network.Sort()
	isok(t, err)
	assert(t, len(series) == 6)

	assert(t, series[0].Name == "A")
	assert(t, series[1].Name == "F")
	assert(t, series[2].Name == "B")
	assert(t, series[3].Name == "C")
}
Ejemplo n.º 3
0
func TestTopsortCycle(t *testing.T) {
	network := topsort.NewNetwork()
	network.AddNode("foo", nil)
	network.AddNode("bar", nil)
	network.AddEdge("foo", "bar")
	network.AddEdge("bar", "foo")
	_, err := network.Sort()
	notok(t, err)
}
Ejemplo n.º 4
0
func TestTopsortEasy(t *testing.T) {
	network := topsort.NewNetwork()
	network.AddNode("foo", nil)
	network.AddNode("bar", nil)
	network.AddEdge("foo", "bar")
	series, err := network.Sort()
	isok(t, err)
	assert(t, len(series) == 2)
}
Ejemplo n.º 5
0
func newAlphaNetwork(start, end rune) *topsort.Network {
	network := topsort.NewNetwork()

	for c := start; c <= end; c++ {
		network.AddNode(string(c), nil)
	}

	return network
}
Ejemplo n.º 6
0
func sortRepos(repos []string) ([]string, error) {
	if noSortFlag || len(repos) <= 1 {
		return repos, nil
	}

	network := topsort.NewNetwork()

	rs := []*Repo{}
	for _, repo := range repos {
		r, err := fetch(repo)
		if err != nil {
			return nil, err
		}
		rs = append(rs, r)
		network.AddNode(r.Identifier(), repo)
		network.AddNode(r.RepoName, repo)
	}

	for _, r := range rs {
		for _, entry := range r.Entries() {
			from, err := r.DockerFrom(&entry)
			if err != nil {
				return nil, err
			}
			if i := strings.IndexRune(from, ':'); i >= 0 {
				// we want "repo -> repo" relations, no tags
				from = from[:i]
			}
			if from == r.RepoName {
				// "a:a -> a:b" is OK (ignore that here -- see Repo.SortedEntries for that)
				continue
			}
			// TODO somehow reconcile/avoid "a:a -> b:b, b:b -> a:c" (which will exhibit here as cyclic)
			network.AddEdgeIfExists(from, r.Identifier())
			network.AddEdgeIfExists(from, r.RepoName)
		}
	}

	nodes, err := network.Sort()
	if err != nil {
		return nil, err
	}

	ret := []string{}
	seen := map[string]bool{}
	for _, node := range nodes {
		repo := node.Value.(string)
		if seen[repo] {
			continue
		}
		seen[repo] = true
		ret = append(ret, repo)
	}

	return ret, nil
}
Ejemplo n.º 7
0
func (r Repo) SortedEntries() ([]manifest.Manifest2822Entry, error) {
	entries := r.Entries()

	if noSortFlag || len(entries) <= 1 {
		return entries, nil
	}

	network := topsort.NewNetwork()

	for i, entry := range entries {
		for _, tag := range r.Tags("", false, entry) {
			network.AddNode(tag, &entries[i])
		}
	}

	for _, entry := range entries {
		from, err := r.DockerFrom(&entry)
		if err != nil {
			return nil, err
		}
		for _, tag := range r.Tags("", false, entry) {
			network.AddEdgeIfExists(from, tag)
		}
	}

	nodes, err := network.Sort()
	if err != nil {
		return nil, err
	}

	seen := map[*manifest.Manifest2822Entry]bool{}
	ret := []manifest.Manifest2822Entry{}
	for _, node := range nodes {
		entry := node.Value.(*manifest.Manifest2822Entry)
		if seen[entry] {
			// TODO somehow reconcile "a:a -> b:b, b:b -> a:c"
			continue
		}
		ret = append(ret, *entry)
		seen[entry] = true
	}

	return ret, nil
}
Ejemplo n.º 8
0
// Given a bunch of DSC objects, sort the packages topologically by
// build order by looking at the relationship between the Build-Depends
// field.
func OrderDSCForBuild(dscs []DSC, arch dependency.Arch) ([]DSC, error) {
	sourceMapping := map[string]string{}
	network := topsort.NewNetwork()
	ret := []DSC{}

	/*
	 * - Create binary -> source mapping.
	 * - Error if two sources provide the same binary
	 * - Create a node for each source
	 * - Create an edge from the source -> source
	 * - return sorted list of dsc files
	 */

	for _, dsc := range dscs {
		for _, binary := range dsc.Binaries {
			sourceMapping[binary] = dsc.Source
		}
		network.AddNode(dsc.Source, dsc)
	}

	for _, dsc := range dscs {
		concreteBuildDepends := dsc.BuildDepends.GetPossibilities(arch)
		for _, relation := range concreteBuildDepends {
			if val, ok := sourceMapping[relation.Name]; ok {
				err := network.AddEdge(val, dsc.Source)
				if err != nil {
					return nil, err
				}
			}
		}
	}

	nodes, err := network.Sort()
	if err != nil {
		return nil, err
	}

	for _, node := range nodes {
		ret = append(ret, node.Value.(DSC))
	}

	return ret, nil
}
Ejemplo n.º 9
0
func sortRepoObjects(rs []*Repo) ([]*Repo, error) {
	// short circuit if we don't have to go further
	if noSortFlag || len(rs) <= 1 {
		return rs, nil
	}

	network := topsort.NewNetwork()

	// a map of alternate tag names to the canonical "node name" for topsort purposes
	canonicalNodes := map[string]string{}
	canonicalRepos := map[string]*Repo{}

	for _, r := range rs {
		node := r.Identifier()
		for _, entry := range r.Entries() {
			for _, tag := range r.Tags("", false, entry) {
				if canonicalRepo, ok := canonicalRepos[tag]; ok && canonicalRepo.TagName != "" {
					// if we run into a duplicate, we want to prefer a specific tag over a full repo
					continue
				}

				canonicalNodes[tag] = node
				canonicalRepos[tag] = r
			}
		}
		network.AddNode(node, r)
	}

	for _, r := range rs {
		for _, entry := range r.Entries() {
			from, err := r.DockerFrom(&entry)
			if err != nil {
				return nil, err
			}
			from = latestizeRepoTag(from)

			fromNode, ok := canonicalNodes[from]
			if !ok {
				// if our FROM isn't in the list of things we're sorting, it isn't relevant in this context
				continue
			}

			// TODO somehow reconcile/avoid "a:a -> b:b, b:b -> a:c" (which will exhibit here as cyclic)
			for _, tag := range r.Tags("", false, entry) {
				if tagNode, ok := canonicalNodes[tag]; ok {
					if tagNode == fromNode {
						// don't be cyclic
						continue
					}
					if err := network.AddEdge(fromNode, tagNode); err != nil {
						return nil, err
					}
				}
			}
		}
	}

	nodes, err := network.Sort()
	if err != nil {
		return nil, err
	}

	ret := []*Repo{}
	for _, node := range nodes {
		ret = append(ret, node.Value.(*Repo))
	}

	return ret, nil
}
Ejemplo n.º 10
0
func cmdFamily(parents bool, c *cli.Context) error {
	depsRepos, err := repos(c.Bool("all"), c.Args()...)
	if err != nil {
		return cli.NewMultiError(fmt.Errorf(`failed gathering repo list`), err)
	}

	uniq := c.Bool("uniq")
	applyConstraints := c.Bool("apply-constraints")

	allRepos, err := repos(true)
	if err != nil {
		return cli.NewMultiError(fmt.Errorf(`failed gathering ALL repos list`), err)
	}

	// create network (all repos)
	network := topsort.NewNetwork()

	// add nodes
	for _, repo := range allRepos {
		r, err := fetch(repo)
		if err != nil {
			return cli.NewMultiError(fmt.Errorf(`failed fetching repo %q`, repo), err)
		}

		for _, entry := range r.Entries() {
			if applyConstraints && r.SkipConstraints(entry) {
				continue
			}

			for _, tag := range r.Tags("", false, entry) {
				network.AddNode(tag, entry)
			}
		}
	}

	// add edges
	for _, repo := range allRepos {
		r, err := fetch(repo)
		if err != nil {
			return cli.NewMultiError(fmt.Errorf(`failed fetching repo %q`, repo), err)
		}
		for _, entry := range r.Entries() {
			if applyConstraints && r.SkipConstraints(entry) {
				continue
			}

			from, err := r.DockerFrom(&entry)
			if err != nil {
				return cli.NewMultiError(fmt.Errorf(`failed fetching/scraping FROM for %q (tags %q)`, r.RepoName, entry.TagsString()), err)
			}
			for _, tag := range r.Tags("", false, entry) {
				network.AddEdge(from, tag)
			}
		}
	}

	// now the real work
	seen := map[*topsort.Node]bool{}
	for _, repo := range depsRepos {
		r, err := fetch(repo)
		if err != nil {
			return cli.NewMultiError(fmt.Errorf(`failed fetching repo %q`, repo), err)
		}

		for _, entry := range r.Entries() {
			if applyConstraints && r.SkipConstraints(entry) {
				continue
			}

			for _, tag := range r.Tags("", uniq, entry) {
				nodes := []*topsort.Node{}
				if parents {
					nodes = append(nodes, network.Get(tag).InboundEdges...)
				} else {
					nodes = append(nodes, network.Get(tag).OutboundEdges...)
				}
				for len(nodes) > 0 {
					node := nodes[0]
					nodes = nodes[1:]
					if seen[node] {
						continue
					}
					seen[node] = true
					fmt.Printf("%s\n", node.Name)
					if parents {
						nodes = append(nodes, node.InboundEdges...)
					} else {
						nodes = append(nodes, node.OutboundEdges...)
					}
				}
			}
		}
	}

	return nil
}