Skip to content

Commit e5b8315

Browse files
authored
Merge pull request #1411 from schoenherrg/feature/filter-using-file
Feature: Support Reading Filter Expressions from a File
2 parents fea7acb + c6bb5f7 commit e5b8315

19 files changed

Lines changed: 229 additions & 17 deletions

cmd/mirror_create.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ func aptlyMirrorCreate(cmd *commander.Command, args []string) error {
4646
return fmt.Errorf("unable to create mirror: %s", err)
4747
}
4848

49-
repo.Filter = context.Flags().Lookup("filter").Value.String()
49+
repo.Filter = context.Flags().Lookup("filter").Value.String() // allows file/stdin with @
5050
repo.FilterWithDeps = context.Flags().Lookup("filter-with-deps").Value.Get().(bool)
5151
repo.SkipComponentCheck = context.Flags().Lookup("force-components").Value.Get().(bool)
5252
repo.SkipArchitectureCheck = context.Flags().Lookup("force-architectures").Value.Get().(bool)
@@ -103,7 +103,7 @@ Example:
103103
cmd.Flag.Bool("with-installer", false, "download additional not packaged installer files")
104104
cmd.Flag.Bool("with-sources", false, "download source packages in addition to binary packages")
105105
cmd.Flag.Bool("with-udebs", false, "download .udeb packages (Debian installer support)")
106-
cmd.Flag.String("filter", "", "filter packages in mirror")
106+
AddStringOrFileFlag(&cmd.Flag, "filter", "", "filter packages in mirror, use '@file' to read filter from file or '@-' for stdin")
107107
cmd.Flag.Bool("filter-with-deps", false, "when filtering, include dependencies of matching packages as well")
108108
cmd.Flag.Bool("force-components", false, "(only with component list) skip check that requested components are listed in Release file")
109109
cmd.Flag.Bool("force-architectures", false, "(only with architecture list) skip check that requested architectures are listed in Release file")

