func aptlyRepoShow(cmd *commander.Command, args []string) error { var err error if len(args) != 1 { 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 show: %s", err) } err = localRepoCollection.LoadComplete(repo) if err != nil { return fmt.Errorf("unable to show: %s", err) } fmt.Printf("Name: %s\n", repo.Name) fmt.Printf("Comment: %s\n", repo.Comment) fmt.Printf("Number of packages: %d\n", repo.NumPackages()) withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool) if withPackages { ListPackagesRefList(repo.RefList()) } return err }
func aptlyRepoList(cmd *commander.Command, args []string) error { var err error if len(args) != 0 { cmd.Usage() return err } localRepoCollection := debian.NewLocalRepoCollection(context.database) if localRepoCollection.Len() > 0 { fmt.Printf("List of mirrors:\n") repos := make([]string, localRepoCollection.Len()) i := 0 localRepoCollection.ForEach(func(repo *debian.LocalRepo) error { err := localRepoCollection.LoadComplete(repo) if err != nil { return err } repos[i] = fmt.Sprintf(" * %s (packages: %d)", repo.String(), repo.NumPackages()) i++ return nil }) sort.Strings(repos) for _, repo := range repos { fmt.Println(repo) } fmt.Printf("\nTo get more information about local repository, run `aptly repo show <name>`.\n") } else { fmt.Printf("No local repositories found, create one with `aptly repo create ...`.\n") } return err }
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 aptlyRepoCreate(cmd *commander.Command, args []string) error { var err error if len(args) != 1 { cmd.Usage() return err } repo := debian.NewLocalRepo(args[0], cmd.Flag.Lookup("comment").Value.String()) localRepoCollection := debian.NewLocalRepoCollection(context.database) err = localRepoCollection.Add(repo) if err != nil { return fmt.Errorf("unable to add local repo: %s", err) } fmt.Printf("\nLocal repo %s successfully added.\nYou can run 'aptly repo add %s ...' to add packages to repository.\n", repo, repo.Name) return err }
func aptlyRepoDrop(cmd *commander.Command, args []string) error { var err error if len(args) != 1 { 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 drop: %s", err) } force := cmd.Flag.Lookup("force").Value.Get().(bool) if !force { snapshotCollection := debian.NewSnapshotCollection(context.database) snapshots := snapshotCollection.ByLocalRepoSource(repo) if len(snapshots) > 0 { fmt.Printf("Local repo `%s` was used to create following snapshots:\n", repo.Name) for _, snapshot := range snapshots { fmt.Printf(" * %s\n", snapshot) } return fmt.Errorf("won't delete local repo with snapshots, use -force to override") } } err = localRepoCollection.Drop(repo) if err != nil { return fmt.Errorf("unable to drop: %s", err) } fmt.Printf("Local repo `%s` has been removed.\n", repo.Name) return err }
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 aptlyGraph(cmd *commander.Command, args []string) error { var err error graph := gographviz.NewGraph() graph.SetDir(true) graph.SetName("aptly") existingNodes := map[string]bool{} fmt.Printf("Loading mirrors...\n") repoCollection := debian.NewRemoteRepoCollection(context.database) err = repoCollection.ForEach(func(repo *debian.RemoteRepo) error { err := repoCollection.LoadComplete(repo) if err != nil { return err } graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{ "shape": "Mrecord", "style": "filled", "fillcolor": "darkgoldenrod1", "label": graphvizEscape(fmt.Sprintf("{Mirror %s|url: %s|dist: %s|comp: %s|arch: %s|pkgs: %d}", repo.Name, repo.ArchiveRoot, repo.Distribution, strings.Join(repo.Components, ", "), strings.Join(repo.Architectures, ", "), repo.NumPackages())), }) existingNodes[repo.UUID] = true return nil }) if err != nil { return err } fmt.Printf("Loading local repos...\n") localRepoCollection := debian.NewLocalRepoCollection(context.database) err = localRepoCollection.ForEach(func(repo *debian.LocalRepo) error { err := localRepoCollection.LoadComplete(repo) if err != nil { return err } graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{ "shape": "Mrecord", "style": "filled", "fillcolor": "mediumseagreen", "label": graphvizEscape(fmt.Sprintf("{Repo %s|comment: %s|pkgs: %d}", repo.Name, repo.Comment, repo.NumPackages())), }) existingNodes[repo.UUID] = true return nil }) if err != nil { return err } fmt.Printf("Loading snapshots...\n") snapshotCollection := debian.NewSnapshotCollection(context.database) snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error { existingNodes[snapshot.UUID] = true return nil }) err = snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error { err := snapshotCollection.LoadComplete(snapshot) if err != nil { return err } description := snapshot.Description if snapshot.SourceKind == "repo" { description = "Snapshot from repo" } graph.AddNode("aptly", graphvizEscape(snapshot.UUID), map[string]string{ "shape": "Mrecord", "style": "filled", "fillcolor": "cadetblue1", "label": graphvizEscape(fmt.Sprintf("{Snapshot %s|%s|pkgs: %d}", snapshot.Name, description, snapshot.NumPackages())), }) if snapshot.SourceKind == "repo" || snapshot.SourceKind == "local" || snapshot.SourceKind == "snapshot" { for _, uuid := range snapshot.SourceIDs { _, exists := existingNodes[uuid] if exists { graph.AddEdge(graphvizEscape(uuid), "", graphvizEscape(snapshot.UUID), "", true, nil) } } } return nil }) if err != nil { return err } fmt.Printf("Loading published repos...\n") publishedCollection := debian.NewPublishedRepoCollection(context.database) publishedCollection.ForEach(func(repo *debian.PublishedRepo) error { graph.AddNode("aptly", graphvizEscape(repo.UUID), map[string]string{ "shape": "Mrecord", "style": "filled", "fillcolor": "darkolivegreen1", "label": graphvizEscape(fmt.Sprintf("{Published %s/%s|comp: %s|arch: %s}", repo.Prefix, repo.Distribution, repo.Component, strings.Join(repo.Architectures, ", "))), }) _, exists := existingNodes[repo.SnapshotUUID] if exists { graph.AddEdge(graphvizEscape(repo.SnapshotUUID), "", graphvizEscape(repo.UUID), "", true, nil) } return nil }) fmt.Printf("Generating graph...\n") buf := bytes.NewBufferString(graph.String()) tempfile, err := ioutil.TempFile("", "aptly-graph") if err != nil { return err } tempfile.Close() os.Remove(tempfile.Name()) tempfilename := tempfile.Name() + ".png" command := exec.Command("dot", "-Tpng", "-o"+tempfilename) command.Stderr = os.Stderr stdin, err := command.StdinPipe() if err != nil { return err } err = command.Start() if err != nil { return fmt.Errorf("unable to execute dot: %s (is graphviz package installed?)", err) } _, err = io.Copy(stdin, buf) if err != nil { return err } err = stdin.Close() if err != nil { return err } err = command.Wait() if err != nil { return err } err = exec.Command("open", tempfilename).Run() if err != nil { fmt.Printf("Rendered to PNG file: %s\n", tempfilename) err = nil } 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 aptlySnapshotCreate(cmd *commander.Command, args []string) error { var ( err error snapshot *debian.Snapshot ) if len(args) == 4 && args[1] == "from" && args[2] == "mirror" { // aptly snapshot create snap from mirror mirror repoName, snapshotName := args[3], args[0] repoCollection := debian.NewRemoteRepoCollection(context.database) repo, err := repoCollection.ByName(repoName) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } err = repoCollection.LoadComplete(repo) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } snapshot, err = debian.NewSnapshotFromRepository(snapshotName, repo) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } } else if len(args) == 4 && args[1] == "from" && args[2] == "repo" { // aptly snapshot create snap from repo repo localRepoName, snapshotName := args[3], args[0] localRepoCollection := debian.NewLocalRepoCollection(context.database) repo, err := localRepoCollection.ByName(localRepoName) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } err = localRepoCollection.LoadComplete(repo) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } snapshot, err = debian.NewSnapshotFromLocalRepo(snapshotName, repo) if err != nil { return fmt.Errorf("unable to create snapshot: %s", err) } } else if len(args) == 2 && args[1] == "empty" { // aptly snapshot create snap empty snapshotName := args[0] packageList := debian.NewPackageList() snapshot = debian.NewSnapshotFromPackageList(snapshotName, nil, packageList, "Created as empty") } else { cmd.Usage() return err } snapshotCollection := debian.NewSnapshotCollection(context.database) err = snapshotCollection.Add(snapshot) if err != nil { return fmt.Errorf("unable to add snapshot: %s", err) } fmt.Printf("\nSnapshot %s successfully created.\nYou can run 'aptly publish snapshot %s' to publish snapshot as Debian repository.\n", snapshot.Name, snapshot.Name) 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.progress.Printf("Loading mirrors, local repos 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 } if repo.RefList() != nil { existingPackageRefs = existingPackageRefs.Merge(repo.RefList(), false) } return nil }) if err != nil { return err } localRepoCollection := debian.NewLocalRepoCollection(context.database) err = localRepoCollection.ForEach(func(repo *debian.LocalRepo) error { err := localRepoCollection.LoadComplete(repo) if err != nil { return err } if repo.RefList() != nil { 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.progress.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.progress.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.progress.Printf("Building list of files referenced by packages...\n") referencedFiles := make([]string, 0, existingPackageRefs.Len()) context.progress.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.packagePool) if err != nil { return err } referencedFiles = append(referencedFiles, paths...) context.progress.AddBar(1) return nil }) if err != nil { return err } sort.Strings(referencedFiles) context.progress.ShutdownBar() // build a list of files in the package pool context.progress.Printf("Building list of files in package pool...\n") existingFiles, err := context.packagePool.FilepathList(context.progress) 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.progress.Printf("Deleting unreferenced files (%d)...\n", len(filesToDelete)) if len(filesToDelete) > 0 { context.progress.InitBar(int64(len(filesToDelete)), false) totalSize := int64(0) for _, file := range filesToDelete { size, err := context.packagePool.Remove(file) if err != nil { return err } context.progress.AddBar(1) totalSize += size } context.progress.ShutdownBar() context.progress.Printf("Disk space freed: %.2f GiB...\n", float64(totalSize)/1024.0/1024.0/1024.0) } return err }