func aptlyRepoRemove(cmd *commander.Command, args []string) error { var err error if len(args) < 2 { cmd.Usage() return err } name := args[0] localRepoCollection := debian.NewLocalRepoCollection(context.database) repo, err := localRepoCollection.ByName(name) if err != nil { return fmt.Errorf("unable to remove: %s", err) } err = localRepoCollection.LoadComplete(repo) if err != nil { return fmt.Errorf("unable to remove: %s", err) } context.progress.Printf("Loading packages...\n") packageCollection := debian.NewPackageCollection(context.database) list, err := debian.NewPackageListFromRefList(repo.RefList(), packageCollection) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } list.PrepareIndex() toRemove, err := list.Filter(args[1:], false, nil, 0, nil) if err != nil { return fmt.Errorf("unable to remove: %s", err) } toRemove.ForEach(func(p *debian.Package) error { list.Remove(p) context.progress.ColoredPrintf("@r[-]@| %s removed", p) return nil }) if cmd.Flag.Lookup("dry-run").Value.Get().(bool) { context.progress.Printf("\nChanges not saved, as dry run has been requested.\n") } else { repo.UpdateRefList(debian.NewPackageRefListFromPackageList(list)) err = localRepoCollection.Update(repo) if err != nil { return fmt.Errorf("unable to save: %s", err) } } return err }
func aptlyMirrorUpdate(cmd *commander.Command, args []string) error { var err error if len(args) != 1 { cmd.Usage() return err } name := args[0] repoCollection := debian.NewRemoteRepoCollection(context.database) repo, err := repoCollection.ByName(name) if err != nil { return fmt.Errorf("unable to update: %s", err) } err = repoCollection.LoadComplete(repo) if err != nil { return fmt.Errorf("unable to update: %s", err) } ignoreMismatch := cmd.Flag.Lookup("ignore-checksums").Value.Get().(bool) verifier, err := getVerifier(cmd) if err != nil { return fmt.Errorf("unable to initialize GPG verifier: %s", err) } err = repo.Fetch(context.downloader, verifier) if err != nil { return fmt.Errorf("unable to update: %s", err) } packageCollection := debian.NewPackageCollection(context.database) err = repo.Download(context.downloader, packageCollection, context.packageRepository, ignoreMismatch) if err != nil { return fmt.Errorf("unable to update: %s", err) } err = repoCollection.Update(repo) if err != nil { return fmt.Errorf("unable to update: %s", err) } fmt.Printf("\nMirror `%s` has been successfully updated.\n", repo.Name) return err }
//ListPackagesRefList shows list of packages in PackageRefList func ListPackagesRefList(reflist *debian.PackageRefList) (err error) { fmt.Printf("Packages:\n") packageCollection := debian.NewPackageCollection(context.database) err = reflist.ForEach(func(key []byte) error { p, err := packageCollection.ByKey(key) if err != nil { return err } fmt.Printf(" %s\n", p) return nil }) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } return }
func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error { var err error if len(args) < 3 { cmd.Usage() return err } command := cmd.Name() localRepoCollection := debian.NewLocalRepoCollection(context.database) dstRepo, err := localRepoCollection.ByName(args[1]) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } err = localRepoCollection.LoadComplete(dstRepo) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } var ( srcRefList *debian.PackageRefList srcRepo *debian.LocalRepo ) if command == "copy" || command == "move" { srcRepo, err = localRepoCollection.ByName(args[0]) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } if srcRepo.UUID == dstRepo.UUID { return fmt.Errorf("unable to %s: source and destination are the same", command) } err = localRepoCollection.LoadComplete(srcRepo) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } srcRefList = srcRepo.RefList() } else if command == "import" { repoCollection := debian.NewRemoteRepoCollection(context.database) srcRepo, err := repoCollection.ByName(args[0]) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } err = repoCollection.LoadComplete(srcRepo) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } if srcRepo.RefList() == nil { return fmt.Errorf("unable to %s: mirror not updated", command) } srcRefList = srcRepo.RefList() } else { panic("unexpected command") } context.progress.Printf("Loading packages...\n") packageCollection := debian.NewPackageCollection(context.database) dstList, err := debian.NewPackageListFromRefList(dstRepo.RefList(), packageCollection) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } srcList, err := debian.NewPackageListFromRefList(srcRefList, packageCollection) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } srcList.PrepareIndex() var architecturesList []string withDeps := cmd.Flag.Lookup("with-deps").Value.Get().(bool) if withDeps { dstList.PrepareIndex() // Calculate architectures if len(context.architecturesList) > 0 { architecturesList = context.architecturesList } else { architecturesList = dstList.Architectures(false) } sort.Strings(architecturesList) if len(architecturesList) == 0 { return fmt.Errorf("unable to determine list of architectures, please specify explicitly") } } toProcess, err := srcList.Filter(args[2:], withDeps, dstList, context.dependencyOptions, architecturesList) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } var verb string if command == "move" { verb = "moved" } else if command == "copy" { verb = "copied" } else if command == "import" { verb = "imported" } err = toProcess.ForEach(func(p *debian.Package) error { err = dstList.Add(p) if err != nil { return err } if command == "move" { srcList.Remove(p) } context.progress.ColoredPrintf("@g[o]@| %s %s", p, verb) return nil }) if err != nil { return fmt.Errorf("unable to %s: %s", command, err) } if cmd.Flag.Lookup("dry-run").Value.Get().(bool) { context.progress.Printf("\nChanges not saved, as dry run has been requested.\n") } else { dstRepo.UpdateRefList(debian.NewPackageRefListFromPackageList(dstList)) err = localRepoCollection.Update(dstRepo) if err != nil { return fmt.Errorf("unable to save: %s", err) } if command == "move" { srcRepo.UpdateRefList(debian.NewPackageRefListFromPackageList(srcList)) err = localRepoCollection.Update(srcRepo) if err != nil { return fmt.Errorf("unable to save: %s", err) } } } return err }
func aptlyRepoAdd(cmd *commander.Command, args []string) error { var err error if len(args) < 2 { cmd.Usage() return err } name := args[0] verifier := &utils.GpgVerifier{} localRepoCollection := debian.NewLocalRepoCollection(context.database) repo, err := localRepoCollection.ByName(name) if err != nil { return fmt.Errorf("unable to add: %s", err) } err = localRepoCollection.LoadComplete(repo) if err != nil { return fmt.Errorf("unable to add: %s", err) } context.progress.Printf("Loading packages...\n") packageCollection := debian.NewPackageCollection(context.database) list, err := debian.NewPackageListFromRefList(repo.RefList(), packageCollection) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } packageFiles := []string{} for _, location := range args[1:] { info, err := os.Stat(location) if err != nil { context.progress.ColoredPrintf("@y[!]@| @!Unable to process %s: %s@|", location, err) continue } if info.IsDir() { err = filepath.Walk(location, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".dsc") { packageFiles = append(packageFiles, path) } return nil }) } else { if strings.HasSuffix(info.Name(), ".deb") || strings.HasSuffix(info.Name(), ".dsc") { packageFiles = append(packageFiles, location) } else { context.progress.ColoredPrintf("@y[!]@| @!Unknwon file extenstion: %s@|", location) continue } } } processedFiles := []string{} sort.Strings(packageFiles) for _, file := range packageFiles { var ( stanza debian.Stanza err error p *debian.Package ) isSourcePackage := strings.HasSuffix(file, ".dsc") if isSourcePackage { stanza, err = debian.GetControlFileFromDsc(file, verifier) if err == nil { stanza["Package"] = stanza["Source"] delete(stanza, "Source") p, err = debian.NewSourcePackageFromControlFile(stanza) } } else { stanza, err = debian.GetControlFileFromDeb(file) p = debian.NewPackageFromControlFile(stanza) } if err != nil { context.progress.ColoredPrintf("@y[!]@| @!Unable to read file %s: %s@|", file, err) continue } checksums, err := utils.ChecksumsForFile(file) if err != nil { return err } if isSourcePackage { p.Files = append(p.Files, debian.PackageFile{Filename: filepath.Base(file), Checksums: checksums}) } else { p.Files = []debian.PackageFile{debian.PackageFile{Filename: filepath.Base(file), Checksums: checksums}} } err = context.packagePool.Import(file, checksums.MD5) if err != nil { context.progress.ColoredPrintf("@y[!]@| @!Unable to import file %s into pool: %s@|", file, err) continue } processedFiles = append(processedFiles, file) // go over all files, except for the last one (.dsc/.deb itself) for i := 0; i < len(p.Files)-1; i++ { sourceFile := filepath.Join(filepath.Dir(file), filepath.Base(p.Files[i].Filename)) err = context.packagePool.Import(sourceFile, p.Files[i].Checksums.MD5) if err != nil { context.progress.ColoredPrintf("@y[!]@| @!Unable to import file %s into pool: %s@|", sourceFile, err) break } processedFiles = append(processedFiles, sourceFile) } if err != nil { // some files haven't been imported continue } err = packageCollection.Update(p) if err != nil { context.progress.ColoredPrintf("@y[!]@| @!Unable to save package %s: %s@|", p, err) continue } err = list.Add(p) if err != nil { context.progress.ColoredPrintf("@y[!]@| @!Unable to add package to repo %s: %s@|", p, err) continue } context.progress.ColoredPrintf("@g[+]@| %s added@|", p) } repo.UpdateRefList(debian.NewPackageRefListFromPackageList(list)) err = localRepoCollection.Update(repo) if err != nil { return fmt.Errorf("unable to save: %s", err) } if cmd.Flag.Lookup("remove-files").Value.Get().(bool) { processedFiles = utils.StrSliceDeduplicate(processedFiles) for _, file := range processedFiles { err := os.Remove(file) if err != nil { return fmt.Errorf("unable to remove file: %s", err) } } } return err }
func aptlySnapshotDiff(cmd *commander.Command, args []string) error { var err error if len(args) != 2 { cmd.Usage() return err } onlyMatching := cmd.Flag.Lookup("only-matching").Value.Get().(bool) snapshotCollection := debian.NewSnapshotCollection(context.database) packageCollection := debian.NewPackageCollection(context.database) // Load <name-a> snapshot snapshotA, err := snapshotCollection.ByName(args[0]) if err != nil { return fmt.Errorf("unable to load snapshot A: %s", err) } err = snapshotCollection.LoadComplete(snapshotA) if err != nil { return fmt.Errorf("unable to load snapshot A: %s", err) } // Load <name-b> snapshot snapshotB, err := snapshotCollection.ByName(args[1]) if err != nil { return fmt.Errorf("unable to load snapshot B: %s", err) } err = snapshotCollection.LoadComplete(snapshotB) if err != nil { return fmt.Errorf("unable to load snapshot B: %s", err) } // Calculate diff diff, err := snapshotA.RefList().Diff(snapshotB.RefList(), packageCollection) if err != nil { return fmt.Errorf("unable to calculate diff: %s", err) } if len(diff) == 0 { fmt.Printf("Snapshots are identical.\n") } else { fmt.Printf(" Arch | Package | Version in A | Version in B\n") for _, pdiff := range diff { if onlyMatching && (pdiff.Left == nil || pdiff.Right == nil) { continue } var verA, verB, pkg, arch, code string if pdiff.Left == nil { verA = "-" verB = pdiff.Right.Version pkg = pdiff.Right.Name arch = pdiff.Right.Architecture } else { pkg = pdiff.Left.Name arch = pdiff.Left.Architecture verA = pdiff.Left.Version if pdiff.Right == nil { verB = "-" } else { verB = pdiff.Right.Version } } if pdiff.Left == nil { code = "@g+@|" } else { if pdiff.Right == nil { code = "@r-@|" } else { code = "@y!@|" } } color.Printf(code+" %-6s | %-40s | %-40s | %-40s\n", arch, pkg, verA, verB) } } return err }
func aptlySnapshotPull(cmd *commander.Command, args []string) error { var err error if len(args) < 4 { cmd.Usage() return err } noDeps := cmd.Flag.Lookup("no-deps").Value.Get().(bool) snapshotCollection := debian.NewSnapshotCollection(context.database) packageCollection := debian.NewPackageCollection(context.database) // Load <name> snapshot snapshot, err := snapshotCollection.ByName(args[0]) if err != nil { return fmt.Errorf("unable to pull: %s", err) } err = snapshotCollection.LoadComplete(snapshot) if err != nil { return fmt.Errorf("unable to pull: %s", err) } // Load <source> snapshot source, err := snapshotCollection.ByName(args[1]) if err != nil { return fmt.Errorf("unable to pull: %s", err) } err = snapshotCollection.LoadComplete(source) if err != nil { return fmt.Errorf("unable to pull: %s", err) } fmt.Printf("Dependencies would be pulled into snapshot:\n %s\nfrom snapshot:\n %s\nand result would be saved as new snapshot %s.\n", snapshot, source, args[2]) // Convert snapshot to package list fmt.Printf("Loading packages (%d)...\n", snapshot.RefList().Len()+source.RefList().Len()) packageList, err := debian.NewPackageListFromRefList(snapshot.RefList(), packageCollection) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } sourcePackageList, err := debian.NewPackageListFromRefList(source.RefList(), packageCollection) if err != nil { return fmt.Errorf("unable to load packages: %s", err) } fmt.Printf("Building indexes...\n") packageList.PrepareIndex() sourcePackageList.PrepareIndex() // Calculate architectures var architecturesList []string if len(context.architecturesList) > 0 { architecturesList = context.architecturesList } else { architecturesList = packageList.Architectures(false) } if len(architecturesList) == 0 { return fmt.Errorf("unable to determine list of architectures, please specify explicitly") } // Initial dependencies out of arguments initialDependencies := make([]debian.Dependency, len(args)-3) for i, arg := range args[3:] { initialDependencies[i], err = debian.ParseDependency(arg) if err != nil { return fmt.Errorf("unable to parse argument: %s", err) } } // Perform pull for _, arch := range architecturesList { dependencies := make([]debian.Dependency, len(initialDependencies), 128) for i := range dependencies { dependencies[i] = initialDependencies[i] dependencies[i].Architecture = arch } // Go over list of initial dependencies + list of dependencies found for i := 0; i < len(dependencies); i++ { dep := dependencies[i] // Search for package that can satisfy dependencies pkg := sourcePackageList.Search(dep) if pkg == nil { color.Printf("@y[!]@| @!Dependency %s can't be satisfied with source %s@|", &dep, source) fmt.Printf("\n") continue } // Remove all packages with the same name and architecture for p := packageList.Search(debian.Dependency{Architecture: arch, Pkg: pkg.Name}); p != nil; { packageList.Remove(p) color.Printf("@r[-]@| %s removed", p) fmt.Printf("\n") p = packageList.Search(debian.Dependency{Architecture: arch, Pkg: pkg.Name}) } // Add new discovered package packageList.Add(pkg) color.Printf("@g[+]@| %s added", pkg) fmt.Printf("\n") if noDeps { continue } // Find missing dependencies for single added package pL := debian.NewPackageList() pL.Add(pkg) missing, err := pL.VerifyDependencies(context.dependencyOptions, []string{arch}, packageList) if err != nil { color.Printf("@y[!]@| @!Error while verifying dependencies for pkg %s: %s@|", pkg, err) fmt.Printf("\n") } // Append missing dependencies to the list of dependencies to satisfy for _, misDep := range missing { found := false for _, d := range dependencies { if d == misDep { found = true break } } if !found { dependencies = append(dependencies, misDep) } } } } if cmd.Flag.Lookup("dry-run").Value.Get().(bool) { fmt.Printf("\nNot creating snapshot, as dry run was requested.\n") } else { // Create <destination> snapshot destination := debian.NewSnapshotFromPackageList(args[2], []*debian.Snapshot{snapshot, source}, packageList, fmt.Sprintf("Pulled into '%s' with '%s' as source, pull request was: '%s'", snapshot.Name, source.Name, strings.Join(args[3:], " "))) err = snapshotCollection.Add(destination) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } fmt.Printf("\nSnapshot %s successfully created.\nYou can run 'aptly publish snapshot %s' to publish snapshot as Debian repository.\n", destination.Name, destination.Name) } return err }
func aptlySnapshotVerify(cmd *commander.Command, args []string) error { var err error if len(args) < 1 { cmd.Usage() return err } snapshotCollection := debian.NewSnapshotCollection(context.database) packageCollection := debian.NewPackageCollection(context.database) snapshots := make([]*debian.Snapshot, len(args)) for i := range snapshots { snapshots[i], err = snapshotCollection.ByName(args[i]) if err != nil { return fmt.Errorf("unable to verify: %s", err) } err = snapshotCollection.LoadComplete(snapshots[i]) if err != nil { return fmt.Errorf("unable to verify: %s", err) } } packageList, err := debian.NewPackageListFromRefList(snapshots[0].RefList(), packageCollection) if err != nil { fmt.Errorf("unable to load packages: %s", err) } sourcePackageList := debian.NewPackageList() err = sourcePackageList.Append(packageList) if err != nil { fmt.Errorf("unable to merge sources: %s", err) } for i := 1; i < len(snapshots); i++ { pL, err := debian.NewPackageListFromRefList(snapshots[i].RefList(), packageCollection) if err != nil { fmt.Errorf("unable to load packages: %s", err) } err = sourcePackageList.Append(pL) if err != nil { fmt.Errorf("unable to merge sources: %s", err) } } sourcePackageList.PrepareIndex() var architecturesList []string if len(context.architecturesList) > 0 { architecturesList = context.architecturesList } else { architecturesList = packageList.Architectures(true) } if len(architecturesList) == 0 { return fmt.Errorf("unable to determine list of architectures, please specify explicitly") } missing, err := packageList.VerifyDependencies(context.dependencyOptions, architecturesList, sourcePackageList) if err != nil { return fmt.Errorf("unable to verify dependencies: %s", err) } if len(missing) == 0 { fmt.Printf("All dependencies are satisfied.\n") } else { fmt.Printf("Missing dependencies (%d):\n", len(missing)) deps := make(sort.StringSlice, len(missing)) i := 0 for _, dep := range missing { deps[i] = dep.String() i++ } sort.Strings(deps) for _, dep := range deps { fmt.Printf(" %s\n", dep) } } return err }
func aptlyPublishSnapshot(cmd *commander.Command, args []string) error { var err error if len(args) < 1 || len(args) > 2 { cmd.Usage() return err } name := args[0] var prefix string if len(args) == 2 { prefix = args[1] } else { prefix = "" } publishedCollecton := debian.NewPublishedRepoCollection(context.database) snapshotCollection := debian.NewSnapshotCollection(context.database) snapshot, err := snapshotCollection.ByName(name) if err != nil { return fmt.Errorf("unable to publish: %s", err) } err = snapshotCollection.LoadComplete(snapshot) if err != nil { return fmt.Errorf("unable to publish: %s", err) } var sourceRepo *debian.RemoteRepo if snapshot.SourceKind == "repo" && len(snapshot.SourceIDs) == 1 { repoCollection := debian.NewRemoteRepoCollection(context.database) sourceRepo, _ = repoCollection.ByUUID(snapshot.SourceIDs[0]) } component := cmd.Flag.Lookup("component").Value.String() if component == "" { if sourceRepo != nil && len(sourceRepo.Components) == 1 { component = sourceRepo.Components[0] } else { component = "main" } } distribution := cmd.Flag.Lookup("distribution").Value.String() if distribution == "" { if sourceRepo != nil { distribution = sourceRepo.Distribution } if distribution == "" { return fmt.Errorf("unable to guess distribution name, please specify explicitly") } } published, err := debian.NewPublishedRepo(prefix, distribution, component, context.architecturesList, snapshot) if err != nil { return fmt.Errorf("unable to publish: %s", err) } duplicate := publishedCollecton.CheckDuplicate(published) if duplicate != nil { publishedCollecton.LoadComplete(duplicate, snapshotCollection) return fmt.Errorf("prefix/distribution already used by another published repo: %s", duplicate) } signer, err := getSigner(cmd) if err != nil { return fmt.Errorf("unable to initialize GPG signer: %s", err) } packageCollection := debian.NewPackageCollection(context.database) err = published.Publish(context.packageRepository, packageCollection, signer) if err != nil { return fmt.Errorf("unable to publish: %s", err) } err = publishedCollecton.Add(published) if err != nil { return fmt.Errorf("unable to save to DB: %s", err) } if prefix != "" && !strings.HasSuffix(prefix, "/") { prefix += "/" } fmt.Printf("\nSnapshot %s has been successfully published.\nPlease setup your webserver to serve directory '%s' with autoindexing.\n", snapshot.Name, context.packageRepository.PublicPath()) fmt.Printf("Now you can add following line to apt sources:\n") fmt.Printf(" deb http://your-server/%s %s %s\n", prefix, distribution, component) fmt.Printf("Don't forget to add your GPG key to apt with apt-key.\n") fmt.Printf("\nYou can also use `aptly serve` to publish your repositories over HTTP quickly.\n") return err }
// aptly db cleanup func aptlyDbCleanup(cmd *commander.Command, args []string) error { var err error if len(args) != 0 { cmd.Usage() return err } // collect information about references packages... existingPackageRefs := debian.NewPackageRefList() context.downloader.GetProgress().Printf("Loading mirrors and snapshots...\n") repoCollection := debian.NewRemoteRepoCollection(context.database) err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error { err := repoCollection.LoadComplete(repo) if err != nil { return err } existingPackageRefs = existingPackageRefs.Merge(repo.RefList(), false) return nil }) if err != nil { return err } snapshotCollection := debian.NewSnapshotCollection(context.database) err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error { err := snapshotCollection.LoadComplete(snapshot) if err != nil { return err } existingPackageRefs = existingPackageRefs.Merge(snapshot.RefList(), false) return nil }) if err != nil { return err } // ... and compare it to the list of all packages context.downloader.GetProgress().Printf("Loading list of all packages...\n") packageCollection := debian.NewPackageCollection(context.database) allPackageRefs := packageCollection.AllPackageRefs() toDelete := allPackageRefs.Substract(existingPackageRefs) // delete packages that are no longer referenced context.downloader.GetProgress().Printf("Deleting unreferenced packages (%d)...\n", toDelete.Len()) context.database.StartBatch() err = toDelete.ForEach(func(ref []byte) error { return packageCollection.DeleteByKey(ref) }) if err != nil { return err } err = context.database.FinishBatch() if err != nil { return fmt.Errorf("unable to write to DB: %s", err) } // now, build a list of files that should be present in Repository (package pool) context.downloader.GetProgress().Printf("Building list of files referenced by packages...\n") referencedFiles := make([]string, 0, existingPackageRefs.Len()) context.downloader.GetProgress().InitBar(int64(existingPackageRefs.Len()), false) err = existingPackageRefs.ForEach(func(key []byte) error { pkg, err := packageCollection.ByKey(key) if err != nil { return err } paths, err := pkg.FilepathList(context.packageRepository) if err != nil { return err } referencedFiles = append(referencedFiles, paths...) context.downloader.GetProgress().AddBar(1) return nil }) if err != nil { return err } sort.Strings(referencedFiles) context.downloader.GetProgress().ShutdownBar() // build a list of files in the package pool context.downloader.GetProgress().Printf("Building list of files in package pool...\n") existingFiles, err := context.packageRepository.PoolFilepathList(context.downloader.GetProgress()) if err != nil { return fmt.Errorf("unable to collect file paths: %s", err) } // find files which are in the pool but not referenced by packages filesToDelete := utils.StrSlicesSubstract(existingFiles, referencedFiles) // delete files that are no longer referenced context.downloader.GetProgress().Printf("Deleting unreferenced files (%d)...\n", len(filesToDelete)) if len(filesToDelete) > 0 { context.downloader.GetProgress().InitBar(int64(len(filesToDelete)), false) totalSize := int64(0) for _, file := range filesToDelete { size, err := context.packageRepository.PoolRemove(file) if err != nil { return err } context.downloader.GetProgress().AddBar(1) totalSize += size } context.downloader.GetProgress().ShutdownBar() context.downloader.GetProgress().Printf("Disk space freed: %.2f GiB...\n", float64(totalSize)/1024.0/1024.0/1024.0) } return err }