1package cmd
2
3import (
4	"fmt"
5	"sort"
6	"strings"
7
8	"github.com/aptly-dev/aptly/deb"
9	"github.com/aptly-dev/aptly/query"
10	"github.com/smira/commander"
11	"github.com/smira/flag"
12)
13
14func aptlySnapshotFilter(cmd *commander.Command, args []string) error {
15	var err error
16	if len(args) < 3 {
17		cmd.Usage()
18		return commander.ErrCommandError
19	}
20
21	withDeps := context.Flags().Lookup("with-deps").Value.Get().(bool)
22
23	// Load <source> snapshot
24	source, err := context.CollectionFactory().SnapshotCollection().ByName(args[0])
25	if err != nil {
26		return fmt.Errorf("unable to filter: %s", err)
27	}
28
29	err = context.CollectionFactory().SnapshotCollection().LoadComplete(source)
30	if err != nil {
31		return fmt.Errorf("unable to filter: %s", err)
32	}
33
34	// Convert snapshot to package list
35	context.Progress().Printf("Loading packages (%d)...\n", source.RefList().Len())
36	packageList, err := deb.NewPackageListFromRefList(source.RefList(), context.CollectionFactory().PackageCollection(), context.Progress())
37	if err != nil {
38		return fmt.Errorf("unable to load packages: %s", err)
39	}
40
41	context.Progress().Printf("Building indexes...\n")
42	packageList.PrepareIndex()
43
44	// Calculate architectures
45	var architecturesList []string
46
47	if len(context.ArchitecturesList()) > 0 {
48		architecturesList = context.ArchitecturesList()
49	} else {
50		architecturesList = packageList.Architectures(false)
51	}
52
53	sort.Strings(architecturesList)
54
55	if len(architecturesList) == 0 && withDeps {
56		return fmt.Errorf("unable to determine list of architectures, please specify explicitly")
57	}
58
59	// Initial queries out of arguments
60	queries := make([]deb.PackageQuery, len(args)-2)
61	for i, arg := range args[2:] {
62		queries[i], err = query.Parse(arg)
63		if err != nil {
64			return fmt.Errorf("unable to parse query: %s", err)
65		}
66	}
67
68	// Filter with dependencies as requested
69	result, err := packageList.FilterWithProgress(queries, withDeps, nil, context.DependencyOptions(), architecturesList, context.Progress())
70	if err != nil {
71		return fmt.Errorf("unable to filter: %s", err)
72	}
73
74	// Create <destination> snapshot
75	destination := deb.NewSnapshotFromPackageList(args[1], []*deb.Snapshot{source}, result,
76		fmt.Sprintf("Filtered '%s', query was: '%s'", source.Name, strings.Join(args[2:], " ")))
77
78	err = context.CollectionFactory().SnapshotCollection().Add(destination)
79	if err != nil {
80		return fmt.Errorf("unable to create snapshot: %s", err)
81	}
82
83	context.Progress().Printf("\nSnapshot %s successfully filtered.\nYou can run 'aptly publish snapshot %s' to publish snapshot as Debian repository.\n", destination.Name, destination.Name)
84
85	return err
86}
87
88func makeCmdSnapshotFilter() *commander.Command {
89	cmd := &commander.Command{
90		Run:       aptlySnapshotFilter,
91		UsageLine: "filter <source> <destination> <package-query> ...",
92		Short:     "filter packages in snapshot producing another snapshot",
93		Long: `
94Command filter does filtering in snapshot <source>, producing another
95snapshot <destination>. Packages could be specified simply
96as 'package-name' or as package queries.
97
98Example:
99
100    $ aptly snapshot filter wheezy-main wheezy-required 'Priorioty (required)'
101`,
102		Flag: *flag.NewFlagSet("aptly-snapshot-filter", flag.ExitOnError),
103	}
104
105	cmd.Flag.Bool("with-deps", false, "include dependent packages as well")
106
107	return cmd
108}
109