autoproj 2.3.1 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
|