autoproj 2.3.1 → 2.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -3
- data/.vscode/launch.json +25 -0
- data/Gemfile +10 -3
- data/autoproj.gemspec +1 -1
- data/bin/autoproj_bootstrap +5 -3
- data/bin/autoproj_bootstrap.in +5 -3
- data/bin/autoproj_install +2 -2
- data/bin/autoproj_install.in +2 -2
- data/lib/autoproj.rb +3 -1
- data/lib/autoproj/build_option.rb +4 -4
- data/lib/autoproj/cli.rb +10 -1
- data/lib/autoproj/cli/base.rb +14 -4
- data/lib/autoproj/cli/bootstrap.rb +2 -2
- data/lib/autoproj/cli/cache.rb +4 -10
- data/lib/autoproj/cli/clean.rb +1 -1
- data/lib/autoproj/cli/commit.rb +1 -1
- data/lib/autoproj/cli/exec.rb +11 -5
- data/lib/autoproj/cli/locate.rb +12 -12
- data/lib/autoproj/cli/log.rb +1 -2
- data/lib/autoproj/cli/main.rb +23 -4
- data/lib/autoproj/cli/main_plugin.rb +2 -2
- data/lib/autoproj/cli/manifest.rb +6 -3
- data/lib/autoproj/cli/query.rb +71 -10
- data/lib/autoproj/cli/reset.rb +4 -4
- data/lib/autoproj/cli/switch_config.rb +2 -2
- data/lib/autoproj/cli/tag.rb +2 -2
- data/lib/autoproj/cli/update.rb +2 -0
- data/lib/autoproj/cli/which.rb +17 -0
- data/lib/autoproj/exceptions.rb +9 -4
- data/lib/autoproj/git_server_configuration.rb +80 -53
- data/lib/autoproj/manifest.rb +1 -1
- data/lib/autoproj/ops/cache.rb +21 -10
- data/lib/autoproj/ops/main_config_switcher.rb +6 -9
- data/lib/autoproj/os_package_query.rb +99 -0
- data/lib/autoproj/package_managers/bundler_manager.rb +8 -1
- data/lib/autoproj/package_managers/yum_manager.rb +2 -2
- data/lib/autoproj/package_managers/zypper_manager.rb +2 -2
- data/lib/autoproj/query_base.rb +128 -0
- data/lib/autoproj/reporter.rb +12 -0
- data/lib/autoproj/{query.rb → source_package_query.rb} +15 -81
- data/lib/autoproj/version.rb +1 -1
- data/lib/autoproj/workspace.rb +38 -0
- metadata +8 -5
- data/lib/autoproj/cli/snapshot.rb +0 -66
data/lib/autoproj/manifest.rb
CHANGED
@@ -240,7 +240,7 @@ def validate_package_name_argument(package, require_existing: true)
|
|
240
240
|
#
|
241
241
|
# Validate that the given package object is defined in self
|
242
242
|
def validate_package_set_in_self(package_set)
|
243
|
-
if find_package_set(
|
243
|
+
if find_package_set(package_set.name) != package_set
|
244
244
|
raise UnregisteredPackageSet, "#{package_set.name} is not registered on #{self}"
|
245
245
|
end
|
246
246
|
end
|
data/lib/autoproj/ops/cache.rb
CHANGED
@@ -47,7 +47,7 @@ def cache_git(pkg, options = Hash.new)
|
|
47
47
|
Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'remote', 'update', 'autobuild')
|
48
48
|
end
|
49
49
|
with_retry(10) do
|
50
|
-
Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'fetch', '--tags')
|
50
|
+
Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'fetch', 'autobuild', '--tags')
|
51
51
|
end
|
52
52
|
Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'gc', '--prune=all')
|
53
53
|
end
|
@@ -63,17 +63,28 @@ def cache_archive(pkg)
|
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
def create_or_update(
|
67
|
-
options = Kernel.validate_options options,
|
68
|
-
keep_going: false,
|
69
|
-
checkout_only: false
|
70
|
-
keep_going = options[:keep_going]
|
71
|
-
checkout_only = options[:checkout_only]
|
72
|
-
|
66
|
+
def create_or_update(*package_names, all: true, keep_going: false, checkout_only: false)
|
73
67
|
FileUtils.mkdir_p cache_dir
|
74
68
|
|
75
|
-
|
76
|
-
|
69
|
+
if package_names.empty?
|
70
|
+
packages =
|
71
|
+
if all
|
72
|
+
manifest.each_autobuild_package
|
73
|
+
else
|
74
|
+
manifest.all_selected_source_packages.map(&:autobuild)
|
75
|
+
end
|
76
|
+
else
|
77
|
+
packages = package_names.map do |name|
|
78
|
+
if pkg = manifest.find_autobuild_package(name)
|
79
|
+
pkg
|
80
|
+
else
|
81
|
+
raise PackageNotFound, "no package named #{name}"
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
packages = packages.sort_by(&:name)
|
87
|
+
|
77
88
|
total = packages.size
|
78
89
|
Autoproj.message "Handling #{total} packages"
|
79
90
|
packages.each_with_index do |pkg, i|
|
@@ -73,15 +73,12 @@ def validate_autoproj_current_root(reuse)
|
|
73
73
|
|
74
74
|
MAIN_CONFIGURATION_TEMPLATE = File.expand_path(File.join("..", "..", "..", "samples", 'autoproj'), File.dirname(__FILE__))
|
75
75
|
|
76
|
-
def bootstrap(buildconf_info,
|
77
|
-
options = validate_options options,
|
78
|
-
reuse: Array.new
|
79
|
-
|
76
|
+
def bootstrap(buildconf_info, reuse: Array.new)
|
80
77
|
check_root_dir_empty
|
81
|
-
validate_autoproj_current_root(
|
78
|
+
validate_autoproj_current_root(reuse)
|
82
79
|
|
83
80
|
ws.config.validate_ruby_executable
|
84
|
-
ws.config.set 'reused_autoproj_installations',
|
81
|
+
ws.config.set 'reused_autoproj_installations', reuse, true
|
85
82
|
ws.env.export_env_sh(shell_helpers: ws.config.shell_helpers?)
|
86
83
|
|
87
84
|
# If we are not getting the installation setup from a VCS, copy the template
|
@@ -101,14 +98,14 @@ def bootstrap(buildconf_info, options = Hash.new)
|
|
101
98
|
raise ConfigError.new, "cannot read file / URL #{manifest_url}, did you mean 'autoproj bootstrap VCSTYPE #{manifest_url}' ?"
|
102
99
|
end
|
103
100
|
|
104
|
-
File.open(File.join(
|
101
|
+
File.open(File.join(ws.config_dir, "manifest"), "w") do |io|
|
105
102
|
io.write(manifest_data)
|
106
103
|
end
|
107
104
|
|
108
105
|
elsif buildconf_info.size >= 2 # is a VCS definition for the manifest itself ...
|
109
|
-
type, url, *
|
106
|
+
type, url, *vcs_options = *buildconf_info
|
110
107
|
url = VCSDefinition.to_absolute_url(url, ws.root_dir)
|
111
|
-
do_switch_config(false, type, url, *
|
108
|
+
do_switch_config(false, type, url, *vcs_options)
|
112
109
|
end
|
113
110
|
ws.env.export_env_sh(shell_helpers: ws.config.shell_helpers?)
|
114
111
|
ws.config.save
|
@@ -0,0 +1,99 @@
|
|
1
|
+
module Autoproj
|
2
|
+
# Match class to query OS packages
|
3
|
+
#
|
4
|
+
# This class allows to create a query object based on a textual
|
5
|
+
# representation, and then match osdeps packages using this query object.
|
6
|
+
#
|
7
|
+
# The queries are of the form
|
8
|
+
#
|
9
|
+
# FIELD=VALUE:FIELD~VALUE:FIELD=VALUE
|
10
|
+
#
|
11
|
+
# The F=V form requires an exact match while F~V allows partial
|
12
|
+
# matches. The different matches are combined with AND (i.e. only packages
|
13
|
+
# matching all criterias will be returned)
|
14
|
+
#
|
15
|
+
# The following fields are allowed:
|
16
|
+
# * name: the osdep name
|
17
|
+
# * real_package: a regexp that matches the name of the underlying package
|
18
|
+
# * package_manager: a regexp that matches the underlying package manager
|
19
|
+
#
|
20
|
+
class OSPackageQuery < QueryBase
|
21
|
+
ALLOWED_FIELDS = [
|
22
|
+
'name',
|
23
|
+
'real_package',
|
24
|
+
'package_manager'
|
25
|
+
]
|
26
|
+
DEFAULT_FIELDS = {
|
27
|
+
}
|
28
|
+
|
29
|
+
def initialize(fields, value, partial, os_package_resolver)
|
30
|
+
super(fields, value, partial)
|
31
|
+
@os_package_resolver = os_package_resolver
|
32
|
+
end
|
33
|
+
|
34
|
+
class Adapter
|
35
|
+
def initialize(pkg, os_package_resolver)
|
36
|
+
@pkg = pkg
|
37
|
+
@os_package_resolver = os_package_resolver
|
38
|
+
end
|
39
|
+
|
40
|
+
def name
|
41
|
+
[@pkg]
|
42
|
+
end
|
43
|
+
|
44
|
+
def real_package
|
45
|
+
packages = @os_package_resolver.resolve_os_packages([@pkg])
|
46
|
+
packages.flat_map do |handler, handler_packages|
|
47
|
+
handler_packages
|
48
|
+
end.uniq
|
49
|
+
end
|
50
|
+
|
51
|
+
def package_manager
|
52
|
+
packages = @os_package_resolver.resolve_os_packages([@pkg])
|
53
|
+
packages.flat_map do |handler, handler_packages|
|
54
|
+
handler
|
55
|
+
end.uniq
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# Checks if a package matches against the query
|
60
|
+
#
|
61
|
+
# @param [String] pkg the osdep package name
|
62
|
+
# @return [Boolean] true if it does, false otherwise
|
63
|
+
#
|
64
|
+
# If the package matches, the returned value can be one of:
|
65
|
+
#
|
66
|
+
# EXACT:: this is an exact match
|
67
|
+
# PARTIAL::
|
68
|
+
# the expected value can be found in the package field. The
|
69
|
+
# match is done in a case-insensitive way
|
70
|
+
#
|
71
|
+
# If partial? is not set (i.e. if FIELD=VALUE was used), then only EXACT
|
72
|
+
# or false can be returned.
|
73
|
+
def match(pkg)
|
74
|
+
pkg = Adapter.new(pkg, @os_package_resolver)
|
75
|
+
pkg_value = fields.inject(pkg) do |v, field_name|
|
76
|
+
v.send(field_name)
|
77
|
+
end
|
78
|
+
|
79
|
+
if pkg_value.include?(value)
|
80
|
+
return EXACT
|
81
|
+
end
|
82
|
+
|
83
|
+
if !partial?
|
84
|
+
return
|
85
|
+
end
|
86
|
+
|
87
|
+
if pkg_value.any? { |v| @value_rx === v }
|
88
|
+
return PARTIAL
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Parse a single field in a query (i.e. a FIELD[=~]VALUE string)
|
93
|
+
def self.parse(str, os_package_resolver)
|
94
|
+
fields, value, partial =
|
95
|
+
super(str, allowed_fields: ALLOWED_FIELDS)
|
96
|
+
OSPackageQuery.new(fields, value, partial, os_package_resolver)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -231,7 +231,14 @@ def merge_gemfiles(*path, unlock: [])
|
|
231
231
|
end
|
232
232
|
end
|
233
233
|
path.each do |gemfile|
|
234
|
-
bundler_def =
|
234
|
+
bundler_def =
|
235
|
+
begin Bundler::Dsl.evaluate(gemfile, nil, [])
|
236
|
+
rescue Exception => e
|
237
|
+
cleaned_message = e.message.
|
238
|
+
gsub(/There was an error parsing([^:]+)/, "Error in gem definitions").
|
239
|
+
gsub(/# from.*/, '')
|
240
|
+
raise ConfigError, cleaned_message
|
241
|
+
end
|
235
242
|
gems_remotes |= bundler_def.send(:sources).rubygems_remotes.to_set
|
236
243
|
bundler_def.dependencies.each do |d|
|
237
244
|
d.groups.each do |group_name|
|
@@ -42,8 +42,8 @@ def install(packages, filter_uptodate_packages: false, install_only: false)
|
|
42
42
|
result = false
|
43
43
|
if !patterns.empty?
|
44
44
|
result |= super(patterns,
|
45
|
-
auto_install_cmd:
|
46
|
-
user_install_cmd:
|
45
|
+
auto_install_cmd: %w{yum groupinstall -y},
|
46
|
+
user_install_cmd: %w{yum groupinstall})
|
47
47
|
end
|
48
48
|
if !packages.empty?
|
49
49
|
result |= super(packages)
|
@@ -29,8 +29,8 @@ def install(packages, filter_uptodate_packages: false, install_only: false)
|
|
29
29
|
result = false
|
30
30
|
if !patterns.empty?
|
31
31
|
result |= super(patterns,
|
32
|
-
auto_install_cmd:
|
33
|
-
user_install_cmd:
|
32
|
+
auto_install_cmd: %w{zypper --non-interactive install --type pattern},
|
33
|
+
user_install_cmd: %w{zypper install --type pattern})
|
34
34
|
end
|
35
35
|
if !packages.empty?
|
36
36
|
result |= super(packages)
|
@@ -0,0 +1,128 @@
|
|
1
|
+
module Autoproj
|
2
|
+
# Base implementation for the query classes {SourcePackageQuery} and {OSPackageQuery}
|
3
|
+
class QueryBase
|
4
|
+
# Match priorities
|
5
|
+
EXACT = 4
|
6
|
+
PARTIAL = 3
|
7
|
+
|
8
|
+
# The call chain to be matched (i.e. autobuild.name becomes
|
9
|
+
# ['autobuild', 'name']
|
10
|
+
attr_reader :fields
|
11
|
+
# The expected value
|
12
|
+
attr_reader :value
|
13
|
+
# Whether the match can be partial
|
14
|
+
attr_predicate :partial?, true
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
#
|
18
|
+
# Match class that matches anything
|
19
|
+
#
|
20
|
+
# Use {.all}
|
21
|
+
class All
|
22
|
+
def match(pkg); true end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Get a query that matches anything
|
26
|
+
#
|
27
|
+
# @return [All]
|
28
|
+
def self.all
|
29
|
+
All.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(fields, value, partial)
|
33
|
+
@fields = fields
|
34
|
+
@value = value
|
35
|
+
@value_rx = Regexp.new(Regexp.quote(value), true)
|
36
|
+
@partial = partial
|
37
|
+
end
|
38
|
+
|
39
|
+
# Checks if a package matches against the query
|
40
|
+
#
|
41
|
+
# @param [String] pkg the osdep package name
|
42
|
+
# @return [Boolean] true if it does, false otherwise
|
43
|
+
#
|
44
|
+
# If the package matches, the returned value can be one of:
|
45
|
+
#
|
46
|
+
# EXACT:: this is an exact match
|
47
|
+
# PARTIAL::
|
48
|
+
# the expected value can be found in the package field. The
|
49
|
+
# match is done in a case-insensitive way
|
50
|
+
#
|
51
|
+
# If partial? is not set (i.e. if FIELD=VALUE was used), then only EXACT
|
52
|
+
# or false can be returned.
|
53
|
+
def match(pkg)
|
54
|
+
raise NotImplementedError
|
55
|
+
end
|
56
|
+
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
# Parse a single field in a query (i.e. a FIELD[=~]VALUE string)
|
60
|
+
#
|
61
|
+
# This is NOT meant to be used directly. Subclasses are supposed to
|
62
|
+
# redefine .parse to create the relevant match object.
|
63
|
+
def self.parse(str, allowed_fields: [], default_fields: Hash.new)
|
64
|
+
if parsed = /[=~]/.match(str)
|
65
|
+
field, value = parsed.pre_match, parsed.post_match
|
66
|
+
partial = (parsed[0] == '~')
|
67
|
+
else
|
68
|
+
raise ArgumentError, "invalid query string '#{str}', expected FIELD and VALUE separated by either = or ~"
|
69
|
+
end
|
70
|
+
|
71
|
+
field = default_fields[field] || field
|
72
|
+
|
73
|
+
# Validate the query key
|
74
|
+
if !allowed_fields.include?(field)
|
75
|
+
raise ArgumentError, "'#{field}' is not a known query key"
|
76
|
+
end
|
77
|
+
|
78
|
+
fields = field.split('.')
|
79
|
+
return fields, value, partial
|
80
|
+
end
|
81
|
+
|
82
|
+
# Parse a complete query
|
83
|
+
def self.parse_query(query, *args)
|
84
|
+
query = query.split(':')
|
85
|
+
query = query.map do |str|
|
86
|
+
parse(str, *args)
|
87
|
+
end
|
88
|
+
if query.size == 1
|
89
|
+
query.first
|
90
|
+
else
|
91
|
+
And.new(query)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Match object that combines multiple matches using a logical OR
|
96
|
+
class Or
|
97
|
+
def initialize(submatches)
|
98
|
+
@submatches = submatches
|
99
|
+
end
|
100
|
+
def each_subquery(&block)
|
101
|
+
@submatches.each(&block)
|
102
|
+
end
|
103
|
+
def match(pkg)
|
104
|
+
@submatches.map { |m| m.match(pkg) }.compact.max
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Match object that combines multiple matches using a logical AND
|
109
|
+
class And
|
110
|
+
def initialize(submatches)
|
111
|
+
@submatches = submatches
|
112
|
+
end
|
113
|
+
def each_subquery(&block)
|
114
|
+
@submatches.each(&block)
|
115
|
+
end
|
116
|
+
def match(pkg)
|
117
|
+
matches = @submatches.map do |m|
|
118
|
+
if p = m.match(pkg)
|
119
|
+
p
|
120
|
+
else return
|
121
|
+
end
|
122
|
+
end
|
123
|
+
matches.min
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
data/lib/autoproj/reporter.rb
CHANGED
@@ -88,6 +88,18 @@ def self.report(root_dir: nil, silent: nil, debug: Autobuild.debug,
|
|
88
88
|
package_failures, on_package_failures: on_package_failures, interrupted_by: interrupted)
|
89
89
|
end
|
90
90
|
|
91
|
+
rescue CLI::CLIException, InvalidWorkspace, ConfigError => e
|
92
|
+
if silent_errors
|
93
|
+
return [e]
|
94
|
+
elsif on_package_failures == :raise
|
95
|
+
raise e
|
96
|
+
elsif on_package_failures == :report
|
97
|
+
Autoproj.error e.message
|
98
|
+
elsif on_package_failures == :exit
|
99
|
+
Autoproj.error e.message
|
100
|
+
exit 1
|
101
|
+
end
|
102
|
+
|
91
103
|
rescue SystemExit
|
92
104
|
raise
|
93
105
|
ensure
|
@@ -27,7 +27,7 @@ module Autoproj
|
|
27
27
|
# * 'vcs' can be used instead of 'vcs.url'
|
28
28
|
# * 'package_set' can be used instead of 'package_set.name'
|
29
29
|
#
|
30
|
-
class
|
30
|
+
class SourcePackageQuery < QueryBase
|
31
31
|
ALLOWED_FIELDS = [
|
32
32
|
'autobuild.name',
|
33
33
|
'autobuild.srcdir',
|
@@ -44,29 +44,13 @@ class Query
|
|
44
44
|
}
|
45
45
|
|
46
46
|
# Match priorities
|
47
|
-
EXACT = 4
|
48
|
-
PARTIAL = 3
|
49
47
|
DIR_PREFIX_STRONG = 2
|
50
48
|
DIR_PREFIX_WEAK = 1
|
51
49
|
|
52
|
-
attr_reader :fields
|
53
|
-
attr_reader :value
|
54
50
|
attr_predicate :use_dir_prefix?
|
55
|
-
attr_predicate :partial?
|
56
|
-
|
57
|
-
class All
|
58
|
-
def match(pkg); true end
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.all
|
62
|
-
All.new
|
63
|
-
end
|
64
51
|
|
65
52
|
def initialize(fields, value, partial)
|
66
|
-
|
67
|
-
@value = value
|
68
|
-
@value_rx = Regexp.new(Regexp.quote(value), true)
|
69
|
-
@partial = partial
|
53
|
+
super(fields, value, partial)
|
70
54
|
|
71
55
|
directories = value.split('/')
|
72
56
|
if !directories.empty?
|
@@ -119,15 +103,15 @@ def match(pkg)
|
|
119
103
|
return
|
120
104
|
end
|
121
105
|
|
122
|
-
if
|
106
|
+
if @value_rx === pkg_value
|
123
107
|
return PARTIAL
|
124
108
|
end
|
125
109
|
|
126
110
|
# Special match for directories: match directory prefixes
|
127
111
|
if use_dir_prefix?
|
128
|
-
if
|
112
|
+
if @dir_prefix_strong_rx === pkg_value
|
129
113
|
return DIR_PREFIX_STRONG
|
130
|
-
elsif
|
114
|
+
elsif @dir_prefix_weak_rx === pkg_value
|
131
115
|
return DIR_PREFIX_WEAK
|
132
116
|
end
|
133
117
|
end
|
@@ -135,69 +119,19 @@ def match(pkg)
|
|
135
119
|
|
136
120
|
# Parse a single field in a query (i.e. a FIELD[=~]VALUE string)
|
137
121
|
def self.parse(str)
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
end
|
143
|
-
|
144
|
-
if DEFAULT_FIELDS[field]
|
145
|
-
field = DEFAULT_FIELDS[field]
|
146
|
-
end
|
147
|
-
|
148
|
-
# Validate the query key
|
149
|
-
if !ALLOWED_FIELDS.include?(field)
|
150
|
-
raise ArgumentError, "#{field} is not a known query key"
|
151
|
-
end
|
152
|
-
|
153
|
-
fields = field.split('.')
|
154
|
-
new(fields, value, partial)
|
155
|
-
end
|
156
|
-
|
157
|
-
# Parse a complete query
|
158
|
-
def self.parse_query(query)
|
159
|
-
query = query.split(':')
|
160
|
-
query = query.map do |str|
|
161
|
-
if str !~ /[=~]/
|
162
|
-
match_name = Query.parse("autobuild.name~#{str}")
|
163
|
-
match_dir = Query.parse("autobuild.srcdir~#{str}")
|
164
|
-
Or.new([match_name, match_dir])
|
165
|
-
else
|
166
|
-
Query.parse(str)
|
167
|
-
end
|
168
|
-
end
|
169
|
-
if query.size == 1
|
170
|
-
query.first
|
122
|
+
if str !~ /[=~]/
|
123
|
+
match_name = parse("autobuild.name~#{str}")
|
124
|
+
match_dir = parse("autobuild.srcdir~#{str}")
|
125
|
+
return Or.new([match_name, match_dir])
|
171
126
|
else
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
# Match object that combines multiple matches using a logical OR
|
177
|
-
class Or
|
178
|
-
def initialize(submatches)
|
179
|
-
@submatches = submatches
|
180
|
-
end
|
181
|
-
def match(pkg)
|
182
|
-
@submatches.map { |m| m.match(pkg) }.compact.max
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
# Match object that combines multiple matches using a logical AND
|
187
|
-
class And
|
188
|
-
def initialize(submatches)
|
189
|
-
@submatches = submatches
|
190
|
-
end
|
191
|
-
def match(pkg)
|
192
|
-
matches = @submatches.map do |m|
|
193
|
-
if p = m.match(pkg)
|
194
|
-
p
|
195
|
-
else return
|
196
|
-
end
|
197
|
-
end
|
198
|
-
matches.min
|
127
|
+
fields, value, partial =
|
128
|
+
super(str, default_fields: DEFAULT_FIELDS, allowed_fields: ALLOWED_FIELDS)
|
129
|
+
return new(fields, value, partial)
|
199
130
|
end
|
200
131
|
end
|
201
132
|
end
|
133
|
+
|
134
|
+
# For backward compatibility
|
135
|
+
Query = SourcePackageQuery
|
202
136
|
end
|
203
137
|
|