cmd/mirror_edit.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ func aptlyMirrorEdit(cmd *commander.Command, args []string) error {
3232
context.Flags().Visit(func(flag *flag.Flag) {
3333
switch flag.Name {
3434
case "filter":
35-
repo.Filter = flag.Value.String()
35+
repo.Filter = flag.Value.String() // allows file/stdin with @
3636
case "filter-with-deps":
3737
repo.FilterWithDeps = flag.Value.Get().(bool)
3838
case "with-installer":
@@ -104,7 +104,7 @@ Example:
104104
}
105105

106106
cmd.Flag.String("archive-url", "", "archive url is the root of archive")
107-
cmd.Flag.String("filter", "", "filter packages in mirror")
107+
AddStringOrFileFlag(&cmd.Flag, "filter", "", "filter packages in mirror, use '@file' to read filter from file or '@-' for stdin")
108108
cmd.Flag.Bool("filter-with-deps", false, "when filtering, include dependencies of matching packages as well")
109109
cmd.Flag.Bool("ignore-signatures", false, "disable verification of Release file signatures")
110110
cmd.Flag.Bool("with-installer", false, "download additional not packaged installer files")

cmd/package_search.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ func aptlyPackageSearch(cmd *commander.Command, args []string) error {
2121
}
2222

2323
if len(args) == 1 {
24-
q, err = query.Parse(args[0])
24+
value, err := GetStringOrFileContent(args[0])
25+
if err != nil {
26+
return fmt.Errorf("unable to read package query from file %s: %w", args[0], err)
27+
}
28+
q, err = query.Parse(value)
2529
if err != nil {
2630
return fmt.Errorf("unable to search: %s", err)
2731
}
@@ -49,6 +53,7 @@ func makeCmdPackageSearch() *commander.Command {
4953
Long: `
5054
Command search displays list of packages in whole DB that match package query.
5155
56+
Use '@file' to read query from file or '@-' for stdin.
5257
If query is not specified, all the packages are displayed.
5358
5459
Example:

cmd/package_show.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,11 @@ func aptlyPackageShow(cmd *commander.Command, args []string) error {
6666
return commander.ErrCommandError
6767
}
6868

69-
q, err := query.Parse(args[0])
69+
value, err := GetStringOrFileContent(args[0])
70+
if err != nil {
71+
return fmt.Errorf("unable to read package query from file %s: %w", args[0], err)
72+
}
73+
q, err := query.Parse(value)
7074
if err != nil {
7175
return fmt.Errorf("unable to show: %s", err)
7276
}
@@ -130,6 +134,8 @@ matching query. Information from Debian control file is displayed.
130134
Optionally information about package files and
131135
inclusion into mirrors/snapshots/local repos is shown.
132136
137+
Use '@file' to read query from file or '@-' for stdin.
138+
133139
Example:
134140
135141
$ aptly package show 'nginx-light_1.2.1-2.2+wheezy2_i386'

cmd/repo_move.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,11 @@ func aptlyRepoMoveCopyImport(cmd *commander.Command, args []string) error {
110110

111111
queries := make([]deb.PackageQuery, len(args)-2)
112112
for i := 0; i < len(args)-2; i++ {
113-
queries[i], err = query.Parse(args[i+2])
113+
value, err := GetStringOrFileContent(args[i+2])
114+
if err != nil {
115+
return fmt.Errorf("unable to read package query from file %s: %w", args[i+2], err)
116+
}
117+
queries[i], err = query.Parse(value)
114118
if err != nil {
115119
return fmt.Errorf("unable to %s: %s", command, err)
116120
}
@@ -186,6 +190,8 @@ func makeCmdRepoMove() *commander.Command {
186190
Command move moves packages matching <package-query> from local repo
187191
<src-name> to local repo <dst-name>.
188192
193+
Use '@file' to read package queries from file or '@-' for stdin.
194+
189195
Example:
190196
191197
$ aptly repo move testing stable 'myapp (=0.1.12)'

cmd/repo_remove.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,11 @@ func aptlyRepoRemove(cmd *commander.Command, args []string) error {
3838

3939
queries := make([]deb.PackageQuery, len(args)-1)
4040
for i := 0; i < len(args)-1; i++ {
41-
queries[i], err = query.Parse(args[i+1])
41+
value, err := GetStringOrFileContent(args[i+1])
42+
if err != nil {
43+
return fmt.Errorf("unable to read package query from file %s: %w", args[i+1], err)
44+
}
45+
queries[i], err = query.Parse(value)
4246
if err != nil {
4347
return fmt.Errorf("unable to remove: %s", err)
4448
}
@@ -81,6 +85,8 @@ Commands removes packages matching <package-query> from local repository
8185
snapshots, they can be removed completely (including files) by running
8286
'aptly db cleanup'.
8387
88+
Use '@file' to read package queries from file or '@-' for stdin.
89+
8490
Example:
8591
8692
$ aptly repo remove testing 'myapp (=0.1.12)'

cmd/snapshot_filter.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,11 @@ func aptlySnapshotFilter(cmd *commander.Command, args []string) error {
6060
// Initial queries out of arguments
6161
queries := make([]deb.PackageQuery, len(args)-2)
6262
for i, arg := range args[2:] {
63-
queries[i], err = query.Parse(arg)
63+
value, err := GetStringOrFileContent(arg)
64+
if err != nil {
65+
return fmt.Errorf("unable to read package query from file %s: %w", arg, err)
66+
}
67+
queries[i], err = query.Parse(value)
6468
if err != nil {
6569
return fmt.Errorf("unable to parse query: %s", err)
6670
}
@@ -103,6 +107,8 @@ Command filter does filtering in snapshot <source>, producing another
103107
snapshot <destination>. Packages could be specified simply
104108
as 'package-name' or as package queries.
105109
110+
Use '@file' syntax to read package queries from file and '@-' to read from stdin.
111+
106112
Example:
107113
108114
$ aptly snapshot filter wheezy-main wheezy-required 'Priority (required)'

cmd/snapshot_pull.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,11 @@ func aptlySnapshotPull(cmd *commander.Command, args []string) error {
8888
// Initial queries out of arguments
8989
queries := make([]deb.PackageQuery, len(args)-3)
9090
for i, arg := range args[3:] {
91-
queries[i], err = query.Parse(arg)
91+
value, err := GetStringOrFileContent(arg)
92+
if err != nil {
93+
return fmt.Errorf("unable to read package query from file %s: %w", arg, err)
94+
}
95+
queries[i], err = query.Parse(value)
9296
if err != nil {
9397
return fmt.Errorf("unable to parse query: %s", err)
9498
}
@@ -167,6 +171,8 @@ versions from <source> following dependencies. New snapshot <destination>
167171
is created as a result of this process. Packages could be specified simply
168172
as 'package-name' or as package queries.
169173
174+
Use '@file' syntax to read package queries from file and '@-' to read from stdin.
175+
170176
Example:
171177
172178
$ aptly snapshot pull wheezy-main wheezy-backports wheezy-new-xorg xorg-server-server

cmd/snapshot_search.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,11 @@ func aptlySnapshotMirrorRepoSearch(cmd *commander.Command, args []string) error
7878
list.PrepareIndex()
7979

8080
if len(args) == 2 {
81-
q, err = query.Parse(args[1])
81+
value, err := GetStringOrFileContent(args[1])
82+
if err != nil {
83+
return fmt.Errorf("unable to read package query from file %s: %w", args[1], err)
84+
}
85+
q, err = query.Parse(value)
8286
if err != nil {
8387
return fmt.Errorf("unable to search: %s", err)
8488
}
@@ -134,6 +138,8 @@ Command search displays list of packages in snapshot that match package query
134138
135139
If query is not specified, all the packages are displayed.
136140
141+
Use '@file' syntax to read package query from file and '@-' to read from stdin.
142+
137143
Example:
138144
139145
$ aptly snapshot search wheezy-main '$Architecture (i386), Name (% *-dev)'

cmd/string_or_file_flag.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package cmd
2+
3+
import (
4+
"io"
5+
"os"
6+
"strings"
7+
8+
"github.com/smira/flag"
9+
)
10+
11+
// StringOrFileFlag is a custom flag type that can handle both string input and file input.
12+
// If the input starts with '@', it is treated as a filename and the contents are read from the file.
13+
// If the input is '@-', the contents are read from stdin.
14+
type StringOrFileFlag struct {
15+
value string
16+
}
17+
18+
func (s *StringOrFileFlag) String() string {
19+
return s.value
20+
}
21+
22+
func (s *StringOrFileFlag) Set(value string) error {
23+
var err error
24+
s.value, err = GetStringOrFileContent(value)
25+
return err
26+
}
27+
28+
func (s *StringOrFileFlag) Get() any {
29+
return s.value
30+
}
31+
32+
func AddStringOrFileFlag(flagSet *flag.FlagSet, name string, value string, usage string) *StringOrFileFlag {
33+
result := &StringOrFileFlag{value: value}
34+
flagSet.Var(result, name, usage)
35+
return result
36+
}
37+
38+
func GetStringOrFileContent(value string) (string, error) {
39+
if !strings.HasPrefix(value, "@") {
40+
return value, nil
41+
}
42+
43+
filename := strings.TrimPrefix(value, "@")
44+
var data []byte
45+
var err error
46+
if filename == "-" { // Read from stdin
47+
data, err = io.ReadAll(os.Stdin)
48+
} else {
49+
data, err = os.ReadFile(filename)
50+
}
51+
if err != nil {
52+
return "", err
53+
}
54+
return string(data), nil
55+
}

0 commit comments

Comments
 (0)