github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/modinstaller/install_data.go (about)

     1  package modinstaller
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Masterminds/semver/v3"
     7  	"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
     8  	"github.com/turbot/steampipe/pkg/steampipeconfig/versionmap"
     9  	"github.com/turbot/steampipe/pkg/versionhelpers"
    10  	"github.com/xlab/treeprint"
    11  )
    12  
    13  type InstallData struct {
    14  	// record of the full dependency tree
    15  	Lock    *versionmap.WorkspaceLock
    16  	NewLock *versionmap.WorkspaceLock
    17  
    18  	// ALL the available versions for each dependency mod(we populate this in a lazy fashion)
    19  	allAvailable versionmap.VersionListMap
    20  
    21  	// list of dependencies installed by recent install operation
    22  	Installed versionmap.DependencyVersionMap
    23  	// list of dependencies which have been upgraded
    24  	Upgraded versionmap.DependencyVersionMap
    25  	// list of dependencies which have been downgraded
    26  	Downgraded versionmap.DependencyVersionMap
    27  	// list of dependencies which have been uninstalled
    28  	Uninstalled  versionmap.DependencyVersionMap
    29  	WorkspaceMod *modconfig.Mod
    30  }
    31  
    32  func NewInstallData(workspaceLock *versionmap.WorkspaceLock, workspaceMod *modconfig.Mod) *InstallData {
    33  	return &InstallData{
    34  		Lock:         workspaceLock,
    35  		WorkspaceMod: workspaceMod,
    36  		NewLock:      versionmap.EmptyWorkspaceLock(workspaceLock),
    37  		allAvailable: make(versionmap.VersionListMap),
    38  		Installed:    make(versionmap.DependencyVersionMap),
    39  		Upgraded:     make(versionmap.DependencyVersionMap),
    40  		Downgraded:   make(versionmap.DependencyVersionMap),
    41  		Uninstalled:  make(versionmap.DependencyVersionMap),
    42  	}
    43  }
    44  
    45  // GetAvailableUpdates returns a map of all installed mods which are not in the lock file
    46  func (d *InstallData) GetAvailableUpdates() (versionmap.DependencyVersionMap, error) {
    47  	res := make(versionmap.DependencyVersionMap)
    48  	for parent, deps := range d.Lock.InstallCache {
    49  		for name, resolvedConstraint := range deps {
    50  			includePrerelease := resolvedConstraint.IsPrerelease()
    51  			availableVersions, err := d.getAvailableModVersions(name, includePrerelease)
    52  			if err != nil {
    53  				return nil, err
    54  			}
    55  			constraint, _ := versionhelpers.NewConstraint(resolvedConstraint.Constraint)
    56  			var latestVersion = getVersionSatisfyingConstraint(constraint, availableVersions)
    57  			if latestVersion.GreaterThan(resolvedConstraint.Version) {
    58  				res.Add(name, resolvedConstraint.Alias, latestVersion, constraint.Original, parent)
    59  			}
    60  		}
    61  	}
    62  	return res, nil
    63  }
    64  
    65  // onModInstalled is called when a dependency is satisfied by installing a mod version
    66  func (d *InstallData) onModInstalled(dependency *ResolvedModRef, modDef *modconfig.Mod, parent *modconfig.Mod) {
    67  	parentPath := parent.GetInstallCacheKey()
    68  	// get the constraint from the parent (it must be there)
    69  	modVersionConstraint := parent.Require.GetModDependency(dependency.Name).Constraint.Original
    70  
    71  	// update lock
    72  	d.NewLock.InstallCache.Add(dependency.Name, modDef.ShortName, modDef.Version, modVersionConstraint, parentPath)
    73  }
    74  
    75  // addExisting is called when a dependency is satisfied by a mod which is already installed
    76  func (d *InstallData) addExisting(dependencyName string, existingDep *modconfig.Mod, constraint *versionhelpers.Constraints, parent *modconfig.Mod) {
    77  	// update lock
    78  	parentPath := parent.GetInstallCacheKey()
    79  	d.NewLock.InstallCache.Add(dependencyName, existingDep.ShortName, existingDep.Version, constraint.Original, parentPath)
    80  }
    81  
    82  // retrieve all available mod versions from our cache, or from Git if not yet cached
    83  func (d *InstallData) getAvailableModVersions(modName string, includePrerelease bool) ([]*semver.Version, error) {
    84  	// have we already loaded the versions for this mod
    85  	availableVersions, ok := d.allAvailable[modName]
    86  	if ok {
    87  		return availableVersions, nil
    88  	}
    89  	// so we have not cached this yet - retrieve from Git
    90  	var err error
    91  	availableVersions, err = getTagVersionsFromGit(getGitUrl(modName), includePrerelease)
    92  	if err != nil {
    93  		return nil, fmt.Errorf("could not retrieve version data from Git URL '%s'", modName)
    94  	}
    95  	// update our cache
    96  	d.allAvailable[modName] = availableVersions
    97  
    98  	return availableVersions, nil
    99  }
   100  
   101  // update the lock with the NewLock and dtermine if any mods have been uninstalled
   102  func (d *InstallData) onInstallComplete() {
   103  	d.Installed = d.NewLock.InstallCache.GetMissingFromOther(d.Lock.InstallCache)
   104  	d.Uninstalled = d.Lock.InstallCache.GetMissingFromOther(d.NewLock.InstallCache)
   105  	d.Upgraded = d.Lock.InstallCache.GetUpgradedInOther(d.NewLock.InstallCache)
   106  	d.Downgraded = d.Lock.InstallCache.GetDowngradedInOther(d.NewLock.InstallCache)
   107  	d.Lock = d.NewLock
   108  }
   109  
   110  func (d *InstallData) GetUpdatedTree() treeprint.Tree {
   111  	return d.Upgraded.GetDependencyTree(d.WorkspaceMod.GetInstallCacheKey())
   112  }
   113  
   114  func (d *InstallData) GetInstalledTree() treeprint.Tree {
   115  	return d.Installed.GetDependencyTree(d.WorkspaceMod.GetInstallCacheKey())
   116  }
   117  
   118  func (d *InstallData) GetUninstalledTree() treeprint.Tree {
   119  	return d.Uninstalled.GetDependencyTree(d.WorkspaceMod.GetInstallCacheKey())
   120  }