mirror of
https://github.com/aptly-dev/aptly.git
synced 2026-06-05 05:20:34 +00:00
Refactor commands to subpackage.
This commit is contained in:
+62
@@ -0,0 +1,62 @@
|
||||
// Package cmd implements console commands
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"os"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// RootCommand creates root command in command tree
|
||||
func RootCommand() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
UsageLine: os.Args[0],
|
||||
Short: "Debian repository management tool",
|
||||
Long: `
|
||||
}
|
||||
aptly is a tool to create partial and full mirrors of remote
|
||||
repositories, filter them, merge, upgrade individual packages,
|
||||
take snapshots and publish them back as Debian repositories.`,
|
||||
Flag: *flag.NewFlagSet("aptly", flag.ExitOnError),
|
||||
Subcommands: []*commander.Command{
|
||||
makeCmdDb(),
|
||||
makeCmdGraph(),
|
||||
makeCmdMirror(),
|
||||
makeCmdServe(),
|
||||
makeCmdSnapshot(),
|
||||
makeCmdPublish(),
|
||||
makeCmdVersion(),
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("dep-follow-suggests", false, "when processing dependencies, follow Suggests")
|
||||
cmd.Flag.Bool("dep-follow-source", false, "when processing dependencies, follow from binary to Source packages")
|
||||
cmd.Flag.Bool("dep-follow-recommends", false, "when processing dependencies, follow Recommends")
|
||||
cmd.Flag.Bool("dep-follow-all-variants", false, "when processing dependencies, follow a & b if depdency is 'a|b'")
|
||||
cmd.Flag.String("architectures", "", "list of architectures to consider during (comma-separated), default to all available")
|
||||
cmd.Flag.String("config", "", "location of configuration file (default locations are /etc/aptly.conf, ~/.aptly.conf)")
|
||||
return cmd
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/smira/aptly/aptly"
|
||||
"github.com/smira/aptly/console"
|
||||
"github.com/smira/aptly/database"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/files"
|
||||
"github.com/smira/aptly/http"
|
||||
"github.com/smira/aptly/utils"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Common context shared by all commands
|
||||
var context struct {
|
||||
progress aptly.Progress
|
||||
downloader aptly.Downloader
|
||||
database database.Storage
|
||||
packagePool aptly.PackagePool
|
||||
publishedStorage aptly.PublishedStorage
|
||||
dependencyOptions int
|
||||
architecturesList []string
|
||||
}
|
||||
|
||||
func InitContext(cmd *commander.Command) error {
|
||||
var err error
|
||||
|
||||
context.dependencyOptions = 0
|
||||
if utils.Config.DepFollowSuggests || cmd.Flag.Lookup("dep-follow-suggests").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowSuggests
|
||||
}
|
||||
if utils.Config.DepFollowRecommends || cmd.Flag.Lookup("dep-follow-recommends").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowRecommends
|
||||
}
|
||||
if utils.Config.DepFollowAllVariants || cmd.Flag.Lookup("dep-follow-all-variants").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowAllVariants
|
||||
}
|
||||
if utils.Config.DepFollowSource || cmd.Flag.Lookup("dep-follow-source").Value.Get().(bool) {
|
||||
context.dependencyOptions |= debian.DepFollowSource
|
||||
}
|
||||
|
||||
context.architecturesList = utils.Config.Architectures
|
||||
optionArchitectures := cmd.Flag.Lookup("architectures").Value.String()
|
||||
if optionArchitectures != "" {
|
||||
context.architecturesList = strings.Split(optionArchitectures, ",")
|
||||
}
|
||||
|
||||
context.progress = console.NewProgress()
|
||||
context.progress.Start()
|
||||
defer context.progress.Shutdown()
|
||||
|
||||
context.downloader = http.NewDownloader(utils.Config.DownloadConcurrency, context.progress)
|
||||
defer context.downloader.Shutdown()
|
||||
|
||||
context.database, err = database.OpenDB(filepath.Join(utils.Config.RootDir, "db"))
|
||||
if err != nil {
|
||||
return fmt.Errorf("can't open database: %s", err)
|
||||
}
|
||||
defer context.database.Close()
|
||||
|
||||
context.packagePool = files.NewPackagePool(utils.Config.RootDir)
|
||||
context.publishedStorage = files.NewPublishedStorage(utils.Config.RootDir)
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
)
|
||||
|
||||
func makeCmdDbCleanup() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyDbCleanup,
|
||||
UsageLine: "cleanup",
|
||||
Short: "remove unused entries in DB and unreferenced files in the pool",
|
||||
Long: `
|
||||
Database cleanup removes information about unreferenced packages and removes
|
||||
files in the package pool that aren't used by packages anymore
|
||||
|
||||
ex:
|
||||
$ aptly db cleanup
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-db-cleanup", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdDb() *commander.Command {
|
||||
return &commander.Command{
|
||||
UsageLine: "db",
|
||||
Short: "manage aptly's internal database and package pool",
|
||||
Subcommands: []*commander.Command{
|
||||
makeCmdDbCleanup(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-db", flag.ExitOnError),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,129 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// 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 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.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
|
||||
}
|
||||
+174
@@ -0,0 +1,174 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/gographviz"
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func graphvizEscape(s string) string {
|
||||
return fmt.Sprintf("\"%s\"", strings.Replace(s, "\"", "\\\"", 0))
|
||||
}
|
||||
|
||||
func aptlyGraph(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
graph := gographviz.NewGraph()
|
||||
graph.SetDir(true)
|
||||
graph.SetName("aptly")
|
||||
|
||||
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())),
|
||||
})
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("Loading snapshots...\n")
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
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" {
|
||||
for _, uuid := range snapshot.SourceIDs {
|
||||
graph.AddEdge(graphvizEscape(uuid), "", graphvizEscape(snapshot.UUID), "", true, nil)
|
||||
}
|
||||
} else if snapshot.SourceKind == "snapshot" {
|
||||
for _, uuid := range snapshot.SourceIDs {
|
||||
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, ", "))),
|
||||
})
|
||||
|
||||
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 makeCmdGraph() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyGraph,
|
||||
UsageLine: "graph",
|
||||
Short: "display graph of dependencies between aptly objects (requires graphviz)",
|
||||
Long: `
|
||||
Command graph displays relationship between mirrors, snapshots and published repositories using
|
||||
graphviz package to render graph as image.
|
||||
|
||||
ex:
|
||||
$ aptly graph
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-graph", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getVerifier(cmd *commander.Command) (utils.Verifier, error) {
|
||||
if utils.Config.GpgDisableVerify || cmd.Flag.Lookup("ignore-signatures").Value.Get().(bool) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
verifier := &utils.GpgVerifier{}
|
||||
for _, keyRing := range keyRings.keyRings {
|
||||
verifier.AddKeyring(keyRing)
|
||||
}
|
||||
|
||||
err := verifier.InitKeyring()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return verifier, nil
|
||||
}
|
||||
|
||||
type keyRingsFlag struct {
|
||||
keyRings []string
|
||||
}
|
||||
|
||||
func (k *keyRingsFlag) Set(value string) error {
|
||||
k.keyRings = append(k.keyRings, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (k *keyRingsFlag) Get() interface{} {
|
||||
return k.keyRings
|
||||
}
|
||||
|
||||
func (k *keyRingsFlag) String() string {
|
||||
return strings.Join(k.keyRings, ",")
|
||||
}
|
||||
|
||||
var keyRings = keyRingsFlag{}
|
||||
|
||||
func aptlyMirrorList(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 0 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
|
||||
if repoCollection.Len() > 0 {
|
||||
fmt.Printf("List of mirrors:\n")
|
||||
repos := make([]string, repoCollection.Len())
|
||||
i := 0
|
||||
repoCollection.ForEach(func(repo *debian.RemoteRepo) error {
|
||||
repos[i] = repo.String()
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
|
||||
sort.Strings(repos)
|
||||
for _, repo := range repos {
|
||||
fmt.Printf(" * %s\n", repo)
|
||||
}
|
||||
|
||||
fmt.Printf("\nTo get more information about mirror, run `aptly mirror show <name>`.\n")
|
||||
} else {
|
||||
fmt.Printf("No mirrors found, create one with `aptly mirror create ...`.\n")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 3 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
downloadSources := utils.Config.DownloadSourcePackages || cmd.Flag.Lookup("with-sources").Value.Get().(bool)
|
||||
|
||||
repo, err := debian.NewRemoteRepo(args[0], args[1], args[2], args[3:], context.architecturesList, downloadSources)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to create mirror: %s", err)
|
||||
}
|
||||
|
||||
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 fetch mirror: %s", err)
|
||||
}
|
||||
|
||||
repoCollection := debian.NewRemoteRepoCollection(context.database)
|
||||
|
||||
err = repoCollection.Add(repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to add mirror: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("\nMirror %s successfully added.\nYou can run 'aptly mirror update %s' to download repository contents.\n", repo, repo.Name)
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlyMirrorShow(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 show: %s", err)
|
||||
}
|
||||
|
||||
err = repoCollection.LoadComplete(repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to show: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Name: %s\n", repo.Name)
|
||||
fmt.Printf("Archive Root URL: %s\n", repo.ArchiveRoot)
|
||||
fmt.Printf("Distribution: %s\n", repo.Distribution)
|
||||
fmt.Printf("Components: %s\n", strings.Join(repo.Components, ", "))
|
||||
fmt.Printf("Architectures: %s\n", strings.Join(repo.Architectures, ", "))
|
||||
downloadSources := "no"
|
||||
if repo.DownloadSources {
|
||||
downloadSources = "yes"
|
||||
}
|
||||
fmt.Printf("Download Sources: %s\n", downloadSources)
|
||||
if repo.LastDownloadDate.IsZero() {
|
||||
fmt.Printf("Last update: never\n")
|
||||
} else {
|
||||
fmt.Printf("Last update: %s\n", repo.LastDownloadDate.Format("2006-01-02 15:04:05 MST"))
|
||||
fmt.Printf("Number of packages: %d\n", repo.NumPackages())
|
||||
}
|
||||
|
||||
fmt.Printf("\nInformation from release file:\n")
|
||||
for _, k := range utils.StrMapSortedKeys(repo.Meta) {
|
||||
fmt.Printf("%s: %s\n", k, repo.Meta[k])
|
||||
}
|
||||
|
||||
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
|
||||
if withPackages {
|
||||
if repo.LastDownloadDate.IsZero() {
|
||||
fmt.Printf("Unable to show package list, mirror hasn't been downloaded yet.\n")
|
||||
} else {
|
||||
ListPackagesRefList(repo.RefList())
|
||||
}
|
||||
}
|
||||
|
||||
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.progress, context.downloader, packageCollection, context.packagePool, 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
|
||||
}
|
||||
|
||||
func aptlyMirrorDrop(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 drop: %s", err)
|
||||
}
|
||||
|
||||
force := cmd.Flag.Lookup("force").Value.Get().(bool)
|
||||
if !force {
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshots := snapshotCollection.ByRemoteRepoSource(repo)
|
||||
|
||||
if len(snapshots) > 0 {
|
||||
fmt.Printf("Mirror `%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 mirror with snapshots, use -force to override")
|
||||
}
|
||||
}
|
||||
|
||||
err = repoCollection.Drop(repo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Mirror `%s` has been removed.\n", repo.Name)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func makeCmdMirrorCreate() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorCreate,
|
||||
UsageLine: "create <name> <archive url> <distribution> [<component1> ...]",
|
||||
Short: "create new mirror of Debian repository",
|
||||
Long: `
|
||||
Create records information about new mirror and fetches Release file (it doesn't download packages).
|
||||
|
||||
ex:
|
||||
$ aptly mirror create wheezy-main http://mirror.yandex.ru/debian/ wheezy main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-create", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
|
||||
cmd.Flag.Bool("with-sources", false, "download source packages")
|
||||
cmd.Flag.Var(&keyRings, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirrorList() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorList,
|
||||
UsageLine: "list",
|
||||
Short: "list mirrors of remote repositories",
|
||||
Long: `
|
||||
List shows full list of remote repositories.
|
||||
|
||||
ex:
|
||||
$ aptly mirror list
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-list", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.Bool("v", false, "enable verbose output")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirrorShow() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorShow,
|
||||
UsageLine: "show <name>",
|
||||
Short: "show details about remote repository mirror",
|
||||
Long: `
|
||||
Show shows full information about mirror.
|
||||
|
||||
ex:
|
||||
$ aptly mirror show wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-show", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("with-packages", false, "show list of packages")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirrorUpdate() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorUpdate,
|
||||
UsageLine: "update <name>",
|
||||
Short: "update packages from remote mirror",
|
||||
Long: `
|
||||
Update downloads list of packages and package files.
|
||||
|
||||
ex:
|
||||
$ aptly mirror update wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-update", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("ignore-checksums", false, "ignore checksum mismatches while downloading package files and metadata")
|
||||
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
|
||||
cmd.Flag.Var(&keyRings, "keyring", "gpg keyring to use when verifying Release file (could be specified multiple times)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirrorDrop() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyMirrorDrop,
|
||||
UsageLine: "drop <name>",
|
||||
Short: "delete remote repository mirror",
|
||||
Long: `
|
||||
Drop deletes information about remote repository mirror. Package data is not deleted
|
||||
(it could be still used by other mirrors or snapshots).
|
||||
|
||||
ex:
|
||||
$ aptly mirror drop wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-mirror-drop", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("force", false, "force mirror deletion even if used by snapshots")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdMirror() *commander.Command {
|
||||
return &commander.Command{
|
||||
UsageLine: "mirror",
|
||||
Short: "manage mirrors of remote repositories",
|
||||
Subcommands: []*commander.Command{
|
||||
makeCmdMirrorCreate(),
|
||||
makeCmdMirrorList(),
|
||||
makeCmdMirrorShow(),
|
||||
makeCmdMirrorDrop(),
|
||||
makeCmdMirrorUpdate(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-mirror", flag.ExitOnError),
|
||||
}
|
||||
}
|
||||
+265
@@ -0,0 +1,265 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func getSigner(cmd *commander.Command) (utils.Signer, error) {
|
||||
if cmd.Flag.Lookup("skip-signing").Value.Get().(bool) || utils.Config.GpgDisableSign {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
signer := &utils.GpgSigner{}
|
||||
signer.SetKey(cmd.Flag.Lookup("gpg-key").Value.String())
|
||||
signer.SetKeyRing(cmd.Flag.Lookup("keyring").Value.String(), cmd.Flag.Lookup("secret-keyring").Value.String())
|
||||
|
||||
err := signer.Init()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return signer, nil
|
||||
|
||||
}
|
||||
|
||||
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.packagePool, context.publishedStorage, 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.publishedStorage.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
|
||||
}
|
||||
|
||||
func aptlyPublishList(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 0 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
if publishedCollecton.Len() == 0 {
|
||||
fmt.Printf("No snapshots have been published. Publish a snapshot by running `aptly publish snapshot ...`.\n")
|
||||
return err
|
||||
}
|
||||
|
||||
published := make([]string, 0, publishedCollecton.Len())
|
||||
|
||||
err = publishedCollecton.ForEach(func(repo *debian.PublishedRepo) error {
|
||||
err := publishedCollecton.LoadComplete(repo, snapshotCollection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
published = append(published, repo.String())
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load list of repos: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(published)
|
||||
|
||||
fmt.Printf("Published repositories:\n")
|
||||
|
||||
for _, description := range published {
|
||||
fmt.Printf(" * %s\n", description)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func aptlyPublishDrop(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 1 || len(args) > 2 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
distribution := args[0]
|
||||
prefix := "."
|
||||
|
||||
if len(args) == 2 {
|
||||
prefix = args[1]
|
||||
}
|
||||
|
||||
publishedCollecton := debian.NewPublishedRepoCollection(context.database)
|
||||
|
||||
err = publishedCollecton.Remove(context.publishedStorage, prefix, distribution)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to remove: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("\nPublished repositroy has been removed successfully.\n")
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func makeCmdPublishSnapshot() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyPublishSnapshot,
|
||||
UsageLine: "snapshot <name> [<prefix>]",
|
||||
Short: "makes Debian repository out of snapshot",
|
||||
Long: `
|
||||
Command publish oublishes snapshot as Debian repository ready to be used by apt tools.
|
||||
|
||||
ex.
|
||||
$ aptly publish snapshot wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-publish-snapshot", flag.ExitOnError),
|
||||
}
|
||||
cmd.Flag.String("distribution", "", "distribution name to publish")
|
||||
cmd.Flag.String("component", "", "component name to publish")
|
||||
cmd.Flag.String("gpg-key", "", "GPG key ID to use when signing the release")
|
||||
cmd.Flag.String("keyring", "", "GPG keyring to use (instead of default)")
|
||||
cmd.Flag.String("secret-keyring", "", "GPG secret keyring to use (instead of default)")
|
||||
cmd.Flag.Bool("skip-signing", false, "don't sign Release files with GPG")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdPublishDrop() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyPublishDrop,
|
||||
UsageLine: "drop <distribution> [<prefix>]",
|
||||
Short: "removes files of published repository",
|
||||
Long: `
|
||||
Command removes whatever has been published under specified prefix and distribution name.
|
||||
|
||||
ex.
|
||||
$ aptly publish drop wheezy
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-publish-drop", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdPublishList() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyPublishList,
|
||||
UsageLine: "list",
|
||||
Short: "displays list of published repositories",
|
||||
Long: `
|
||||
Display command displays list of currently published snapshots with information about published root.
|
||||
|
||||
ex.
|
||||
$ aptly publish list
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-publish-list", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdPublish() *commander.Command {
|
||||
return &commander.Command{
|
||||
UsageLine: "publish",
|
||||
Short: "manage published repositories",
|
||||
Subcommands: []*commander.Command{
|
||||
makeCmdPublishSnapshot(),
|
||||
makeCmdPublishList(),
|
||||
makeCmdPublishDrop(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-publish", flag.ExitOnError),
|
||||
}
|
||||
}
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/smira/aptly/utils"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func aptlyServe(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
|
||||
publishedCollection := debian.NewPublishedRepoCollection(context.database)
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
if publishedCollection.Len() == 0 {
|
||||
fmt.Printf("No published repositories, unable to serve.\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
listen := cmd.Flag.Lookup("listen").Value.String()
|
||||
|
||||
listenHost, listenPort, err := net.SplitHostPort(listen)
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("wrong -listen specification: %s", err)
|
||||
}
|
||||
|
||||
if listenHost == "" {
|
||||
listenHost, err = os.Hostname()
|
||||
if err != nil {
|
||||
listenHost = "localhost"
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf("Serving published repositories, recommended apt sources list:\n\n")
|
||||
|
||||
sources := make(sort.StringSlice, 0, publishedCollection.Len())
|
||||
published := make(map[string]*debian.PublishedRepo, publishedCollection.Len())
|
||||
|
||||
err = publishedCollection.ForEach(func(repo *debian.PublishedRepo) error {
|
||||
err := publishedCollection.LoadComplete(repo, snapshotCollection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
sources = append(sources, repo.String())
|
||||
published[repo.String()] = repo
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to serve: %s", err)
|
||||
}
|
||||
|
||||
sort.Strings(sources)
|
||||
|
||||
for _, source := range sources {
|
||||
repo := published[source]
|
||||
|
||||
prefix := repo.Prefix
|
||||
if prefix == "." {
|
||||
prefix = ""
|
||||
} else {
|
||||
prefix += "/"
|
||||
}
|
||||
|
||||
fmt.Printf("# %s\ndeb http://%s:%s/%s %s %s\n",
|
||||
repo, listenHost, listenPort, prefix, repo.Distribution, repo.Component)
|
||||
|
||||
if utils.StrSliceHasItem(repo.Architectures, "source") {
|
||||
fmt.Printf("deb-src http://%s:%s/%s %s %s\n",
|
||||
listenHost, listenPort, prefix, repo.Distribution, repo.Component)
|
||||
}
|
||||
}
|
||||
|
||||
context.database.Close()
|
||||
|
||||
fmt.Printf("\nStarting web server at: %s (press Ctrl+C to quit)...\n", listen)
|
||||
|
||||
err = http.ListenAndServe(listen, http.FileServer(http.Dir(context.publishedStorage.PublicPath())))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to serve: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeCmdServe() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlyServe,
|
||||
UsageLine: "serve",
|
||||
Short: "start embedded HTTP server to serve published repositories",
|
||||
Long: `
|
||||
Command serve starts embedded HTTP server (not suitable for real production usage) to serve
|
||||
contents of public/ subdirectory of aptly's root that contains published repositories.
|
||||
|
||||
ex:
|
||||
$ aptly serve -listen=:8080
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-serve", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.String("listen", ":8080", "host:port for HTTP listening")
|
||||
|
||||
return cmd
|
||||
}
|
||||
+732
@@ -0,0 +1,732 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/debian"
|
||||
"github.com/wsxiaoys/terminal/color"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
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) == 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
|
||||
}
|
||||
|
||||
func aptlySnapshotList(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 0 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
if snapshotCollection.Len() > 0 {
|
||||
fmt.Printf("List of snapshots:\n")
|
||||
|
||||
snapshots := make([]string, snapshotCollection.Len())
|
||||
|
||||
i := 0
|
||||
snapshotCollection.ForEach(func(snapshot *debian.Snapshot) error {
|
||||
snapshots[i] = snapshot.String()
|
||||
i++
|
||||
return nil
|
||||
})
|
||||
|
||||
sort.Strings(snapshots)
|
||||
for _, snapshot := range snapshots {
|
||||
fmt.Printf(" * %s\n", snapshot)
|
||||
}
|
||||
|
||||
fmt.Printf("\nTo get more information about snapshot, run `aptly snapshot show <name>`.\n")
|
||||
} else {
|
||||
fmt.Printf("\nNo snapshots found, create one with `aptly snapshot create...`.\n")
|
||||
}
|
||||
return err
|
||||
|
||||
}
|
||||
|
||||
func aptlySnapshotShow(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 1 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshot, err := snapshotCollection.ByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to show: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(snapshot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to show: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Name: %s\n", snapshot.Name)
|
||||
fmt.Printf("Created At: %s\n", snapshot.CreatedAt.Format("2006-01-02 15:04:05 MST"))
|
||||
fmt.Printf("Description: %s\n", snapshot.Description)
|
||||
fmt.Printf("Number of packages: %d\n", snapshot.NumPackages())
|
||||
|
||||
withPackages := cmd.Flag.Lookup("with-packages").Value.Get().(bool)
|
||||
if withPackages {
|
||||
ListPackagesRefList(snapshot.RefList())
|
||||
}
|
||||
|
||||
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([]string, 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 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)
|
||||
}
|
||||
|
||||
sort.Strings(architecturesList)
|
||||
|
||||
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: pkg.Architecture, Pkg: pkg.Name}); p != nil; {
|
||||
packageList.Remove(p)
|
||||
color.Printf("@r[-]@| %s removed", p)
|
||||
fmt.Printf("\n")
|
||||
p = packageList.Search(debian.Dependency{Architecture: pkg.Architecture, 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 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 aptlySnapshotMerge(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) < 2 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
|
||||
sources := make([]*debian.Snapshot, len(args)-1)
|
||||
|
||||
for i := 0; i < len(args)-1; i++ {
|
||||
sources[i], err = snapshotCollection.ByName(args[i+1])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot: %s", err)
|
||||
}
|
||||
|
||||
err = snapshotCollection.LoadComplete(sources[i])
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load snapshot: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
result := sources[0].RefList()
|
||||
|
||||
for i := 1; i < len(sources); i++ {
|
||||
result = result.Merge(sources[i].RefList(), true)
|
||||
}
|
||||
|
||||
sourceDescription := make([]string, len(sources))
|
||||
for i, s := range sources {
|
||||
sourceDescription[i] = fmt.Sprintf("'%s'", s.Name)
|
||||
}
|
||||
|
||||
// Create <destination> snapshot
|
||||
destination := debian.NewSnapshotFromRefList(args[0], sources, result,
|
||||
fmt.Sprintf("Merged from sources: %s", strings.Join(sourceDescription, ", ")))
|
||||
|
||||
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 aptlySnapshotDrop(cmd *commander.Command, args []string) error {
|
||||
var err error
|
||||
if len(args) != 1 {
|
||||
cmd.Usage()
|
||||
return err
|
||||
}
|
||||
|
||||
name := args[0]
|
||||
|
||||
snapshotCollection := debian.NewSnapshotCollection(context.database)
|
||||
snapshot, err := snapshotCollection.ByName(name)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
publishedRepoCollection := debian.NewPublishedRepoCollection(context.database)
|
||||
published := publishedRepoCollection.BySnapshot(snapshot)
|
||||
|
||||
if len(published) > 0 {
|
||||
fmt.Printf("Snapshot `%s` is published currently:\n", snapshot.Name)
|
||||
for _, repo := range published {
|
||||
err = publishedRepoCollection.LoadComplete(repo, snapshotCollection)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to load published: %s", err)
|
||||
}
|
||||
fmt.Printf(" * %s\n", repo)
|
||||
}
|
||||
|
||||
return fmt.Errorf("unable to drop: snapshot is published")
|
||||
}
|
||||
|
||||
force := cmd.Flag.Lookup("force").Value.Get().(bool)
|
||||
if !force {
|
||||
snapshots := snapshotCollection.BySnapshotSource(snapshot)
|
||||
if len(snapshots) > 0 {
|
||||
fmt.Printf("Snapshot `%s` was used as a source in following snapshots:\n", snapshot.Name)
|
||||
for _, snap := range snapshots {
|
||||
fmt.Printf(" * %s\n", snap)
|
||||
}
|
||||
|
||||
return fmt.Errorf("won't delete snapshot that was used as source for other snapshots, use -force to override")
|
||||
}
|
||||
}
|
||||
|
||||
err = snapshotCollection.Drop(snapshot)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to drop: %s", err)
|
||||
}
|
||||
|
||||
fmt.Printf("Snapshot `%s` has been dropped.\n", snapshot.Name)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func makeCmdSnapshotCreate() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotCreate,
|
||||
UsageLine: "create <name> from mirror <mirror-name> | create <name> empty",
|
||||
Short: "creates immutable snapshot of mirror contents",
|
||||
Long: `
|
||||
Command create .. from mirror makes persistent immutable snapshot of remote repository mirror. Snapshot could be
|
||||
published or further modified using merge, pull and other aptly features.
|
||||
|
||||
Command create .. empty creates empty snapshot that could be used as a basis for snapshot pull operations, for example.
|
||||
As snapshots are immutable, creating one empty snapshot should be enough.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot create wheezy-main-today from mirror wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-create", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
|
||||
}
|
||||
|
||||
func makeCmdSnapshotList() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotList,
|
||||
UsageLine: "list",
|
||||
Short: "lists snapshots",
|
||||
Long: `
|
||||
Command list shows full list of snapshots created.
|
||||
|
||||
ex:
|
||||
$ aptly snapshot list
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-list", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotShow() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotShow,
|
||||
UsageLine: "show <name>",
|
||||
Short: "shows details about snapshot",
|
||||
Long: `
|
||||
Command show displays full information about snapshot.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot show wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-show", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("with-packages", false, "show list of packages")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotVerify() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotVerify,
|
||||
UsageLine: "verify <name> [<source> ...]",
|
||||
Short: "verifies that dependencies are satisfied in snapshot",
|
||||
Long: `
|
||||
Verify does depenency resolution in snapshot, possibly using additional snapshots as dependency sources.
|
||||
All unsatisfied dependencies are returned.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot verify wheezy-main wheezy-contrib wheezy-non-free
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-verify", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotPull() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotPull,
|
||||
UsageLine: "pull <name> <source> <destination> <package-name> ...",
|
||||
Short: "performs partial upgrades (pulls new packages) from another snapshot",
|
||||
Long: `
|
||||
Command pull pulls new packages along with its dependencies in <name> snapshot
|
||||
from <source> snapshot. Also can upgrade package version from one snapshot into
|
||||
another, once again along with dependencies. New snapshot <destination> is created as result of this
|
||||
process. Packages could be specified simply as 'package-name' or as dependency 'package-name (>= version)'.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot pull wheezy-main wheezy-backports wheezy-new-xorg xorg-server-server
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-pull", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("dry-run", false, "don't create destination snapshot, just show what would be pulled")
|
||||
cmd.Flag.Bool("no-deps", false, "don't process dependencies, just pull listed packages")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotDiff() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotDiff,
|
||||
UsageLine: "diff <name-a> <name-b>",
|
||||
Short: "calculates difference in packages between two snapshots",
|
||||
Long: `
|
||||
Command diff shows list of missing and new packages, difference in package versions between two snapshots.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot diff -only-matching wheezy-main wheezy-backports
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-diff", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("only-matching", false, "display diff only for matching packages (don't display missing packages)")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotMerge() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotMerge,
|
||||
UsageLine: "merge <destination> <source> [<source>...]",
|
||||
Short: "merges snapshots into one, replacing matching packages",
|
||||
Long: `
|
||||
Merge merges several snapshots into one. Merge happens from left to right. Packages with the same
|
||||
name-architecture pair are replaced during merge (package from latest snapshot on the list wins).
|
||||
If run with only one source snapshot, merge copies source into destination.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot merge wheezy-w-backports wheezy-main wheezy-backports
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-merge", flag.ExitOnError),
|
||||
}
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshotDrop() *commander.Command {
|
||||
cmd := &commander.Command{
|
||||
Run: aptlySnapshotDrop,
|
||||
UsageLine: "drop <name>",
|
||||
Short: "delete snapshot",
|
||||
Long: `
|
||||
Drop removes information about snapshot. If snapshot is published,
|
||||
it can't be dropped.
|
||||
|
||||
ex.
|
||||
$ aptly snapshot drop wheezy-main
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot-drop", flag.ExitOnError),
|
||||
}
|
||||
|
||||
cmd.Flag.Bool("force", false, "remove snapshot even if it was used as source for other snapshots")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func makeCmdSnapshot() *commander.Command {
|
||||
return &commander.Command{
|
||||
UsageLine: "snapshot",
|
||||
Short: "manage snapshots of repositories",
|
||||
Subcommands: []*commander.Command{
|
||||
makeCmdSnapshotCreate(),
|
||||
makeCmdSnapshotList(),
|
||||
makeCmdSnapshotShow(),
|
||||
makeCmdSnapshotVerify(),
|
||||
makeCmdSnapshotPull(),
|
||||
makeCmdSnapshotDiff(),
|
||||
makeCmdSnapshotMerge(),
|
||||
makeCmdSnapshotDrop(),
|
||||
},
|
||||
Flag: *flag.NewFlagSet("aptly-snapshot", flag.ExitOnError),
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/gonuts/commander"
|
||||
"github.com/gonuts/flag"
|
||||
"github.com/smira/aptly/aptly"
|
||||
)
|
||||
|
||||
func aptlyVersion(cmd *commander.Command, args []string) error {
|
||||
fmt.Printf("aptly version: %s\n", aptly.Version)
|
||||
return nil
|
||||
}
|
||||
|
||||
func makeCmdVersion() *commander.Command {
|
||||
return &commander.Command{
|
||||
Run: aptlyVersion,
|
||||
UsageLine: "version",
|
||||
Short: "display version",
|
||||
Long: `
|
||||
Shows aptly version.
|
||||
|
||||
ex:
|
||||
$ aptly version
|
||||
`,
|
||||
Flag: *flag.NewFlagSet("aptly-version", flag.ExitOnError),
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user