Beispiel #1
0
// DependencyGraph builds a dependency graph for the collection
func (c Collection) DependencyGraph() (*graph.Graph, error) {
	g := graph.New()

	// A map containing the resource ids and their nodes in the graph
	nodes := make(map[string]*graph.Node)
	for id := range c {
		node := graph.NewNode(id)
		nodes[id] = node
		g.AddNode(node)
	}

	// Connect the nodes in the graph
	for id, r := range c {
		before := r.GetBefore()
		after := r.GetAfter()

		// Connect current resource with the ones that happen after it
		for _, dep := range after {
			if _, ok := c[dep]; !ok {
				return g, fmt.Errorf("%s wants %s, which does not exist", id, dep)
			}
			g.AddEdge(nodes[id], nodes[dep])
		}

		// Connect current resource with the ones that happen before it
		for _, dep := range before {
			if _, ok := c[dep]; !ok {
				return g, fmt.Errorf("%s wants %s, which does not exist", id, dep)
			}
			g.AddEdge(nodes[dep], nodes[id])
		}
	}

	return g, nil
}
Beispiel #2
0
// DependencyGraph builds a dependency graph for the collection
func (c Collection) DependencyGraph() (*graph.Graph, error) {
	g := graph.New()

	// A map containing the resource ids and their nodes in the graph
	nodes := make(map[string]*graph.Node)
	for id := range c {
		node := graph.NewNode(id)
		nodes[id] = node
		g.AddNode(node)
	}

	// Connect the nodes in the graph
	for id, r := range c {
		// Create edges between the nodes and the ones
		// required by it
		for _, dep := range r.Dependencies() {
			if _, ok := c[dep]; !ok {
				return g, fmt.Errorf("%s wants %s, which does not exist", id, dep)
			}
			g.AddEdge(nodes[id], nodes[dep])
		}

		// Create edges between the nodes and the resources for
		// which we subscribe for changes to
		for dep := range r.SubscribedTo() {
			if _, ok := c[dep]; !ok {
				return g, fmt.Errorf("%s subscribes to %s, which does not exist", id, dep)
			}
			g.AddEdge(nodes[id], nodes[dep])
		}
	}

	return g, nil
}
Beispiel #3
0
// New creates a new empty catalog with the provided configuration
func New(config *Config) *Catalog {
	c := &Catalog{
		config:     config,
		collection: make(resource.Collection),
		sorted:     make([]*graph.Node, 0),
		reversed:   graph.New(),
		status: &Status{
			Items: make(map[string]*StatusItem),
		},
		Unsorted: make([]resource.Resource, 0),
	}

	// Inject the configuration for resources
	resource.DefaultConfig = &resource.Config{
		Logger:   config.Logger,
		SiteRepo: config.SiteRepo,
	}

	// Register the catalog type in Lua and also register
	// metamethods for the catalog, so that we can use
	// the catalog in a more Lua-friendly way
	mt := luar.MT(config.L, c)
	mt.RawSetString("__len", luar.New(config.L, (*Catalog).luaLen))
	config.L.SetGlobal("catalog", luar.New(config.L, c))

	return c
}
Beispiel #4
0
// Executes the "graph" command
func execGraphCommand(c *cli.Context) error {
	if len(c.Args()) < 1 {
		return cli.NewExitError(errNoModuleName.Error(), 64)
	}

	L := lua.NewState()
	defer L.Close()

	module := c.Args()[0]
	config := &catalog.Config{
		Module:   module,
		DryRun:   true,
		Logger:   log.New(os.Stdout, "", log.LstdFlags),
		SiteRepo: c.String("siterepo"),
		L:        L,
	}

	katalog := catalog.New(config)
	resource.LuaRegisterBuiltin(L)
	if err := L.DoFile(module); err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	collection, err := resource.CreateCollection(katalog.Unsorted)
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	g, err := collection.DependencyGraph()
	if err != nil {
		return cli.NewExitError(err.Error(), 1)
	}

	g.AsDot("resources", os.Stdout)
	g.Reversed().AsDot("reversed", os.Stdout)

	sorted, err := g.Sort()
	if err == graph.ErrCircularDependency {
		circular := graph.New()
		circular.AddNode(sorted...)
		circular.AsDot("circular", os.Stdout)
		return cli.NewExitError(graph.ErrCircularDependency.Error(), 1)
	}

	return nil
}