autoproj 1.9.6 → 1.9.7.rc1
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +15 -0
- data/Rakefile +2 -1
- data/bin/autoproj +1 -2
- data/bin/autoproj-cache +56 -0
- data/bin/autoproj-doc +28 -0
- data/bin/autoproj-query +35 -32
- data/bin/autoproj-snapshot +38 -0
- data/bin/autoproj-test +36 -0
- data/bin/autoproj_bootstrap +104 -10
- data/lib/autoproj.rb +9 -0
- data/lib/autoproj/autobuild.rb +40 -99
- data/lib/autoproj/cmdline.rb +64 -37
- data/lib/autoproj/default.osdeps +30 -1
- data/lib/autoproj/environment.rb +78 -0
- data/lib/autoproj/installation_manifest.rb +36 -0
- data/lib/autoproj/loader.rb +0 -0
- data/lib/autoproj/manifest.rb +35 -1298
- data/lib/autoproj/metapackage.rb +51 -0
- data/lib/autoproj/options.rb +14 -0
- data/lib/autoproj/osdeps.rb +60 -8
- data/lib/autoproj/package_definition.rb +58 -0
- data/lib/autoproj/package_manifest.rb +155 -0
- data/lib/autoproj/package_selection.rb +153 -0
- data/lib/autoproj/package_set.rb +497 -0
- data/lib/autoproj/system.rb +1 -1
- data/lib/autoproj/variable_expansion.rb +107 -0
- data/lib/autoproj/vcs_definition.rb +223 -0
- data/lib/autoproj/version.rb +1 -1
- metadata +28 -10
@@ -0,0 +1,51 @@
|
|
1
|
+
module Autoproj
|
2
|
+
# A set of packages that can be referred to by name
|
3
|
+
class Metapackage
|
4
|
+
# The metapackage name
|
5
|
+
attr_reader :name
|
6
|
+
# The packages listed in this metapackage
|
7
|
+
attr_reader :packages
|
8
|
+
# The normal dependency handling behaviour is to generate an error if a
|
9
|
+
# metapackage is selected for the build but some of its dependencies
|
10
|
+
# cannot be built. This modifies the behaviour to simply ignore the
|
11
|
+
# problematic packages.
|
12
|
+
attr_writer :weak_dependencies
|
13
|
+
|
14
|
+
# @return [Boolean] whether the dependencies from this metapackage are
|
15
|
+
# weak or not
|
16
|
+
# @see #weak_dependencies
|
17
|
+
def weak_dependencies?
|
18
|
+
!!@weak_dependencies
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(name)
|
22
|
+
@name = name
|
23
|
+
@packages = []
|
24
|
+
@weak_dependencies = false
|
25
|
+
end
|
26
|
+
|
27
|
+
# Adds a package to this metapackage
|
28
|
+
#
|
29
|
+
# @param [Autobuild::Package] pkg
|
30
|
+
def add(pkg)
|
31
|
+
@packages << pkg
|
32
|
+
end
|
33
|
+
|
34
|
+
# Lists the packages contained in this metapackage
|
35
|
+
#
|
36
|
+
# @yieldparam [Autobuild::Package] pkg
|
37
|
+
def each_package(&block)
|
38
|
+
@packages.each(&block)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Tests if the given package is included in this metapackage
|
42
|
+
#
|
43
|
+
# @param [String,#name] pkg the package or package name
|
44
|
+
def include?(pkg)
|
45
|
+
if !pkg.respond_to?(:to_str)
|
46
|
+
pkg = pkg.name
|
47
|
+
end
|
48
|
+
@packages.any? { |p| p.name == pkg }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/autoproj/options.rb
CHANGED
@@ -1,6 +1,20 @@
|
|
1
1
|
module Autoproj
|
2
2
|
class InputError < RuntimeError; end
|
3
3
|
|
4
|
+
class << self
|
5
|
+
# Programatically overriden autoproj options
|
6
|
+
#
|
7
|
+
# @see override_option
|
8
|
+
attr_reader :option_overrides
|
9
|
+
end
|
10
|
+
@option_overrides = Hash.new
|
11
|
+
|
12
|
+
# Programatically override a user-selected option without changing the
|
13
|
+
# configuration file
|
14
|
+
def self.override_option(option_name, value)
|
15
|
+
@option_overrides[option_name] = value
|
16
|
+
end
|
17
|
+
|
4
18
|
class BuildOption
|
5
19
|
attr_reader :name
|
6
20
|
attr_reader :type
|
data/lib/autoproj/osdeps.rb
CHANGED
@@ -88,11 +88,11 @@ module Autoproj
|
|
88
88
|
end
|
89
89
|
end
|
90
90
|
end
|
91
|
-
|
92
|
-
|
91
|
+
|
92
|
+
sudo = Autobuild.tool_in_path('sudo')
|
93
93
|
Tempfile.open('osdeps_sh') do |io|
|
94
94
|
io.puts "#! /bin/bash"
|
95
|
-
io.puts GAIN_ROOT_ACCESS
|
95
|
+
io.puts GAIN_ROOT_ACCESS % [sudo]
|
96
96
|
io.write script
|
97
97
|
io.flush
|
98
98
|
Autobuild::Subprocess.run 'autoproj', 'osdeps', '/bin/bash', io.path
|
@@ -102,7 +102,7 @@ module Autoproj
|
|
102
102
|
GAIN_ROOT_ACCESS = <<-EOSCRIPT
|
103
103
|
# Gain root access using sudo
|
104
104
|
if test `id -u` != "0"; then
|
105
|
-
exec
|
105
|
+
exec %s /bin/bash $0 "$@"
|
106
106
|
|
107
107
|
fi
|
108
108
|
EOSCRIPT
|
@@ -214,6 +214,15 @@ fi
|
|
214
214
|
end
|
215
215
|
end
|
216
216
|
|
217
|
+
#Package manger for OpenSuse and Suse (untested)
|
218
|
+
class ZypperManager < ShellScriptManager
|
219
|
+
def initialize
|
220
|
+
super(['zypper'], true,
|
221
|
+
"zypper -n install '%s'",
|
222
|
+
"zypper -n install '%s'")
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
217
226
|
# Package manager interface for systems that use yum
|
218
227
|
class YumManager < ShellScriptManager
|
219
228
|
def initialize
|
@@ -389,10 +398,18 @@ fi
|
|
389
398
|
end
|
390
399
|
end
|
391
400
|
|
401
|
+
def reinstall
|
402
|
+
base_cmdline = [Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('gem')]
|
403
|
+
Autobuild::Subprocess.run 'autoproj', 'osdeps', 'reinstall', *base_cmdline,
|
404
|
+
'clean'
|
405
|
+
Autobuild::Subprocess.run 'autoproj', 'osdeps', 'reinstall', *base_cmdline,
|
406
|
+
'pristine', '--all', '--extensions'
|
407
|
+
end
|
408
|
+
|
392
409
|
def install(gems)
|
393
410
|
guess_gem_program
|
394
411
|
|
395
|
-
base_cmdline = [Autobuild.tool('gem'), 'install']
|
412
|
+
base_cmdline = [Autobuild.tool_in_path('ruby'), '-S', Autobuild.tool('gem'), 'install']
|
396
413
|
if !GemManager.with_doc
|
397
414
|
base_cmdline << '--no-rdoc' << '--no-ri'
|
398
415
|
end
|
@@ -690,6 +707,7 @@ fi
|
|
690
707
|
PackageManagers::PacmanManager,
|
691
708
|
PackageManagers::YumManager,
|
692
709
|
PackageManagers::PortManager,
|
710
|
+
PackageManagers::ZypperManager,
|
693
711
|
PackageManagers::PipManager]
|
694
712
|
OS_PACKAGE_HANDLERS = {
|
695
713
|
'debian' => 'apt-dpkg',
|
@@ -697,7 +715,8 @@ fi
|
|
697
715
|
'arch' => 'pacman',
|
698
716
|
'manjarolinux' => 'pacman',
|
699
717
|
'fedora' => 'yum',
|
700
|
-
'darwin' => 'port'
|
718
|
+
'darwin' => 'port',
|
719
|
+
'opensuse' => 'zypper'
|
701
720
|
}
|
702
721
|
|
703
722
|
# The information contained in the OSdeps files, as a hash
|
@@ -888,6 +907,8 @@ fi
|
|
888
907
|
@operating_system = [[lsb_name, "debian"], lsb_versions]
|
889
908
|
elsif lsb_name != 'arch' && File.exists?("/etc/arch-release")
|
890
909
|
@operating_system = [[lsb_name, "arch"], lsb_versions]
|
910
|
+
elsif lsb_name != 'opensuse' && File.exists?("/etc/SuSE-release")
|
911
|
+
@operating_system = [[lsb_name, "opensuse"], lsb_versions]
|
891
912
|
elsif lsb_name != 'debian'
|
892
913
|
# Debian unstable cannot be detected with lsb_release,
|
893
914
|
# so debian has its own detection logic
|
@@ -925,6 +946,11 @@ fi
|
|
925
946
|
[['darwin'], [version.strip]]
|
926
947
|
elsif Autobuild.windows?
|
927
948
|
[['windows'], []]
|
949
|
+
elsif File.exists?('/etc/SuSE-release')
|
950
|
+
version = File.read('/etc/SuSE-release').strip
|
951
|
+
version =~/.*VERSION\s+=\s+([^\s]+)/
|
952
|
+
version = $1
|
953
|
+
[['opensuse'], [version.strip]]
|
928
954
|
end
|
929
955
|
end
|
930
956
|
|
@@ -1466,8 +1492,18 @@ So, what do you want ? (all, none or a comma-separated list of: os gem pip)
|
|
1466
1492
|
# The set of packages that have already been installed
|
1467
1493
|
attr_reader :installed_packages
|
1468
1494
|
|
1469
|
-
#
|
1470
|
-
|
1495
|
+
# Set up the registered package handlers according to the specified osdeps mode
|
1496
|
+
#
|
1497
|
+
# It enables/disables package handlers based on either the value
|
1498
|
+
# returned by {#osdeps_mode} or the value passed as option (the latter
|
1499
|
+
# takes precedence). Moreover, sets the handler's silent flag using
|
1500
|
+
# {#silent?}
|
1501
|
+
#
|
1502
|
+
# @option options [Array<String>] the package handlers that should be
|
1503
|
+
# enabled. The default value is returned by {#osdeps_mode}
|
1504
|
+
# @return [Array<PackageManagers::Manager>] the set of enabled package
|
1505
|
+
# managers
|
1506
|
+
def setup_package_handlers(options = Hash.new)
|
1471
1507
|
options =
|
1472
1508
|
if Kernel.respond_to?(:validate_options)
|
1473
1509
|
Kernel.validate_options options, :osdeps_mode => osdeps_mode
|
@@ -1495,10 +1531,26 @@ So, what do you want ? (all, none or a comma-separated list of: os gem pip)
|
|
1495
1531
|
v.silent = self.silent?
|
1496
1532
|
end
|
1497
1533
|
|
1534
|
+
enabled_handlers = []
|
1535
|
+
if os_package_handler.enabled?
|
1536
|
+
enabled_handlers << os_package_handler
|
1537
|
+
end
|
1538
|
+
package_handlers.each_value do |v|
|
1539
|
+
if v.enabled?
|
1540
|
+
enabled_handlers << v
|
1541
|
+
end
|
1542
|
+
end
|
1543
|
+
enabled_handlers
|
1544
|
+
end
|
1545
|
+
|
1546
|
+
# Requests the installation of the given set of packages
|
1547
|
+
def install(packages, options = Hash.new)
|
1498
1548
|
# Remove the set of packages that have already been installed
|
1499
1549
|
packages = packages.to_set - installed_packages
|
1500
1550
|
return false if packages.empty?
|
1501
1551
|
|
1552
|
+
setup_package_handlers(options)
|
1553
|
+
|
1502
1554
|
packages = resolve_os_dependencies(packages)
|
1503
1555
|
packages = packages.map do |handler, list|
|
1504
1556
|
if filter_uptodate_packages? && handler.respond_to?(:filter_uptodate_packages)
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Autoproj
|
2
|
+
# Autoproj-specific information about a package definition
|
3
|
+
#
|
4
|
+
# This stores the information that goes in addition to the autobuild package
|
5
|
+
# definitions
|
6
|
+
class PackageDefinition
|
7
|
+
# @return [Autobuild::Package] the autobuild package definitins
|
8
|
+
attr_reader :autobuild
|
9
|
+
# @return [Array<#call>] the set of blocks that should be called to
|
10
|
+
# prepare the package. These are called before any operation has been
|
11
|
+
# performed on the package iself.
|
12
|
+
attr_reader :user_blocks
|
13
|
+
# @return [PackageSet] the package set that defined this package
|
14
|
+
attr_reader :package_set
|
15
|
+
# @return [String] path to the file that contains this package's
|
16
|
+
# definition
|
17
|
+
attr_reader :file
|
18
|
+
# Whether this package is completely setup
|
19
|
+
#
|
20
|
+
# If the package is set up, its importer as well as all target
|
21
|
+
# directories are properly set, and all {user_blocks} have been called.
|
22
|
+
def setup?; !!@setup end
|
23
|
+
|
24
|
+
# Sets the {setup?} flag
|
25
|
+
attr_writer :setup
|
26
|
+
|
27
|
+
# @return [VCSDefinition] the version control information associated
|
28
|
+
# with this package
|
29
|
+
attr_accessor :vcs
|
30
|
+
|
31
|
+
def initialize(autobuild, package_set, file)
|
32
|
+
@autobuild, @package_set, @file =
|
33
|
+
autobuild, package_set, file
|
34
|
+
@user_blocks = []
|
35
|
+
end
|
36
|
+
|
37
|
+
# The package name
|
38
|
+
# @return [String]
|
39
|
+
def name
|
40
|
+
autobuild.name
|
41
|
+
end
|
42
|
+
|
43
|
+
# Registers a setup block
|
44
|
+
#
|
45
|
+
# The block will be called when the setup phase is finished, or
|
46
|
+
# immediately if it is already finished (i.e. if {setup?} returns true)
|
47
|
+
#
|
48
|
+
# @param [#call] block the block that should be registered
|
49
|
+
# @yieldparam [Autobuild::Package] pkg the autobuild package object
|
50
|
+
# @see {user_blocks}
|
51
|
+
def add_setup_block(block)
|
52
|
+
user_blocks << block
|
53
|
+
if setup?
|
54
|
+
block.call(autobuild)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module Autoproj
|
2
|
+
# Access to the information contained in a package's manifest.xml file
|
3
|
+
#
|
4
|
+
# Use PackageManifest.load to create
|
5
|
+
class PackageManifest
|
6
|
+
# Load a manifest.xml file and returns the corresponding
|
7
|
+
# PackageManifest object
|
8
|
+
def self.load(package, file)
|
9
|
+
doc =
|
10
|
+
begin REXML::Document.new(File.read(file))
|
11
|
+
rescue REXML::ParseException => e
|
12
|
+
raise Autobuild::PackageException.new(package.name, 'prepare'), "invalid #{file}: #{e.message}"
|
13
|
+
end
|
14
|
+
|
15
|
+
PackageManifest.new(package, doc)
|
16
|
+
end
|
17
|
+
|
18
|
+
# The Autobuild::Package instance this manifest applies on
|
19
|
+
attr_reader :package
|
20
|
+
# The raw XML data as a Nokogiri document
|
21
|
+
attr_reader :xml
|
22
|
+
|
23
|
+
# The list of tags defined for this package
|
24
|
+
#
|
25
|
+
# Tags are defined as multiple <tags></tags> blocks, each of which can
|
26
|
+
# contain multiple comma-separated tags
|
27
|
+
def tags
|
28
|
+
result = []
|
29
|
+
xml.elements.each('package/tags') do |node|
|
30
|
+
result.concat((node.text || "").strip.split(','))
|
31
|
+
end
|
32
|
+
result
|
33
|
+
end
|
34
|
+
|
35
|
+
def documentation
|
36
|
+
xml.elements.each('package/description') do |node|
|
37
|
+
doc = (node.text || "").strip
|
38
|
+
if !doc.empty?
|
39
|
+
return doc
|
40
|
+
end
|
41
|
+
end
|
42
|
+
return short_documentation
|
43
|
+
end
|
44
|
+
|
45
|
+
def short_documentation
|
46
|
+
xml.elements.each('package/description') do |node|
|
47
|
+
doc = node.attributes['brief']
|
48
|
+
if doc
|
49
|
+
doc = doc.to_s.strip
|
50
|
+
end
|
51
|
+
if doc && !doc.empty?
|
52
|
+
return doc.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
"no documentation available for #{package.name} in its manifest.xml file"
|
56
|
+
end
|
57
|
+
|
58
|
+
def initialize(package, doc = REXML::Document.new)
|
59
|
+
@package = package
|
60
|
+
@xml = doc
|
61
|
+
end
|
62
|
+
|
63
|
+
def each_dependency(&block)
|
64
|
+
if block_given?
|
65
|
+
each_os_dependency(&block)
|
66
|
+
each_package_dependency(&block)
|
67
|
+
else
|
68
|
+
enum_for(:each_dependency, &block)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def each_os_dependency
|
73
|
+
if block_given?
|
74
|
+
xml.elements.each('package/rosdep') do |node|
|
75
|
+
yield(node.attributes['name'], false)
|
76
|
+
end
|
77
|
+
package.os_packages.each do |name|
|
78
|
+
yield(name, false)
|
79
|
+
end
|
80
|
+
else
|
81
|
+
enum_for :each_os_dependency
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def each_package_dependency
|
86
|
+
if block_given?
|
87
|
+
depend_nodes = xml.elements.to_a('package/depend') +
|
88
|
+
xml.elements.to_a('package/depend_optional')
|
89
|
+
|
90
|
+
depend_nodes.each do |node|
|
91
|
+
dependency = node.attributes['package']
|
92
|
+
optional = (node.attributes['optional'].to_s == '1' || node.name == "depend_optional")
|
93
|
+
|
94
|
+
if dependency
|
95
|
+
yield(dependency, optional)
|
96
|
+
else
|
97
|
+
raise ConfigError.new, "manifest of #{package.name} has a <depend> tag without a 'package' attribute"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
else
|
101
|
+
enum_for :each_package_dependency
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Enumerates the name and email of each author. If no email is present,
|
106
|
+
# yields (name, nil)
|
107
|
+
def each_author
|
108
|
+
if !block_given?
|
109
|
+
return enum_for(:each_author)
|
110
|
+
end
|
111
|
+
|
112
|
+
xml.elements.each('package/author') do |author|
|
113
|
+
(author.text || "").strip.split(',').each do |str|
|
114
|
+
name, email = str.split('/').map(&:strip)
|
115
|
+
email = nil if email && email.empty?
|
116
|
+
yield(name, email)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# If +name+ points to a text element in the XML document, returns the
|
122
|
+
# content of that element. If no element matches +name+, or if the
|
123
|
+
# content is empty, returns nil
|
124
|
+
def text_node(name)
|
125
|
+
xml.elements.each(name) do |str|
|
126
|
+
str = (str.text || "").strip
|
127
|
+
if !str.empty?
|
128
|
+
return str
|
129
|
+
end
|
130
|
+
end
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
|
134
|
+
# The package associated URL, usually meant to direct to a website
|
135
|
+
#
|
136
|
+
# Returns nil if there is none
|
137
|
+
def url
|
138
|
+
return text_node('package/url')
|
139
|
+
end
|
140
|
+
|
141
|
+
# The package license name
|
142
|
+
#
|
143
|
+
# Returns nil if there is none
|
144
|
+
def license
|
145
|
+
return text_node('package/license')
|
146
|
+
end
|
147
|
+
|
148
|
+
# The package version number
|
149
|
+
#
|
150
|
+
# Returns 0 if none is declared
|
151
|
+
def version
|
152
|
+
return text_node("version")
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module Autoproj
|
2
|
+
# Exception raised by
|
3
|
+
# PackageSelection#filter_excluded_and_ignored_packages when a given
|
4
|
+
# selection is completely excluded
|
5
|
+
class ExcludedSelection < ConfigError
|
6
|
+
attr_reader :selection
|
7
|
+
def initialize(selection)
|
8
|
+
@selection = selection
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Class holding information about which packages have been selected, and
|
13
|
+
# why. It is used to decide whether some non-availability of packages
|
14
|
+
# are errors or simply warnings (i.e. if the user really wants a given
|
15
|
+
# package, or merely might be adding it by accident)
|
16
|
+
class PackageSelection
|
17
|
+
# The set of matches, i.e. a mapping from a user-provided string to
|
18
|
+
# the set of packages it selected
|
19
|
+
attr_reader :matches
|
20
|
+
# The set of selected packages, as a hash of the package name to the
|
21
|
+
# set of user-provided strings that caused that package to be
|
22
|
+
# selected
|
23
|
+
attr_reader :selection
|
24
|
+
# The set of osdeps matches, i.e. a mapping from a user-provided string to
|
25
|
+
# the set of packages it selected
|
26
|
+
attr_reader :osdeps_matches
|
27
|
+
# The set of selected osdeps packages, as a hash of the package name
|
28
|
+
# to the set of user-provided strings that caused that package to be
|
29
|
+
# selected
|
30
|
+
attr_reader :osdeps_selection
|
31
|
+
# A flag that tells #filter_excluded_and_ignored_packages whether
|
32
|
+
# the a given package selection is weak or not.
|
33
|
+
#
|
34
|
+
# If true, a selection that have some excluded packages will not
|
35
|
+
# generate an error. Otherwise (the default), an error is generated
|
36
|
+
attr_reader :weak_dependencies
|
37
|
+
# After a call to #filter_excluded_and_ignored_packages, this
|
38
|
+
# contains the set of package exclusions that have been ignored
|
39
|
+
# because the corresponding metapackage has a weak dependency policy
|
40
|
+
attr_reader :exclusions
|
41
|
+
# After a call to #filter_excluded_and_ignored_packages, this
|
42
|
+
# contains the set of package ignores that have been ignored because
|
43
|
+
# the corresponding metapackage has a weak dependency policy
|
44
|
+
attr_reader :ignores
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
@selection = Hash.new { |h, k| h[k] = Set.new }
|
48
|
+
@matches = Hash.new { |h, k| h[k] = Set.new }
|
49
|
+
@osdeps_matches = Hash.new { |h, k| h[k] = Set.new }
|
50
|
+
@osdeps_selection = Hash.new { |h, k| h[k] = Set.new }
|
51
|
+
@weak_dependencies = Hash.new
|
52
|
+
@ignores = Hash.new { |h, k| h[k] = Set.new }
|
53
|
+
@exclusions = Hash.new { |h, k| h[k] = Set.new }
|
54
|
+
end
|
55
|
+
|
56
|
+
# The set of packages that have been selected
|
57
|
+
def packages
|
58
|
+
selection.keys
|
59
|
+
end
|
60
|
+
|
61
|
+
# The set of packages that have been selected
|
62
|
+
def osdeps_packages
|
63
|
+
osdeps_selection.keys
|
64
|
+
end
|
65
|
+
|
66
|
+
def include?(pkg_name)
|
67
|
+
selection.has_key?(pkg_name) || osdeps_selection.has_key?(pkg_name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def empty?
|
71
|
+
selection.empty?
|
72
|
+
end
|
73
|
+
|
74
|
+
def each(&block)
|
75
|
+
selection.each_key(&block)
|
76
|
+
end
|
77
|
+
|
78
|
+
def select(sel, packages, weak = false)
|
79
|
+
packages = Array(packages)
|
80
|
+
matches[sel] |= packages.to_set.dup
|
81
|
+
packages.each do |pkg_name|
|
82
|
+
selection[pkg_name] << sel
|
83
|
+
end
|
84
|
+
weak_dependencies[sel] = weak
|
85
|
+
end
|
86
|
+
|
87
|
+
def initialize_copy(old)
|
88
|
+
old.selection.each do |pkg_name, set|
|
89
|
+
@selection[pkg_name] = set.dup
|
90
|
+
end
|
91
|
+
old.matches.each do |sel, set|
|
92
|
+
@matches[sel] = set.dup
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def has_match_for?(sel)
|
97
|
+
matches.has_key?(sel)
|
98
|
+
end
|
99
|
+
|
100
|
+
# Remove packages that are explicitely excluded and/or ignored
|
101
|
+
#
|
102
|
+
# Raise an error if an explicit selection expands only to an
|
103
|
+
# excluded package, and display a warning for ignored packages
|
104
|
+
def filter_excluded_and_ignored_packages(manifest)
|
105
|
+
matches.each do |sel, expansion|
|
106
|
+
excluded, other = expansion.partition { |pkg_name| manifest.excluded?(pkg_name) }
|
107
|
+
ignored, ok = other.partition { |pkg_name| manifest.ignored?(pkg_name) }
|
108
|
+
|
109
|
+
if !excluded.empty? && (!weak_dependencies[sel] || (ok.empty? && ignored.empty?))
|
110
|
+
exclusions = excluded.map do |pkg_name|
|
111
|
+
[pkg_name, manifest.exclusion_reason(pkg_name)]
|
112
|
+
end
|
113
|
+
base_msg = "#{sel} is selected in the manifest or on the command line"
|
114
|
+
if exclusions.size == 1
|
115
|
+
reason = exclusions[0][1]
|
116
|
+
if sel == exclusions[0][0]
|
117
|
+
raise ExcludedSelection.new(sel), "#{base_msg}, but it is excluded from the build: #{reason}"
|
118
|
+
elsif weak_dependencies[sel]
|
119
|
+
raise ExcludedSelection.new(sel), "#{base_msg}, but it expands to #{exclusions.map(&:first).join(", ")}, which is excluded from the build: #{reason}"
|
120
|
+
else
|
121
|
+
raise ExcludedSelection.new(sel), "#{base_msg}, but its dependency #{exclusions.map(&:first).join(", ")} is excluded from the build: #{reason}"
|
122
|
+
end
|
123
|
+
elsif weak_dependencies[sel]
|
124
|
+
raise ExcludedSelection.new(sel), "#{base_msg}, but expands to #{exclusions.map(&:first).join(", ")}, and all these packages are excluded from the build:\n #{exclusions.map { |name, reason| "#{name}: #{reason}" }.join("\n ")}"
|
125
|
+
else
|
126
|
+
raise ExcludedSelection.new(sel), "#{base_msg}, but it requires #{exclusions.map(&:first).join(", ")}, and all these packages are excluded from the build:\n #{exclusions.map { |name, reason| "#{name}: #{reason}" }.join("\n ")}"
|
127
|
+
end
|
128
|
+
else
|
129
|
+
self.exclusions[sel] |= excluded.to_set.dup
|
130
|
+
self.ignores[sel] |= ignored.to_set.dup
|
131
|
+
end
|
132
|
+
|
133
|
+
excluded = excluded.to_set
|
134
|
+
ignored = ignored.to_set
|
135
|
+
expansion.delete_if do |pkg_name|
|
136
|
+
ignored.include?(pkg_name) || excluded.include?(pkg_name)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
selection.keys.sort.each do |pkg_name|
|
141
|
+
if manifest.excluded?(pkg_name)
|
142
|
+
selection.delete(pkg_name)
|
143
|
+
elsif manifest.ignored?(pkg_name)
|
144
|
+
selection.delete(pkg_name)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
matches.delete_if do |key, sel|
|
148
|
+
sel.empty?
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|