Pass by options to compute functions in install

This commit is contained in:
Ettore Di Giacinto
2021-04-24 14:26:26 +02:00
parent 848215eef0
commit 55ae67be0f
2 changed files with 177 additions and 32 deletions

View File

@@ -198,7 +198,7 @@ func (l *LuetInstaller) Swap(toRemove pkg.Packages, toInstall pkg.Packages, s *S
return l.swap(syncedRepos, toRemoveFinal, toInstall, s, false) return l.swap(syncedRepos, toRemoveFinal, toInstall, s, false)
} }
func (l *LuetInstaller) computeSwap(syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System) (map[string]ArtifactMatch, pkg.Packages, solver.PackagesAssertions, pkg.PackageDatabase, error) { func (l *LuetInstaller) computeSwap(o Option, syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System) (map[string]ArtifactMatch, pkg.Packages, solver.PackagesAssertions, pkg.PackageDatabase, error) {
allRepos := pkg.NewInMemoryDatabase(false) allRepos := pkg.NewInMemoryDatabase(false)
syncedRepos.SyncDatabase(allRepos) syncedRepos.SyncDatabase(allRepos)
@@ -213,7 +213,7 @@ func (l *LuetInstaller) computeSwap(syncedRepos Repositories, toRemove pkg.Packa
systemAfterChanges := &System{Database: installedtmp} systemAfterChanges := &System{Database: installedtmp}
packs, err := l.computeUninstall(systemAfterChanges, toRemove...) packs, err := l.computeUninstall(o, systemAfterChanges, toRemove...)
if err != nil && !l.Options.Force { if err != nil && !l.Options.Force {
Error("Failed computing uninstall for ", packsToList(toRemove)) Error("Failed computing uninstall for ", packsToList(toRemove))
return nil, nil, nil, nil, errors.Wrap(err, "computing uninstall "+packsToList(toRemove)) return nil, nil, nil, nil, errors.Wrap(err, "computing uninstall "+packsToList(toRemove))
@@ -233,8 +233,8 @@ func (l *LuetInstaller) computeSwap(syncedRepos Repositories, toRemove pkg.Packa
} }
func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System, forceNodeps bool) error { func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, toInstall pkg.Packages, s *System, forceNodeps bool) error {
forced := l.Options.Force //forced := l.Options.Force
nodeps := l.Options.NoDeps // nodeps := l.Options.NoDeps
// We don't want any conflict with the installed to raise during the upgrade. // We don't want any conflict with the installed to raise during the upgrade.
// In this way we both force uninstalls and we avoid to check with conflicts // In this way we both force uninstalls and we avoid to check with conflicts
@@ -244,11 +244,20 @@ func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, to
// now the solver enforces the constraints and explictly denies two packages // now the solver enforces the constraints and explictly denies two packages
// of the same version installed. // of the same version installed.
l.Options.Force = true l.Options.Force = true
nodeps := l.Options.NoDeps
if forceNodeps { if forceNodeps {
l.Options.NoDeps = true nodeps = true
} }
match, packages, assertions, allRepos, err := l.computeSwap(syncedRepos, toRemove, toInstall, s) o := Option{
FullUninstall: l.Options.FullUninstall,
Force: true,
CheckConflicts: l.Options.CheckConflicts,
FullCleanUninstall: l.Options.FullCleanUninstall,
NoDeps: nodeps,
}
match, packages, assertions, allRepos, err := l.computeSwap(o, syncedRepos, toRemove, toInstall, s)
if err != nil { if err != nil {
return errors.Wrap(err, "failed computing package replacement") return errors.Wrap(err, "failed computing package replacement")
} }
@@ -278,15 +287,123 @@ func (l *LuetInstaller) swap(syncedRepos Repositories, toRemove pkg.Packages, to
return nil return nil
} }
err = l.Uninstall(s, toRemove...) toUninstall, uninstall, err := l.generateUninstallFn(o, s, toRemove...)
if err != nil && !l.Options.Force { if err != nil && !o.Force {
Error("Failed uninstall for ", packsToList(toRemove)) return errors.Wrap(err, "while computing uninstall")
return errors.Wrap(err, "uninstalling "+packsToList(toRemove))
} }
l.Options.Force = forced err = uninstall()
l.Options.NoDeps = nodeps if err != nil && !o.Force {
return l.install(syncedRepos, match, packages, assertions, allRepos, s) Error("Failed uninstall for ", packsToList(toUninstall))
return errors.Wrap(err, "uninstalling "+packsToList(toUninstall))
}
o = Option{
Force: l.Options.Force,
NoDeps: l.Options.NoDeps,
}
return l.install(o, syncedRepos, match, packages, assertions, allRepos, s)
}
type Option struct {
Force bool
NoDeps bool
CheckConflicts bool
FullUninstall bool
FullCleanUninstall bool
}
type operation struct {
Option Option
Package pkg.Package
}
// installerOp is the operation that is sent to the
// upgradeWorker's channel (todo)
type installerOp struct {
Uninstall operation
Install operation
}
func (l *LuetInstaller) runOps(syncedRepos Repositories, ops []installerOp, p pkg.Packages, solution solver.PackagesAssertions, allRepos pkg.PackageDatabase, s *System) error {
all := make(chan installerOp)
wg := new(sync.WaitGroup)
// Do the real install
for i := 0; i < l.Options.Concurrency; i++ {
wg.Add(1)
go l.installerOpWorker(i, wg, all, s)
}
for _, c := range ops {
all <- c
}
close(all)
wg.Wait()
return nil
}
func (l *LuetInstaller) installerOpWorker(i int, wg *sync.WaitGroup, c <-chan installerOp, s *System) error {
defer wg.Done()
for p := range c {
if p.Uninstall.Package != nil {
toUninstall, uninstall, err := l.generateUninstallFn(p.Uninstall.Option, s, p.Uninstall.Package)
if err != nil && !l.Options.Force {
return errors.Wrap(err, "while computing uninstall")
}
err = uninstall()
if err != nil && !p.Uninstall.Option.Force {
Error("Failed uninstall for ", packsToList(toUninstall))
return errors.Wrap(err, "uninstalling "+packsToList(toUninstall))
}
}
// return l.install(p.Install.Option, match, packages, assertions, allRepos, s)
}
return nil
}
// checks wheter we can uninstall and install in place and compose installer worker ops
func (l *LuetInstaller) getOpsWithOptions(toUninstall pkg.Packages, installMatch map[string]ArtifactMatch, installOpt, uninstallOpt Option) []installerOp {
resOps := []installerOp{}
for _, match := range installMatch {
if pack, err := toUninstall.Find(match.Package.GetPackageName()); err == nil {
resOps = append(resOps, installerOp{
Uninstall: operation{Package: pack, Option: uninstallOpt},
Install: operation{Package: match.Package, Option: installOpt},
})
} else {
resOps = append(resOps, installerOp{
Install: operation{Package: match.Package, Option: installOpt},
})
}
}
for _, p := range toUninstall {
found := false
for _, match := range installMatch {
if match.Package.GetPackageName() == p.GetPackageName() {
found = true
}
}
if !found {
resOps = append(resOps, installerOp{
Uninstall: operation{Package: p, Option: uninstallOpt},
})
}
}
return resOps
} }
func (l *LuetInstaller) checkAndUpgrade(r Repositories, s *System) error { func (l *LuetInstaller) checkAndUpgrade(r Repositories, s *System) error {
@@ -370,17 +487,20 @@ func (l *LuetInstaller) Install(cp pkg.Packages, s *System) error {
} }
} }
Info("Packages that are going to be installed in the system: \n ", Green(matchesToList(match)).BgBlack().String()) Info("Packages that are going to be installed in the system: \n ", Green(matchesToList(match)).BgBlack().String())
o := Option{
NoDeps: l.Options.NoDeps,
Force: l.Options.Force,
}
if l.Options.Ask { if l.Options.Ask {
Info("By going forward, you are also accepting the licenses of the packages that you are going to install in your system.") Info("By going forward, you are also accepting the licenses of the packages that you are going to install in your system.")
if Ask() { if Ask() {
l.Options.Ask = false // Don't prompt anymore l.Options.Ask = false // Don't prompt anymore
return l.install(syncedRepos, match, packages, assertions, allRepos, s) return l.install(o, syncedRepos, match, packages, assertions, allRepos, s)
} else { } else {
return errors.New("Aborted by user") return errors.New("Aborted by user")
} }
} }
return l.install(syncedRepos, match, packages, assertions, allRepos, s) return l.install(o, syncedRepos, match, packages, assertions, allRepos, s)
} }
func (l *LuetInstaller) download(syncedRepos Repositories, toDownload map[string]ArtifactMatch) error { func (l *LuetInstaller) download(syncedRepos Repositories, toDownload map[string]ArtifactMatch) error {
@@ -540,7 +660,7 @@ func (l *LuetInstaller) computeInstall(syncedRepos Repositories, cp pkg.Packages
return toInstall, p, solution, allRepos, nil return toInstall, p, solution, allRepos, nil
} }
func (l *LuetInstaller) install(syncedRepos Repositories, toInstall map[string]ArtifactMatch, p pkg.Packages, solution solver.PackagesAssertions, allRepos pkg.PackageDatabase, s *System) error { func (l *LuetInstaller) install(o Option, syncedRepos Repositories, toInstall map[string]ArtifactMatch, p pkg.Packages, solution solver.PackagesAssertions, allRepos pkg.PackageDatabase, s *System) error {
// Install packages into rootfs in parallel. // Install packages into rootfs in parallel.
if err := l.download(syncedRepos, toInstall); err != nil { if err := l.download(syncedRepos, toInstall); err != nil {
return errors.Wrap(err, "Downloading packages") return errors.Wrap(err, "Downloading packages")
@@ -569,13 +689,13 @@ func (l *LuetInstaller) install(syncedRepos Repositories, toInstall map[string]A
for _, c := range toInstall { for _, c := range toInstall {
// Annotate to the system that the package was installed // Annotate to the system that the package was installed
_, err := s.Database.CreatePackage(c.Package) _, err := s.Database.CreatePackage(c.Package)
if err != nil && !l.Options.Force { if err != nil && !o.Force {
return errors.Wrap(err, "Failed creating package") return errors.Wrap(err, "Failed creating package")
} }
bus.Manager.Publish(bus.EventPackageInstall, c) bus.Manager.Publish(bus.EventPackageInstall, c)
} }
var toFinalize []pkg.Package var toFinalize []pkg.Package
if !l.Options.NoDeps { if !o.NoDeps {
// TODO: Lower those errors as warning // TODO: Lower those errors as warning
for _, w := range p { for _, w := range p {
// Finalizers needs to run in order and in sequence. // Finalizers needs to run in order and in sequence.
@@ -779,14 +899,14 @@ func (l *LuetInstaller) uninstall(p pkg.Package, s *System) error {
return nil return nil
} }
func (l *LuetInstaller) computeUninstall(s *System, packs ...pkg.Package) (pkg.Packages, error) { func (l *LuetInstaller) computeUninstall(o Option, s *System, packs ...pkg.Package) (pkg.Packages, error) {
var toUninstall pkg.Packages var toUninstall pkg.Packages
// compute uninstall from all world - remove packages in parallel - run uninstall finalizer (in order) TODO - mark the uninstallation in db // compute uninstall from all world - remove packages in parallel - run uninstall finalizer (in order) TODO - mark the uninstallation in db
// Get installed definition // Get installed definition
checkConflicts := l.Options.CheckConflicts checkConflicts := o.CheckConflicts
full := l.Options.FullUninstall full := o.FullUninstall
if l.Options.Force == true { // IF forced, we want to remove the package and all its requires if o.Force == true { // IF forced, we want to remove the package and all its requires
checkConflicts = false checkConflicts = false
full = false full = false
} }
@@ -803,7 +923,7 @@ func (l *LuetInstaller) computeUninstall(s *System, packs ...pkg.Package) (pkg.P
solv := solver.NewResolver(solver.Options{Type: l.Options.SolverOptions.Implementation, Concurrency: l.Options.Concurrency}, installedtmp, installedtmp, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver()) solv := solver.NewResolver(solver.Options{Type: l.Options.SolverOptions.Implementation, Concurrency: l.Options.Concurrency}, installedtmp, installedtmp, pkg.NewInMemoryDatabase(false), l.Options.SolverOptions.Resolver())
var solution pkg.Packages var solution pkg.Packages
var err error var err error
if l.Options.FullCleanUninstall { if o.FullCleanUninstall {
solution, err = solv.UninstallUniverse(packs) solution, err = solv.UninstallUniverse(packs)
if err != nil { if err != nil {
return toUninstall, errors.Wrap(err, "Could not solve the uninstall constraints. Tip: try with --solver-type qlearning or with --force, or by removing packages excluding their dependencies with --nodeps") return toUninstall, errors.Wrap(err, "Could not solve the uninstall constraints. Tip: try with --solver-type qlearning or with --force, or by removing packages excluding their dependencies with --nodeps")
@@ -824,32 +944,47 @@ func (l *LuetInstaller) computeUninstall(s *System, packs ...pkg.Package) (pkg.P
return toUninstall, nil return toUninstall, nil
} }
func (l *LuetInstaller) Uninstall(s *System, packs ...pkg.Package) error {
func (l *LuetInstaller) generateUninstallFn(o Option, s *System, packs ...pkg.Package) (pkg.Packages, func() error, error) {
for _, p := range packs { for _, p := range packs {
if packs, _ := s.Database.FindPackages(p); len(packs) == 0 { if packs, _ := s.Database.FindPackages(p); len(packs) == 0 {
return errors.New("Package not found in the system") return nil, nil, errors.New("Package not found in the system")
} }
} }
Spinner(32) toUninstall, err := l.computeUninstall(o, s, packs...)
toUninstall, err := l.computeUninstall(s, packs...)
if err != nil { if err != nil {
return errors.Wrap(err, "while computing uninstall") return nil, nil, errors.Wrap(err, "while computing uninstall")
} }
SpinnerStop()
uninstall := func() error { uninstall := func() error {
for _, p := range toUninstall { for _, p := range toUninstall {
err := l.uninstall(p, s) err := l.uninstall(p, s)
if err != nil && !l.Options.Force { if err != nil && !o.Force {
return errors.Wrap(err, "Uninstall failed") return errors.Wrap(err, "Uninstall failed")
} }
} }
return nil return nil
} }
return toUninstall, uninstall, nil
}
func (l *LuetInstaller) Uninstall(s *System, packs ...pkg.Package) error {
Spinner(32)
o := Option{
FullUninstall: l.Options.FullUninstall,
Force: l.Options.Force,
CheckConflicts: l.Options.CheckConflicts,
FullCleanUninstall: l.Options.FullCleanUninstall,
}
toUninstall, uninstall, err := l.generateUninstallFn(o, s, packs...)
if err != nil {
return errors.Wrap(err, "while computing uninstall")
}
SpinnerStop()
if len(toUninstall) == 0 { if len(toUninstall) == 0 {
Info("Nothing to do") Info("Nothing to do")
return nil return nil

View File

@@ -645,6 +645,16 @@ func (set Packages) Best(v version.Versioner) Package {
return versionsMap[sorted[len(sorted)-1]] return versionsMap[sorted[len(sorted)-1]]
} }
func (set Packages) Find(packageName string) (Package, error) {
for _, p := range set {
if p.GetPackageName() == packageName {
return p, nil
}
}
return &DefaultPackage{}, errors.New("package not found")
}
func (set Packages) Unique() Packages { func (set Packages) Unique() Packages {
var result Packages var result Packages
uniq := make(map[string]Package) uniq := make(map[string]Package)