diff --git a/actionSync.go b/actionSync.go index 132ec53..4783723 100644 --- a/actionSync.go +++ b/actionSync.go @@ -200,7 +200,7 @@ func (s *SyncAction) propagate(modifiedFiles []string) error { } if s.listImpacted { - s.printResources("List of impacted resources:", toPropagate) + s.showImpacted(inv, timeline, toPropagate) } // update resources. @@ -844,7 +844,7 @@ func (s *SyncAction) buildPropagationMap(buildInv *sync.Inventory, timeline []sy } launchr.Term().Info().Printfln("Collecting %s dependencies:", r.GetName()) - err := s.propagateResourceDeps(r, i.GetVersion(), toPropagate, buildInv.GetRequiredMap(), resourceVersionMap) + err := s.propagateResourceDeps(r, i.GetVersion(), toPropagate, buildInv.GetRequiredByMap(), resourceVersionMap) if err != nil { return toPropagate, resourceVersionMap, err } @@ -883,7 +883,7 @@ func (s *SyncAction) buildPropagationMap(buildInv *sync.Inventory, timeline []sy continue } - s.propagateDepsRecursively(r, version, toPropagate, buildInv.GetRequiredMap(), resourceVersionMap) + s.propagateDepsRecursively(r, version, toPropagate, buildInv.GetRequiredByMap(), resourceVersionMap) } } } @@ -922,6 +922,55 @@ func (s *SyncAction) copyHistory(history *sync.OrderedMap[*sync.Resource]) error return nil } +func (s *SyncAction) showImpacted(inv *sync.Inventory, timeline []sync.TimelineItem, propagated *sync.OrderedMap[*sync.Resource]) { + result := sync.NewOrderedMap[bool]() + timelineResources := sync.NewOrderedMap[bool]() + + for _, item := range timeline { + switch i := item.(type) { + case *sync.TimelineResourcesItem: + resources := i.GetResources() + for _, mrn := range resources.Keys() { + timelineResources.Set(mrn, true) + } + } + } + +iterateTimelineResources: + for _, mrn := range timelineResources.Keys() { + deps := inv.GetRequiredByResources(mrn, -1) + for d := range deps { + if _, ok := propagated.Get(d); ok { + continue iterateTimelineResources + } + + if _, ok := timelineResources.Get(d); ok { + continue iterateTimelineResources + } + } + + result.Set(mrn, true) + } + +iteratePropagate: + for _, mrn := range propagated.Keys() { + deps := inv.GetRequiredByResources(mrn, -1) + for d := range deps { + if _, ok := propagated.Get(d); ok { + continue iteratePropagate + } + } + + result.Set(mrn, true) + } + result.SortKeysAlphabetically() + + launchr.Term().Info().Printf("List of impacted resources:\n") + for _, k := range result.Keys() { + launchr.Term().Printf("- %s\n", k) + } +} + func (s *SyncAction) updateResources(toPropagate *sync.OrderedMap[*sync.Resource], resourceVersionMap map[string]string) error { var sortList []string updateMap := make(map[string]map[string]string) @@ -988,36 +1037,6 @@ func (s *SyncAction) updateResources(toPropagate *sync.OrderedMap[*sync.Resource return nil } -func (s *SyncAction) printResources(message string, resources *sync.OrderedMap[*sync.Resource]) { - if message != "" { - launchr.Term().Info().Println(message) - } - - for _, key := range resources.Keys() { - value, _ := resources.Get(key) - launchr.Term().Printfln("- %s", value.GetName()) - } -} - -// -//func (s *SyncAction) printVariablesInfo(rvm map[string]map[string]bool) { -// if len(rvm) == 0 { -// return -// } -// -// info := make(map[string][]string) -// for resourceName, vars := range rvm { -// for variable := range vars { -// info[variable] = append(info[variable], resourceName) -// } -// } -// -// log.Info("Modified variables in diff (group_vars and vaults):") -// for k, v := range info { -// log.Info("- %s used in: %s", k, strings.Join(v, ", ")) -// } -//} - func (s *SyncAction) propagateResourceDeps(resource *sync.Resource, version string, toPropagate *sync.OrderedMap[*sync.Resource], resourcesGraph map[string]*sync.OrderedMap[bool], resourceVersionMap map[string]string) error { if itemsMap, ok := resourcesGraph[resource.GetName()]; ok { itemsMap.SortKeysAlphabetically() diff --git a/pkg/sync/inventory.go b/pkg/sync/inventory.go index 3fcacae..dc3edf6 100644 --- a/pkg/sync/inventory.go +++ b/pkg/sync/inventory.go @@ -96,10 +96,10 @@ type Inventory struct { ResourcesCrawler *ResourcesCrawler //internal - resourcesMap *OrderedMap[bool] - topOrder []string - requiredMap map[string]*OrderedMap[bool] - dependencyMap map[string]*OrderedMap[bool] + resourcesMap *OrderedMap[bool] + requiredBy map[string]*OrderedMap[bool] + dependsOn map[string]*OrderedMap[bool] + topOrder []string // options sourceDir string @@ -113,8 +113,8 @@ func NewInventory(sourceDir string) (*Inventory, error) { sourceDir: sourceDir, ResourcesCrawler: NewResourcesCrawler(sourceDir), resourcesMap: NewOrderedMap[bool](), - requiredMap: make(map[string]*OrderedMap[bool]), - dependencyMap: make(map[string]*OrderedMap[bool]), + requiredBy: make(map[string]*OrderedMap[bool]), + dependsOn: make(map[string]*OrderedMap[bool]), } err := inv.Init() @@ -139,16 +139,14 @@ func (i *Inventory) GetResourcesOrder() []string { return i.topOrder } -// GetRequiredMap returns the required map, which represents the dependencies between resources in the Inventory. -// The map is of type `map[string]map[string]bool`, where the keys are the resource names and the values are maps of dependent resource names. -func (i *Inventory) GetRequiredMap() map[string]*OrderedMap[bool] { - return i.requiredMap +// GetRequiredByMap returns the required by map, which represents the `required by` dependencies between resources in the Inventory. +func (i *Inventory) GetRequiredByMap() map[string]*OrderedMap[bool] { + return i.requiredBy } -// GetDependenciesMap returns the map, which represents the dependencies between resources in the Inventory. -// The map is of type `map[string]map[string]bool`, where the keys are the resource names and the values are maps of dependent resource names. -func (i *Inventory) GetDependenciesMap() map[string]*OrderedMap[bool] { - return i.dependencyMap +// GetDependsOnMap returns the map, which represents the 'depends on' dependencies between resources in the Inventory. +func (i *Inventory) GetDependsOnMap() map[string]*OrderedMap[bool] { + return i.dependsOn } func (i *Inventory) buildResourcesGraph() error { @@ -209,19 +207,19 @@ func (i *Inventory) buildResourcesGraph() error { return nil } - if i.dependencyMap[resourceName] == nil { - i.dependencyMap[resourceName] = NewOrderedMap[bool]() + if i.dependsOn[resourceName] == nil { + i.dependsOn[resourceName] = NewOrderedMap[bool]() } for _, dep := range deps { if dep.IncludeRole.Name != "" { depName := strings.ReplaceAll(dep.IncludeRole.Name, ".", "__") - if i.requiredMap[depName] == nil { - i.requiredMap[depName] = NewOrderedMap[bool]() + if i.requiredBy[depName] == nil { + i.requiredBy[depName] = NewOrderedMap[bool]() } - i.requiredMap[depName].Set(resourceName, true) - i.dependencyMap[resourceName].Set(depName, true) + i.requiredBy[depName].Set(resourceName, true) + i.dependsOn[resourceName].Set(depName, true) } } } @@ -233,15 +231,15 @@ func (i *Inventory) buildResourcesGraph() error { } platformItems := NewOrderedMap[bool]() - for resourceName := range i.requiredMap { - if _, ok := i.dependencyMap[resourceName]; !ok { + for resourceName := range i.requiredBy { + if _, ok := i.dependsOn[resourceName]; !ok { platformItems.Set(resourceName, true) } } - i.requiredMap[rootPlatform] = platformItems + i.requiredBy[rootPlatform] = platformItems graph := topsort.NewGraph() - for platform, resources := range i.requiredMap { + for platform, resources := range i.requiredBy { for _, resource := range resources.Keys() { graph.AddNode(resource) edgeErr := graph.AddEdge(platform, resource) @@ -493,6 +491,41 @@ func (i *Inventory) SearchVariablesAffectedResources(variables []*Variable) (*Or return resources, resourceVariablesMap, nil } +// GetRequiredByResources returns list of resources which depend on argument resource (directly or not). +func (i *Inventory) GetRequiredByResources(resourceName string, depth int8) map[string]bool { + return i.lookupDependencies(resourceName, i.GetRequiredByMap(), depth) +} + +// GetDependsOnResources returns list of resources which are used by argument resource (directly or not). +func (i *Inventory) GetDependsOnResources(resourceName string, depth int8) map[string]bool { + return i.lookupDependencies(resourceName, i.GetDependsOnMap(), depth) +} + +func (i *Inventory) lookupDependencies(resourceName string, resourcesMap map[string]*OrderedMap[bool], depth int8) map[string]bool { + result := make(map[string]bool) + if m, ok := resourcesMap[resourceName]; ok { + for _, item := range m.Keys() { + result[item] = true + i.lookupDependenciesRecursively(item, resourcesMap, result, 1, depth) + } + } + + return result +} + +func (i *Inventory) lookupDependenciesRecursively(resourceName string, resourcesMap map[string]*OrderedMap[bool], result map[string]bool, depth, limit int8) { + if depth == limit { + return + } + + if m, ok := resourcesMap[resourceName]; ok { + for _, item := range m.Keys() { + result[item] = true + i.lookupDependenciesRecursively(item, resourcesMap, result, depth+1, limit) + } + } +} + func (i *Inventory) pushRequiredVariables(requiredMap map[string]map[string]bool) { for k, v := range requiredMap { for name := range v {