本文整理匯總了Golang中github.com/hashicorp/terraform/dag.AcyclicGraph類的典型用法代碼示例。如果您正苦於以下問題:Golang AcyclicGraph類的具體用法?Golang AcyclicGraph怎麽用?Golang AcyclicGraph使用的例子?那麽, 這裏精選的類代碼示例或許可以為您提供幫助。
在下文中一共展示了AcyclicGraph類的6個代碼示例,這些例子默認根據受歡迎程度排序。您可以為喜歡或者感覺有用的代碼點讚,您的評價將有助於係統推薦出更棒的Golang代碼示例。
示例1: buildProviderAliasGraph
func (t *Tree) buildProviderAliasGraph(g *dag.AcyclicGraph, parent dag.Vertex) {
// Add all our defined aliases
defined := make(map[string]struct{})
for _, p := range t.config.ProviderConfigs {
defined[p.FullName()] = struct{}{}
}
// Add all our used aliases
used := make(map[string]struct{})
for _, r := range t.config.Resources {
if r.Provider != "" {
used[r.Provider] = struct{}{}
}
}
// Add it to the graph
vertex := &providerAliasVertex{
Path: t.Path(),
Defined: defined,
Used: used,
}
g.Add(vertex)
// Connect to our parent if we have one
if parent != nil {
g.Connect(dag.BasicEdge(vertex, parent))
}
// Build all our children
for _, c := range t.Children() {
c.buildProviderAliasGraph(g, vertex)
}
}
示例2: graph
func (l *Layered) graph(db *bolt.DB) (*dag.AcyclicGraph, error) {
graph := new(dag.AcyclicGraph)
graph.Add("root")
// First, add all the layers
layers := make(map[string]*layerVertex)
err := db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(boltLayersBucket)
return bucket.ForEach(func(k, data []byte) error {
var v layerVertex
if err := l.structRead(&v, data); err != nil {
return err
}
// Add this layer to the graph
graph.Add(&v)
// Store the mapping for later
layers[v.Layer.ID] = &v
return nil
})
})
if err != nil {
return nil, err
}
// Next, connect the layers
err = db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(boltEdgesBucket)
return bucket.ForEach(func(k, data []byte) error {
from := layers[string(k)]
to := layers[string(data)]
if from != nil && to != nil {
graph.Connect(dag.BasicEdge(from, to))
}
return nil
})
})
if err != nil {
return nil, err
}
// Finally, add and connect all the envs
err = db.View(func(tx *bolt.Tx) error {
bucket := tx.Bucket(boltEnvsBucket)
return bucket.ForEach(func(k, data []byte) error {
key := fmt.Sprintf("env-%s", string(k))
graph.Add(key)
// Connect the env to the layer it depends on
to := &layerVertex{Layer: &Layer{ID: string(data)}}
graph.Connect(dag.BasicEdge(key, to))
// Connect the root to the environment that is active
graph.Connect(dag.BasicEdge("root", key))
return nil
})
})
if err != nil {
return nil, err
}
return graph, nil
}
示例3: compileImports
// compileImports takes a File, loads all the imports, and merges them
// into the File.
func (c *Compiler) compileImports(root *File) error {
// If we have no imports, short-circuit the whole thing
if len(root.Imports) == 0 {
return nil
}
// Pull these out into variables so they're easier to reference
storage := c.importStorage
cache := c.importCache
cacheLock := &c.importLock
// A graph is used to track for cycles
var graphLock sync.Mutex
graph := new(dag.AcyclicGraph)
graph.Add("root")
// Since we run the import in parallel, multiple errors can happen
// at the same time. We use multierror and a lock to keep track of errors.
var resultErr error
var resultErrLock sync.Mutex
// Forward declarations for some nested functions we use. The docs
// for these functions are above each.
var importSingle func(parent string, f *File) bool
var downloadSingle func(string, *sync.WaitGroup, *sync.Mutex, []*File, int)
// importSingle is responsible for kicking off the imports and merging
// them for a single file. This will return true on success, false on
// failure. On failure, it is expected that any errors are appended to
// resultErr.
importSingle = func(parent string, f *File) bool {
var wg sync.WaitGroup
// Build the list of files we'll merge later
var mergeLock sync.Mutex
merge := make([]*File, len(f.Imports))
// Go through the imports and kick off the download
for idx, i := range f.Imports {
source, err := getter.Detect(
i.Source, filepath.Dir(f.Path),
getter.Detectors)
if err != nil {
resultErrLock.Lock()
defer resultErrLock.Unlock()
resultErr = multierror.Append(resultErr, fmt.Errorf(
"Error loading import source: %s", err))
return false
}
// Add this to the graph and check now if there are cycles
graphLock.Lock()
graph.Add(source)
graph.Connect(dag.BasicEdge(parent, source))
cycles := graph.Cycles()
graphLock.Unlock()
if len(cycles) > 0 {
for _, cycle := range cycles {
names := make([]string, len(cycle))
for i, v := range cycle {
names[i] = dag.VertexName(v)
}
resultErrLock.Lock()
defer resultErrLock.Unlock()
resultErr = multierror.Append(resultErr, fmt.Errorf(
"Cycle found: %s", strings.Join(names, ", ")))
return false
}
}
wg.Add(1)
go downloadSingle(source, &wg, &mergeLock, merge, idx)
}
// Wait for completion
wg.Wait()
// Go through the merge list and look for any nil entries, which
// means that download failed. In that case, return immediately.
// We assume any errors were put into resultErr.
for _, importF := range merge {
if importF == nil {
return false
}
}
for _, importF := range merge {
// We need to copy importF here so that we don't poison
// the cache by modifying the same pointer.
importFCopy := *importF
importF = &importFCopy
source := importF.ID
importF.ID = ""
importF.Path = ""
// Merge it into our file!
if err := f.Merge(importF); err != nil {
//.........這裏部分代碼省略.........
示例4: compileDependencies
func (c *Compiler) compileDependencies(root *CompiledGraphVertex, graph *dag.AcyclicGraph) error {
// For easier reference below
storage := c.depStorage
// Make a map to keep track of the dep source to vertex mapping
vertexMap := make(map[string]*CompiledGraphVertex)
// Store ourselves in the map
key, err := getter.Detect(
".", filepath.Dir(root.File.Path),
getter.Detectors)
if err != nil {
return err
}
vertexMap[key] = root
// Make a queue for the other vertices we need to still get
// dependencies for. We arbitrarily make the cap for this slice
// 30, since that is a ton of dependencies and we don't expect the
// average case to have more than this.
queue := make([]*CompiledGraphVertex, 1, 30)
queue[0] = root
// While we still have dependencies to get, continue loading them.
// TODO: parallelize
for len(queue) > 0 {
var current *CompiledGraphVertex
current, queue = queue[len(queue)-1], queue[:len(queue)-1]
log.Printf("[DEBUG] compiling dependencies for: %s", current.Name())
for _, dep := range current.File.Application.Dependencies {
key, err := getter.Detect(
dep.Source, filepath.Dir(current.File.Path),
getter.Detectors)
if err != nil {
return fmt.Errorf(
"Error loading source: %s", err)
}
vertex := vertexMap[key]
if vertex == nil {
log.Printf("[DEBUG] loading dependency: %s", key)
// Call the callback if we have one
if c.opts.Callback != nil {
c.opts.Callback(&CompileEventDep{
Source: key,
})
}
// Download the dependency
if err := storage.Get(key, key, true); err != nil {
return err
}
dir, _, err := storage.Dir(key)
if err != nil {
return err
}
// Parse the Appfile if it exists
var f *File
appfilePath := filepath.Join(dir, "Appfile")
_, err = os.Stat(appfilePath)
if err != nil && !os.IsNotExist(err) {
return fmt.Errorf(
"Error parsing Appfile in %s: %s", key, err)
}
if err == nil {
f, err = ParseFile(appfilePath)
if err != nil {
return fmt.Errorf(
"Error parsing Appfile in %s: %s", key, err)
}
// Realize all the imports for this file
if err := c.compileImports(f); err != nil {
return err
}
}
// Do any additional loading if we have a loader
if c.opts.Loader != nil {
f, err = c.opts.Loader(f, dir)
if err != nil {
return fmt.Errorf(
"Error loading Appfile in %s: %s", key, err)
}
}
// Set the source
f.Source = key
// If it doesn't have an otto ID then we can't do anything
hasID, err := f.hasID()
if err != nil {
return fmt.Errorf(
"Error checking for ID file for Appfile in %s: %s",
key, err)
}
if !hasID {
//.........這裏部分代碼省略.........
示例5: compileImports
// compileImports需要一個文件,load所有的imports,然後合並到文件中
func compileImports(root *File, importOpts *compileImportOpts, opts *CompileOpts) error {
// 如果沒有imports,直接短路(返回)
if len(root.Imports) == 0 {
return nil
}
// 把它們放入變量,以便我們可以更早的引用
//storage := importOpts.Storage
//cache := importOpts.Cache
//cacheLock := importOpts.CacheLock
// A graph is used to track for cycles
var graphLock sync.Mutex
graph := new(dag.AcyclicGraph)
graph.Add("root")
// 自從我們平行的執行導入,在同一時間會有多個error發生
// 我們使用multierror lock和跟蹤error
var resultErr error
var resultErrLock sync.Mutex
// Forward declarations for some nested functions we use. The docs
// for these functions are above each.
var importSingle func(parent string, f *File) bool
var downloadSingle func(string, *sync.WaitGroup, *sync.Mutex, []*File, int)
// importSingle is responsible for kicking off the imports and merging
// them for a single file. This will return true on success, false on
// failure. On failure, it is expected that any errors are appended to
// resultErr.
importSingle = func(parent string, f *File) bool {
var wg sync.WaitGroup
// 構建文件列表,後麵將合並
var mergeLock sync.Mutex
merge := make([]*File, len(f.Imports))
// 通過導入並開始處理下載
for idx, i := range f.Imports {
source, err := getter.Detect(i.Source, filepath.Dir(f.Path), getter.Detectors)
if err != nil {
resultErrLock.Lock()
defer resultErrLock.Unlock()
resultErr = multierror.Append(resultErr, fmt.Errorf(
"獲取import源錯誤: %s", err))
return false
}
// Add this to the graph and check now if there are cycles
graphLock.Lock()
graph.Add(source)
graph.Connect(dag.BasicEdge(parent, source))
cycles := graph.Cycles()
graphLock.Unlock()
if len(cycles) > 0 {
for _, cycle := range cycles {
names := make([]string, len(cycle))
for i, v := range cycle {
names[i] = dag.VertexName(v)
}
resultErrLock.Lock()
defer resultErrLock.Unlock()
resultErr = multierror.Append(resultErr, fmt.Errorf(
"Cycle found: %s", strings.Join(names, ", ")))
return false
}
}
wg.Add(1)
go downloadSingle(source, &wg, &mergeLock, merge, idx)
}
// Wait for completion
wg.Wait()
// Go through the merge list and look for any nil entries, which
// means that download failed. In that case, return immediately.
// We assume any errors were put into resultErr.
for _, importF := range merge {
if importF == nil {
return false
}
}
for _, importF := range merge {
// We need to copy importF here so that we don't poison
// the cache by modifying the same pointer.
importFCopy := *importF
importF = &importFCopy
source := importF.ID
importF.ID = ""
importF.Path = ""
// Merge it into our file!
if err := f.Merge(importF); err != nil {
resultErrLock.Lock()
defer resultErrLock.Unlock()
resultErr = multierror.Append(resultErr, fmt.Errorf(
"合並import錯誤 %s : %s", source, err))
//.........這裏部分代碼省略.........
示例6: validateProviderAlias
// validateProviderAlias validates that all provider alias references are
// defined at some point in the parent tree. This improves UX by catching
// alias typos at the slight cost of requiring a declaration of usage. This
// is usually a good tradeoff since not many aliases are used.
func (t *Tree) validateProviderAlias() error {
// If we're not the root, don't perform this validation. We must be the
// root since we require full tree visibilty.
if len(t.path) != 0 {
return nil
}
// We'll use a graph to keep track of defined aliases at each level.
// As long as a parent defines an alias, it is okay.
var g dag.AcyclicGraph
t.buildProviderAliasGraph(&g, nil)
// Go through the graph and check that the usage is all good.
var err error
for _, v := range g.Vertices() {
pv, ok := v.(*providerAliasVertex)
if !ok {
// This shouldn't happen, just ignore it.
continue
}
// If we're not using any aliases, fast track and just continue
if len(pv.Used) == 0 {
continue
}
// Grab the ancestors since we're going to have to check if our
// parents define any of our aliases.
var parents []*providerAliasVertex
ancestors, _ := g.Ancestors(v)
for _, raw := range ancestors.List() {
if pv, ok := raw.(*providerAliasVertex); ok {
parents = append(parents, pv)
}
}
for k, _ := range pv.Used {
// Check if we define this
if _, ok := pv.Defined[k]; ok {
continue
}
// Check for a parent
found := false
for _, parent := range parents {
_, found = parent.Defined[k]
if found {
break
}
}
if found {
continue
}
// We didn't find the alias, error!
err = multierror.Append(err, fmt.Errorf(
"module %s: provider alias must be defined by the module or a parent: %s",
strings.Join(pv.Path, "."), k))
}
}
return err
}