autoproj 2.8.8 → 2.9.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/bin/alog +5 -3
- data/lib/autoproj.rb +2 -0
- data/lib/autoproj/cli/base.rb +8 -1
- data/lib/autoproj/cli/build.rb +5 -3
- data/lib/autoproj/cli/locate.rb +5 -1
- data/lib/autoproj/cli/osdeps.rb +1 -0
- data/lib/autoproj/cli/status.rb +13 -4
- data/lib/autoproj/cli/update.rb +9 -5
- data/lib/autoproj/default.osdeps +14 -0
- data/lib/autoproj/manifest.rb +7 -9
- data/lib/autoproj/ops/build.rb +48 -2
- data/lib/autoproj/ops/configuration.rb +18 -0
- data/lib/autoproj/os_package_installer.rb +27 -0
- data/lib/autoproj/os_repository_installer.rb +53 -0
- data/lib/autoproj/os_repository_resolver.rb +137 -0
- data/lib/autoproj/package_managers/apt_dpkg_manager.rb +70 -10
- data/lib/autoproj/package_managers/bundler_manager.rb +9 -2
- data/lib/autoproj/package_managers/debian_version.rb +123 -0
- data/lib/autoproj/package_managers/manager.rb +9 -0
- data/lib/autoproj/package_managers/pip_manager.rb +4 -0
- data/lib/autoproj/package_selection.rb +36 -10
- data/lib/autoproj/package_set.rb +39 -4
- data/lib/autoproj/repository_managers/apt.rb +289 -0
- data/lib/autoproj/repository_managers/manager.rb +26 -0
- data/lib/autoproj/repository_managers/unknown_os_manager.rb +30 -0
- data/lib/autoproj/test.rb +1 -0
- data/lib/autoproj/version.rb +1 -1
- data/lib/autoproj/workspace.rb +21 -7
- metadata +8 -2
@@ -50,6 +50,35 @@ def empty?
|
|
50
50
|
selection.empty?
|
51
51
|
end
|
52
52
|
|
53
|
+
# Returns the source packages selected explicitely or through
|
54
|
+
# dependencies
|
55
|
+
#
|
56
|
+
# @param [Manifest] manifest
|
57
|
+
# @return [Array<PackageDefinition>]
|
58
|
+
def all_selected_source_packages(manifest)
|
59
|
+
names = Set.new
|
60
|
+
roots = each_source_package_name.to_set
|
61
|
+
roots.each do |pkg_name|
|
62
|
+
manifest.find_autobuild_package(pkg_name).all_dependencies(names)
|
63
|
+
end
|
64
|
+
names.merge(roots).map do |pkg_name|
|
65
|
+
manifest.find_package_definition(pkg_name)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns the source packages selected explicitely or through
|
70
|
+
# dependencies
|
71
|
+
#
|
72
|
+
# @param [Manifest] manifest
|
73
|
+
# @return [Array<String>]
|
74
|
+
def all_selected_osdep_packages(manifest)
|
75
|
+
all_sources = all_selected_source_packages(manifest)
|
76
|
+
from_source = all_sources.each_with_object(Set.new) do |pkg, s|
|
77
|
+
s.merge(pkg.autobuild.os_packages)
|
78
|
+
end
|
79
|
+
from_source | osdeps
|
80
|
+
end
|
81
|
+
|
53
82
|
def each(&block)
|
54
83
|
Autoproj.warn_deprecated "PackageSelection#each", "use PackageSelection#each_source_package_name instead", 0
|
55
84
|
each_source_package_name(&block)
|
@@ -78,27 +107,24 @@ def packages
|
|
78
107
|
source_packages
|
79
108
|
end
|
80
109
|
|
81
|
-
def select(sel, packages,
|
82
|
-
|
110
|
+
def select(sel, packages, *_backward, weak: false, osdep: false)
|
111
|
+
unless _backward.empty?
|
83
112
|
Autoproj.warn_deprecated "calling PackageSelection#select with a boolean as third argument", "use e.g. weak: true instead", 0
|
84
|
-
|
113
|
+
weak = _backward.first
|
85
114
|
end
|
86
|
-
options = Kernel.validate_options options,
|
87
|
-
weak: false,
|
88
|
-
osdep: false
|
89
115
|
|
90
116
|
packages = Array(packages).to_set
|
91
117
|
matches[sel].merge(packages)
|
92
118
|
packages.each do |pkg_name|
|
93
119
|
selection[pkg_name] << sel
|
94
120
|
end
|
95
|
-
if
|
121
|
+
if osdep
|
96
122
|
osdeps.merge(packages)
|
97
123
|
else
|
98
124
|
source_packages.merge(packages)
|
99
125
|
end
|
100
126
|
|
101
|
-
weak_dependencies[sel] =
|
127
|
+
weak_dependencies[sel] = weak
|
102
128
|
end
|
103
129
|
|
104
130
|
def initialize_copy(old)
|
@@ -160,10 +186,10 @@ def filter_excluded_and_ignored_packages(manifest)
|
|
160
186
|
end
|
161
187
|
end
|
162
188
|
|
163
|
-
source_packages.delete_if do |pkg_name|
|
189
|
+
source_packages.delete_if do |pkg_name|
|
164
190
|
manifest.excluded?(pkg_name) || manifest.ignored?(pkg_name)
|
165
191
|
end
|
166
|
-
osdeps.delete_if do |pkg_name|
|
192
|
+
osdeps.delete_if do |pkg_name|
|
167
193
|
manifest.excluded?(pkg_name) || manifest.ignored?(pkg_name)
|
168
194
|
end
|
169
195
|
selection.delete_if do |pkg_name, _|
|
data/lib/autoproj/package_set.rb
CHANGED
@@ -5,7 +5,7 @@ module Autoproj
|
|
5
5
|
# dependencies that are provided by the operating system (.osdeps file).
|
6
6
|
class PackageSet
|
7
7
|
# Exception raised when an operation that needs the source.yml to be
|
8
|
-
# loaded is called before {PackageSet#load_description_file} is called
|
8
|
+
# loaded is called before {PackageSet#load_description_file} is called
|
9
9
|
class NotLoaded < RuntimeError
|
10
10
|
attr_reader :package_set
|
11
11
|
def initialize(package_set)
|
@@ -34,7 +34,7 @@ def add_source_file(name)
|
|
34
34
|
|
35
35
|
# The manifest this package set is registered on
|
36
36
|
#
|
37
|
-
# @return [Manifest]
|
37
|
+
# @return [Manifest]
|
38
38
|
def manifest
|
39
39
|
ws.manifest
|
40
40
|
end
|
@@ -64,10 +64,21 @@ def manifest
|
|
64
64
|
# and the corresponding OSPackageResolver object
|
65
65
|
attr_reader :all_osdeps
|
66
66
|
|
67
|
+
# The set of OSRepositoryResolver object that represent the osrepos files
|
68
|
+
# available in this package set
|
69
|
+
#
|
70
|
+
# @return [Array<(String,OSRepositoryResolver)>] the list of osdep files
|
71
|
+
# and the corresponding OSRepositoryResolver object
|
72
|
+
attr_reader :all_osrepos
|
73
|
+
|
67
74
|
# The OSPackageResolver which is a merged version of all OSdeps in
|
68
75
|
# {#all_osdeps}
|
69
76
|
attr_reader :os_package_resolver
|
70
77
|
|
78
|
+
# The OSRepositoryResolver which is a merged version of all OSrepos in
|
79
|
+
# {#all_osrepos}
|
80
|
+
attr_reader :os_repository_resolver
|
81
|
+
|
71
82
|
# If this package set has been imported from another package set, this
|
72
83
|
# is the other package set object
|
73
84
|
attr_accessor :imported_from
|
@@ -144,12 +155,14 @@ def initialize(
|
|
144
155
|
raise ArgumentError, "cannot create a package set with a nil vcs, create a null VCS using VCSDefinition.none"
|
145
156
|
end
|
146
157
|
@name = name
|
158
|
+
@os_repository_resolver = OSRepositoryResolver.new
|
147
159
|
@os_package_resolver = OSPackageResolver.new(
|
148
160
|
operating_system: ws.os_package_resolver.operating_system,
|
149
161
|
package_managers: ws.os_package_resolver.package_managers,
|
150
162
|
os_package_manager: ws.os_package_resolver.os_package_manager)
|
151
163
|
@importer_definitions_cache = Hash.new
|
152
164
|
@all_osdeps = []
|
165
|
+
@all_osrepos = []
|
153
166
|
@constants_definitions = Hash.new
|
154
167
|
@required_autoproj_version = '0'
|
155
168
|
@version_control = Array.new
|
@@ -175,11 +188,24 @@ def load_osdeps(file, **options)
|
|
175
188
|
new_osdeps
|
176
189
|
end
|
177
190
|
|
191
|
+
# Load a new osrepos file for this package set
|
192
|
+
def load_osrepos(file)
|
193
|
+
new_osrepos = OSRepositoryResolver.load(file)
|
194
|
+
all_osrepos << new_osrepos
|
195
|
+
os_repository_resolver.merge(all_osrepos.last)
|
196
|
+
new_osrepos
|
197
|
+
end
|
198
|
+
|
178
199
|
# Enumerate all osdeps package names from this package set
|
179
200
|
def each_osdep(&block)
|
180
201
|
os_package_resolver.all_package_names.each(&block)
|
181
202
|
end
|
182
203
|
|
204
|
+
# Enumerate all osrepos entries from this package set
|
205
|
+
def each_osrepo(&block)
|
206
|
+
os_repository_resolver.all_entries.each(&block)
|
207
|
+
end
|
208
|
+
|
183
209
|
# True if this source has already been checked out on the local autoproj
|
184
210
|
# installation
|
185
211
|
def present?; File.directory?(raw_local_dir) end
|
@@ -302,7 +328,7 @@ def repository_id
|
|
302
328
|
# For local sources, is simply returns the path to the source directory.
|
303
329
|
def user_local_dir
|
304
330
|
if local?
|
305
|
-
return vcs.url
|
331
|
+
return vcs.url
|
306
332
|
else
|
307
333
|
File.join(ws.config_dir, 'remotes', name)
|
308
334
|
end
|
@@ -714,7 +740,7 @@ def overrides_for(package, vcs, require_existing: true)
|
|
714
740
|
# This is a helper for {#overrides_for}
|
715
741
|
def resolve_overrides(key, vcs)
|
716
742
|
overrides.each do |file, file_overrides|
|
717
|
-
new_spec, new_raw_entry =
|
743
|
+
new_spec, new_raw_entry =
|
718
744
|
Autoproj.in_file file do
|
719
745
|
version_control_field(key, file_overrides, validate: false, file: file)
|
720
746
|
end
|
@@ -762,6 +788,15 @@ def each_osdeps_file
|
|
762
788
|
yield(file)
|
763
789
|
end
|
764
790
|
end
|
791
|
+
|
792
|
+
# Yields each osdeps definition files that are present in this package
|
793
|
+
# set
|
794
|
+
def each_osrepos_file
|
795
|
+
return enum_for(__method__) if !block_given?
|
796
|
+
Dir.glob(File.join(local_dir, "*.osrepos")).each do |file|
|
797
|
+
yield(file)
|
798
|
+
end
|
799
|
+
end
|
765
800
|
end
|
766
801
|
end
|
767
802
|
|
@@ -0,0 +1,289 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
require 'open3'
|
4
|
+
require 'pathname'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
module Autoproj
|
8
|
+
module RepositoryManagers
|
9
|
+
# Apt repository manager class
|
10
|
+
class APT < Manager
|
11
|
+
attr_reader :source_files
|
12
|
+
attr_reader :source_entries
|
13
|
+
attr_reader :sources_dir
|
14
|
+
attr_reader :autoproj_sources
|
15
|
+
|
16
|
+
SOURCES_DIR = '/etc/apt'.freeze
|
17
|
+
SOURCE_TYPES = ['deb', 'deb-src'].freeze
|
18
|
+
AUTOPROJ_SOURCES = '/etc/apt/sources.list.d/autoproj.list'.freeze
|
19
|
+
|
20
|
+
def initialize(ws, sources_dir: SOURCES_DIR, autoproj_sources: AUTOPROJ_SOURCES)
|
21
|
+
@sources_dir = sources_dir
|
22
|
+
@autoproj_sources = autoproj_sources
|
23
|
+
@source_files = Dir[File.join(sources_dir, '**', '*.list')]
|
24
|
+
@source_entries = {}
|
25
|
+
|
26
|
+
source_files.each { |file| load_sources_from_file(file) }
|
27
|
+
super(ws)
|
28
|
+
end
|
29
|
+
|
30
|
+
def os_dependencies
|
31
|
+
super + ['archive-keyring', 'gnupg', 'apt-transport-https']
|
32
|
+
end
|
33
|
+
|
34
|
+
def load_sources_from_file(file)
|
35
|
+
contents = File.open(file).read
|
36
|
+
contents.gsub!(/\r\n?/, "\n")
|
37
|
+
|
38
|
+
contents.each_line do |line|
|
39
|
+
@source_entries[file] ||= []
|
40
|
+
@source_entries[file] << parse_source_line(line, raise_if_invalid: false)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def parse_source_line(line, raise_if_invalid: true)
|
45
|
+
entry = {}
|
46
|
+
entry[:valid] = false
|
47
|
+
entry[:enabled] = true
|
48
|
+
entry[:source] = ''
|
49
|
+
entry[:comment] = ''
|
50
|
+
|
51
|
+
line.strip!
|
52
|
+
if line.start_with?('#')
|
53
|
+
entry[:enabled] = false
|
54
|
+
line = line[1..-1]
|
55
|
+
end
|
56
|
+
|
57
|
+
i = line.index('#')
|
58
|
+
if i&.positive?
|
59
|
+
entry[:comment] = line[(i + 1)..-1].strip
|
60
|
+
line = line[0..(i - 1)]
|
61
|
+
end
|
62
|
+
|
63
|
+
entry[:source] = line.strip
|
64
|
+
chunks = entry[:source].split
|
65
|
+
entry[:valid] = true if SOURCE_TYPES.include?(chunks[0])
|
66
|
+
entry[:source] = chunks.join(' ')
|
67
|
+
|
68
|
+
if raise_if_invalid && (!entry[:valid] || !entry[:enabled])
|
69
|
+
raise ConfigError, "Invalid source line: #{entry[:source]}"
|
70
|
+
end
|
71
|
+
|
72
|
+
entry
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_source(source, file = nil)
|
76
|
+
file = if file
|
77
|
+
File.join(sources_dir, 'sources.list.d', file)
|
78
|
+
else
|
79
|
+
autoproj_sources
|
80
|
+
end
|
81
|
+
|
82
|
+
new_entry = parse_source_line(source)
|
83
|
+
found = entry_exist?(new_entry)
|
84
|
+
|
85
|
+
if found
|
86
|
+
file = found.first
|
87
|
+
entry = found.last
|
88
|
+
return false if entry[:enabled]
|
89
|
+
|
90
|
+
enable_entry_in_file(file, entry)
|
91
|
+
else
|
92
|
+
add_entry_to_file(file, new_entry)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def append_entry(contents, entry)
|
97
|
+
unless entry[:enabled]
|
98
|
+
contents << '#'
|
99
|
+
contents << ' ' unless entry[:source].start_with?('#')
|
100
|
+
end
|
101
|
+
|
102
|
+
contents << entry[:source]
|
103
|
+
contents << "# #{entry[:comment]}" unless entry[:comment].empty?
|
104
|
+
contents << "\n"
|
105
|
+
end
|
106
|
+
|
107
|
+
def enable_entry_in_file(file, enable_entry)
|
108
|
+
contents = ''
|
109
|
+
source_entries[file].each do |entry|
|
110
|
+
entry[:enabled] = true if enable_entry[:source] == entry[:source]
|
111
|
+
append_entry(contents, entry)
|
112
|
+
end
|
113
|
+
run_tee_command(['sudo', 'tee', file], contents)
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
def add_entry_to_file(file, entry)
|
118
|
+
run_tee_command(['sudo', 'tee', '-a', file], entry[:source])
|
119
|
+
@source_entries[file] ||= []
|
120
|
+
@source_entries[file] << entry
|
121
|
+
true
|
122
|
+
end
|
123
|
+
|
124
|
+
def run_tee_command(command, contents)
|
125
|
+
contents = StringIO.new("#{contents}\n")
|
126
|
+
Autobuild::Subprocess.run('autoproj', 'osrepos', *command, input_streams: [contents])
|
127
|
+
end
|
128
|
+
|
129
|
+
def entry_exist?(new_entry)
|
130
|
+
source_entries.each_pair do |file, entries|
|
131
|
+
entry = entries.find { |e| e[:source] == new_entry[:source] }
|
132
|
+
return [file, entry] if entry
|
133
|
+
end
|
134
|
+
nil
|
135
|
+
end
|
136
|
+
|
137
|
+
def source_exist?(source)
|
138
|
+
entry_exist?(parse_source_line(source))
|
139
|
+
end
|
140
|
+
|
141
|
+
def key_exist?(key)
|
142
|
+
exist = false
|
143
|
+
Open3.popen3("apt-key export #{key}") do |_, _, stderr, wait_thr|
|
144
|
+
exist = true if wait_thr.value.success? && stderr.read.empty?
|
145
|
+
end
|
146
|
+
exist
|
147
|
+
end
|
148
|
+
|
149
|
+
def apt_update
|
150
|
+
Autobuild::Subprocess.run(
|
151
|
+
'autoproj',
|
152
|
+
'osrepos',
|
153
|
+
'sudo',
|
154
|
+
'apt-get',
|
155
|
+
'update'
|
156
|
+
)
|
157
|
+
end
|
158
|
+
|
159
|
+
def add_apt_key(id, origin, type: :keyserver)
|
160
|
+
if type == :keyserver
|
161
|
+
Autobuild::Subprocess.run(
|
162
|
+
'autoproj',
|
163
|
+
'osrepos',
|
164
|
+
'sudo',
|
165
|
+
'apt-key',
|
166
|
+
'adv',
|
167
|
+
'--keyserver',
|
168
|
+
origin,
|
169
|
+
'--recv-key',
|
170
|
+
id
|
171
|
+
)
|
172
|
+
else
|
173
|
+
open(origin) do |io|
|
174
|
+
Autobuild::Subprocess.run(
|
175
|
+
'autoproj',
|
176
|
+
'osrepos',
|
177
|
+
'sudo',
|
178
|
+
'apt-key',
|
179
|
+
'add',
|
180
|
+
'-',
|
181
|
+
input_streams: [io]
|
182
|
+
)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
rescue Errno::ENOENT, SocketError => e
|
186
|
+
raise ConfigError, e.message
|
187
|
+
end
|
188
|
+
|
189
|
+
def filter_installed_definitions(definitions)
|
190
|
+
definitions = definitions.dup.reject do |definition|
|
191
|
+
if definition['type'] == 'repo'
|
192
|
+
_, entry = source_exist?(definition['repo'])
|
193
|
+
entry && entry[:enabled]
|
194
|
+
else
|
195
|
+
key_exist?(definition['id'])
|
196
|
+
end
|
197
|
+
end
|
198
|
+
definitions
|
199
|
+
end
|
200
|
+
|
201
|
+
def print_installing_definitions(definitions)
|
202
|
+
repos = definitions.select { |definition| definition['type'] == 'repo' }
|
203
|
+
keys = definitions.select { |definition| definition['type'] == 'key' }
|
204
|
+
|
205
|
+
unless repos.empty?
|
206
|
+
Autoproj.message ' adding apt repositories:'
|
207
|
+
repos.each do |repo|
|
208
|
+
if repo['file']
|
209
|
+
Autoproj.message " #{repo['repo']}, file: #{repo['file']}"
|
210
|
+
else
|
211
|
+
Autoproj.message " #{repo['repo']}"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
return if keys.empty?
|
216
|
+
|
217
|
+
Autoproj.message ' adding apt keys:'
|
218
|
+
keys.each do |key|
|
219
|
+
if key['keyserver']
|
220
|
+
Autoproj.message " id: #{key['id']}, keyserver: #{key['keyserver']}"
|
221
|
+
else
|
222
|
+
Autoproj.message " id: #{key['id']}, url: #{key['url']}"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
# Validates repositories definitions from .osrepos files
|
228
|
+
#
|
229
|
+
# Examples:
|
230
|
+
#
|
231
|
+
# - ubuntu:
|
232
|
+
# - xenial:
|
233
|
+
# type: repo
|
234
|
+
# repo: 'deb http://archive.ubuntu.com/ubuntu/ xenial main restricted'
|
235
|
+
#
|
236
|
+
# - ubuntu:
|
237
|
+
# - xenial:
|
238
|
+
# type: key
|
239
|
+
# id: 630239CC130E1A7FD81A27B140976EAF437D05B5
|
240
|
+
# keyserver: 'hkp://ha.pool.sks-keyservers.net:80'
|
241
|
+
#
|
242
|
+
# - ubuntu:
|
243
|
+
# - xenial:
|
244
|
+
# type: key
|
245
|
+
# id: D2486D2DD83DB69272AFE98867170598AF249743
|
246
|
+
# url: 'http://packages.osrfoundation.org/gazebo.key'
|
247
|
+
#
|
248
|
+
def validate_definitions(definitions)
|
249
|
+
invalid_string = 'Invalid apt repository definition'
|
250
|
+
definitions.each do |definition|
|
251
|
+
raise ConfigError, "#{invalid_string} type: #{definition['type']}" unless %w[repo key].include?(definition['type'])
|
252
|
+
|
253
|
+
if definition['type'] == 'repo'
|
254
|
+
raise ConfigError, "#{invalid_string}: 'repo' key missing" if definition['repo'].nil?
|
255
|
+
raise ConfigError, "#{invalid_string}: 'repo' should be a String" unless definition['repo'].is_a?(String)
|
256
|
+
raise ConfigError, "#{invalid_string}: 'file' should be a String" if definition['file'] && !definition['file'].is_a?(String)
|
257
|
+
if definition['file'] && Pathname.new(definition['file']).absolute?
|
258
|
+
raise ConfigError, "#{invalid_string}: 'file' should be a relative to #{File.join(SOURCES_DIR, 'sources.list.d')}"
|
259
|
+
end
|
260
|
+
else
|
261
|
+
raise ConfigError, "#{invalid_string}: 'id' key missing" if definition['id'].nil?
|
262
|
+
raise ConfigError, "#{invalid_string}: 'id' should be a String" unless definition['id'].is_a?(String)
|
263
|
+
raise ConfigError, "#{invalid_string}: 'url' conflicts with 'keyserver'" if definition['url'] && definition['keyserver']
|
264
|
+
raise ConfigError, "#{invalid_string}: 'url' should be a String" if definition['url'] && !definition['url'].is_a?(String)
|
265
|
+
raise ConfigError, "#{invalid_string}: 'keyserver' should be a String" if definition['keyserver'] && !definition['keyserver'].is_a?(String)
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def install(definitions)
|
271
|
+
super
|
272
|
+
validate_definitions(definitions)
|
273
|
+
definitions = filter_installed_definitions(definitions)
|
274
|
+
print_installing_definitions(definitions)
|
275
|
+
|
276
|
+
definitions.each do |definition|
|
277
|
+
if definition['type'] == 'repo'
|
278
|
+
add_source(definition['repo'], definition['file'])
|
279
|
+
else
|
280
|
+
type = definition['url'] ? 'url' : 'keyserver'
|
281
|
+
origin = definition[type]
|
282
|
+
add_apt_key(definition['id'], origin, type: type.to_sym)
|
283
|
+
end
|
284
|
+
end
|
285
|
+
apt_update unless definitions.empty?
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|