autoproj 1.12.6 → 1.13.0.b1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Manifest.txt +14 -0
- data/Rakefile +1 -1
- data/bin/autoproj +4 -0
- data/bin/autoproj-bootstrap +16 -0
- data/bin/autoproj-commit +10 -0
- data/bin/autoproj-list +4 -3
- data/bin/autoproj-log +5 -0
- data/bin/autoproj-reset +13 -0
- data/bin/autoproj-show +3 -1
- data/bin/autoproj-snapshot +18 -29
- data/bin/autoproj-tag +13 -0
- data/bin/autoproj-test +15 -20
- data/bin/autoproj-versions +20 -0
- data/bin/autoproj_bootstrap +149 -28
- data/bin/autoproj_bootstrap.in +1 -2
- data/lib/autoproj.rb +2 -0
- data/lib/autoproj/autobuild.rb +41 -17
- data/lib/autoproj/cli.rb +7 -0
- data/lib/autoproj/cli/reset.rb +79 -0
- data/lib/autoproj/cli/snapshot.rb +63 -0
- data/lib/autoproj/cli/tag.rb +82 -0
- data/lib/autoproj/cli/test.rb +90 -0
- data/lib/autoproj/cli/versions.rb +94 -0
- data/lib/autoproj/cmdline.rb +127 -140
- data/lib/autoproj/configuration.rb +95 -0
- data/lib/autoproj/default.osdeps +3 -0
- data/lib/autoproj/gitorious.rb +25 -37
- data/lib/autoproj/manifest.rb +46 -9
- data/lib/autoproj/ops/cache.rb +1 -1
- data/lib/autoproj/ops/configuration.rb +7 -8
- data/lib/autoproj/ops/snapshot.rb +258 -0
- data/lib/autoproj/ops/tools.rb +36 -3
- data/lib/autoproj/osdeps.rb +28 -16
- data/lib/autoproj/package_definition.rb +13 -0
- data/lib/autoproj/package_manifest.rb +35 -32
- data/lib/autoproj/package_set.rb +74 -17
- data/lib/autoproj/system.rb +23 -10
- data/lib/autoproj/test.rb +60 -0
- data/lib/autoproj/version.rb +1 -1
- data/test/ops/test_configuration.rb +20 -0
- metadata +39 -7
@@ -210,13 +210,108 @@ module Autoproj
|
|
210
210
|
end
|
211
211
|
end
|
212
212
|
|
213
|
+
# Returns true if packages and prefixes should be auto-generated, based
|
214
|
+
# on the SHA of the package names. This is meant to be used for build
|
215
|
+
# services that want to check that dependencies are properly set
|
216
|
+
#
|
217
|
+
# The default is false (disabled)
|
218
|
+
#
|
219
|
+
# @return [Boolean]
|
213
220
|
def randomize_layout?
|
214
221
|
get('randomize_layout', false)
|
215
222
|
end
|
216
223
|
|
224
|
+
# Sets whether the layout should be randomized
|
225
|
+
#
|
226
|
+
# @return [Boolean]
|
227
|
+
# @see randomize_layout?
|
217
228
|
def randomize_layout=(value)
|
218
229
|
set('randomize_layout', value, true)
|
219
230
|
end
|
231
|
+
|
232
|
+
DEFAULT_UTILITY_SETUP = Hash[
|
233
|
+
'doc' => true,
|
234
|
+
'test' => false]
|
235
|
+
|
236
|
+
# The configuration key that should be used to store the utility
|
237
|
+
# enable/disable information
|
238
|
+
#
|
239
|
+
# @param [String] the utility name
|
240
|
+
# @return [String] the config key
|
241
|
+
def utility_key(utility)
|
242
|
+
"autoproj_#{utility}_utility"
|
243
|
+
end
|
244
|
+
|
245
|
+
# Returns whether a given utility is enabled for the package
|
246
|
+
#
|
247
|
+
# If there is no specific configuration for the package, uses the global
|
248
|
+
# default set with utility_enable_all or utility_disable_all. If none of
|
249
|
+
# these methods has been called, uses the default in
|
250
|
+
# {DEFAULT_UTILITY_SETUP}
|
251
|
+
#
|
252
|
+
# @param [String] utility the utility name (e.g. 'doc' or 'test')
|
253
|
+
# @param [String] package the package name
|
254
|
+
# @return [Boolean] true if the utility should be enabled for the
|
255
|
+
# requested package and false otherwise
|
256
|
+
def utility_enabled_for?(utility, package)
|
257
|
+
utility_config = get(utility_key(utility), Hash.new)
|
258
|
+
if utility_config.has_key?(package)
|
259
|
+
utility_config[package]
|
260
|
+
else get("#{utility_key(utility)}_default", DEFAULT_UTILITY_SETUP[utility])
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
# Enables a utility for all packages
|
265
|
+
#
|
266
|
+
# This both sets the default value for all packages and resets all
|
267
|
+
# package-specific values set with {utility_enable_for} and
|
268
|
+
# {utility_disable_for}
|
269
|
+
#
|
270
|
+
# @param [String] utility the utility name (e.g. 'doc' or 'test')
|
271
|
+
# @return [void]
|
272
|
+
def utility_enable_all(utility)
|
273
|
+
reset(utility_key(utility))
|
274
|
+
set("#{utility_key(utility)}_default", true)
|
275
|
+
end
|
276
|
+
|
277
|
+
# Enables a utility for a specific package
|
278
|
+
#
|
279
|
+
# Note that if the default for this utility is to be enabled, this is
|
280
|
+
# essentially a no-op.
|
281
|
+
#
|
282
|
+
# @param [String] utility the utility name (e.g. 'doc' or 'test')
|
283
|
+
# @param [String] package the package name
|
284
|
+
# @return [void]
|
285
|
+
def utility_enable_for(utility, package)
|
286
|
+
utility_config = get(utility_key(utility), Hash.new)
|
287
|
+
set(utility_key(utility), utility_config.merge(package => true))
|
288
|
+
end
|
289
|
+
|
290
|
+
# Disables a utility for all packages
|
291
|
+
#
|
292
|
+
# This both sets the default value for all packages and resets all
|
293
|
+
# package-specific values set with {utility_enable_for} and
|
294
|
+
# {utility_disable_for}
|
295
|
+
#
|
296
|
+
# @param [String] utility the utility name (e.g. 'doc' or 'test')
|
297
|
+
# @return [void]
|
298
|
+
def utility_disable_all(utility)
|
299
|
+
reset(utility_key(utility))
|
300
|
+
set("#{utility_key(utility)}_default", false)
|
301
|
+
end
|
302
|
+
|
303
|
+
# Disables a utility for a specific package
|
304
|
+
#
|
305
|
+
# Note that if the default for this utility is to be disabled, this is
|
306
|
+
# essentially a no-op.
|
307
|
+
#
|
308
|
+
# @param [String] utility the utility name (e.g. 'doc' or 'test')
|
309
|
+
# @param [String] package the package name
|
310
|
+
# @return [void]
|
311
|
+
def utility_disable_for(utility, package)
|
312
|
+
utility_config = get(utility_key(utility), Hash.new)
|
313
|
+
set(utility_key(utility), utility_config.merge(package => false))
|
314
|
+
end
|
220
315
|
end
|
221
316
|
end
|
222
317
|
|
data/lib/autoproj/default.osdeps
CHANGED
data/lib/autoproj/gitorious.rb
CHANGED
@@ -25,51 +25,35 @@ module Autoproj
|
|
25
25
|
:http_url => "https://git.#{base_url}",
|
26
26
|
:ssh_url => "git@#{base_url}:",
|
27
27
|
:fallback_to_http => true,
|
28
|
-
:default => '
|
29
|
-
|
30
|
-
|
31
|
-
|
28
|
+
:default => 'git,ssh'
|
29
|
+
|
30
|
+
gitorious_long_doc = [
|
31
|
+
"How should I interact with #{base_url} (git, http or ssh)",
|
32
|
+
"If you give two values, comma-separated, the first one will be",
|
33
|
+
"used for pulling and the second one for pushing"]
|
32
34
|
|
33
35
|
access_methods = Hash[
|
34
36
|
'git' => 'git,ssh',
|
35
37
|
'ssh' => 'ssh,ssh',
|
36
38
|
'http' => 'http,http']
|
37
39
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
if !access_methods.has_key?(method)
|
47
|
-
raise Autoproj::InputError, "#{method} is not a known access method"
|
48
|
-
elsif disabled_methods.include?(method)
|
49
|
-
raise Autoproj::InputError, "#{method} is disabled on #{base_url}"
|
40
|
+
configuration_option name, 'string',
|
41
|
+
:default => options[:default],
|
42
|
+
:doc => gitorious_long_doc do |value|
|
43
|
+
if value =~ /,/
|
44
|
+
value.split(',').each do |method|
|
45
|
+
if !access_methods.has_key?(method)
|
46
|
+
raise Autoproj::InputError, "#{method} is not a known access method"
|
47
|
+
end
|
50
48
|
end
|
49
|
+
elsif !access_methods.has_key?(value)
|
50
|
+
raise Autoproj::InputError, "#{value} is not a known access method"
|
51
51
|
end
|
52
|
-
elsif !access_methods.has_key?(value)
|
53
|
-
raise Autoproj::InputError, "#{value} is not a known access method"
|
54
|
-
elsif disabled_methods.include?(value)
|
55
|
-
raise Autoproj::InputError, "#{method} is disabled on #{base_url}"
|
56
|
-
end
|
57
|
-
|
58
|
-
value
|
59
|
-
end
|
60
52
|
|
61
|
-
|
62
|
-
|
63
|
-
:doc => gitorious_long_doc, &validator
|
53
|
+
value
|
54
|
+
end
|
64
55
|
|
65
|
-
access_mode = Autoproj.
|
66
|
-
begin
|
67
|
-
validator[access_mode]
|
68
|
-
rescue Autoproj::InputError => e
|
69
|
-
Autoproj.warn e.message
|
70
|
-
Autoproj.config.reset(name)
|
71
|
-
access_mode = Autoproj.config.get(name)
|
72
|
-
end
|
56
|
+
access_mode = Autoproj.user_config(name)
|
73
57
|
access_mode = access_methods[access_mode] || access_mode
|
74
58
|
pull, push = access_mode.split(',')
|
75
59
|
[[pull, "_ROOT"], [push, "_PUSH_ROOT"]].each do |method, var_suffix|
|
@@ -89,11 +73,15 @@ module Autoproj
|
|
89
73
|
end
|
90
74
|
pull_base_url = Autoproj.user_config("#{name}_ROOT")
|
91
75
|
push_base_url = Autoproj.user_config("#{name}_PUSH_ROOT")
|
92
|
-
Hash[:
|
76
|
+
Hash[type: 'git',
|
77
|
+
url: "#{pull_base_url}#{url}",
|
78
|
+
push_to: "#{push_base_url}#{url}",
|
79
|
+
retry_count: 10,
|
80
|
+
repository_id: "#{name.downcase}:#{url}"].merge(vcs_options)
|
93
81
|
end
|
94
82
|
end
|
95
83
|
end
|
96
84
|
|
97
|
-
Autoproj.gitorious_server_configuration('GITORIOUS', 'gitorious.org'
|
85
|
+
Autoproj.gitorious_server_configuration('GITORIOUS', 'gitorious.org')
|
98
86
|
Autoproj.gitorious_server_configuration('GITHUB', 'github.com', :http_url => 'https://github.com', :default => 'http,ssh')
|
99
87
|
|
data/lib/autoproj/manifest.rb
CHANGED
@@ -40,7 +40,8 @@ module Autoproj
|
|
40
40
|
# @return [Array<PackageSet>]
|
41
41
|
attr_writer :package_sets
|
42
42
|
|
43
|
-
# Returns true if +pkg_name+ has been explicitely selected
|
43
|
+
# Returns true if +pkg_name+ has been explicitely selected, either by
|
44
|
+
# the command line or through the layout
|
44
45
|
def explicitly_selected_package?(pkg_name)
|
45
46
|
explicit_selection && explicit_selection.include?(pkg_name)
|
46
47
|
end
|
@@ -65,8 +66,14 @@ module Autoproj
|
|
65
66
|
|
66
67
|
@file = file
|
67
68
|
@data = data
|
68
|
-
@ignored_packages |= (data['ignored_packages'] || Set.new)
|
69
|
-
data['exclude_packages']
|
69
|
+
@ignored_packages |= (data['ignored_packages'] || Set.new).to_set
|
70
|
+
@manifest_exclusions |= (data['exclude_packages'] || Set.new).to_set
|
71
|
+
|
72
|
+
@normalized_layout = Hash.new
|
73
|
+
compute_normalized_layout(
|
74
|
+
normalized_layout,
|
75
|
+
'/',
|
76
|
+
data['layout'] || Hash.new)
|
70
77
|
|
71
78
|
if data['constants']
|
72
79
|
@constant_definitions = Autoproj.resolve_constant_definitions(data['constants'])
|
@@ -128,6 +135,7 @@ module Autoproj
|
|
128
135
|
@ignored_os_dependencies = Set.new
|
129
136
|
@reused_installations = Array.new
|
130
137
|
@ignored_packages = Set.new
|
138
|
+
@manifest_exclusions = Set.new
|
131
139
|
|
132
140
|
@constant_definitions = Hash.new
|
133
141
|
if Autoproj.has_config_key?('manifest_source')
|
@@ -139,7 +147,7 @@ module Autoproj
|
|
139
147
|
# Call this method to ignore a specific package. It must not be used in
|
140
148
|
# init.rb, as the manifest is not yet loaded then
|
141
149
|
def ignore_package(package_name)
|
142
|
-
@ignored_packages << package_name
|
150
|
+
@ignored_packages << package_name.to_str
|
143
151
|
end
|
144
152
|
|
145
153
|
# True if the given package should not be built, with the packages that
|
@@ -185,7 +193,7 @@ module Autoproj
|
|
185
193
|
# The set of package names that are listed in the excluded_packages
|
186
194
|
# section of the manifest
|
187
195
|
def manifest_exclusions
|
188
|
-
|
196
|
+
@manifest_exclusions
|
189
197
|
end
|
190
198
|
|
191
199
|
# A package_name => reason map of the exclusions added with #add_exclusion.
|
@@ -198,6 +206,17 @@ module Autoproj
|
|
198
206
|
automatic_exclusions[package_name] = reason
|
199
207
|
end
|
200
208
|
|
209
|
+
# Tests whether the given package is excluded in the manifest
|
210
|
+
def excluded_in_manifest?(package_name)
|
211
|
+
manifest_exclusions.any? do |matcher|
|
212
|
+
if (pkg_set = metapackages[matcher]) && pkg_set.include?(package_name)
|
213
|
+
true
|
214
|
+
else
|
215
|
+
Regexp.new(matcher) === package_name
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
201
220
|
# If +package_name+ is excluded from the build, returns a string that
|
202
221
|
# tells why. Otherwise, returns nil
|
203
222
|
#
|
@@ -205,7 +224,7 @@ module Autoproj
|
|
205
224
|
# exclude_packages section of the manifest, or because they are
|
206
225
|
# disabled on this particular operating system.
|
207
226
|
def exclusion_reason(package_name)
|
208
|
-
if
|
227
|
+
if excluded_in_manifest?(package_name)
|
209
228
|
"#{package_name} is listed in the exclude_packages section of the manifest"
|
210
229
|
else
|
211
230
|
automatic_exclusions[package_name]
|
@@ -218,7 +237,11 @@ module Autoproj
|
|
218
237
|
# This is useful to avoid building packages that are of no use for the
|
219
238
|
# user.
|
220
239
|
def excluded?(package_name)
|
221
|
-
|
240
|
+
package_name = package_name.to_str
|
241
|
+
|
242
|
+
if normalized_layout.has_key?(package_name)
|
243
|
+
false
|
244
|
+
elsif excluded_in_manifest?(package_name)
|
222
245
|
true
|
223
246
|
elsif automatic_exclusions.any? { |pkg_name, | pkg_name == package_name }
|
224
247
|
true
|
@@ -375,6 +398,12 @@ module Autoproj
|
|
375
398
|
packages[name]
|
376
399
|
end
|
377
400
|
|
401
|
+
def find_autobuild_package(name)
|
402
|
+
if pkg = packages[name]
|
403
|
+
pkg.autobuild
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
378
407
|
def package(name)
|
379
408
|
packages[name]
|
380
409
|
end
|
@@ -500,6 +529,10 @@ module Autoproj
|
|
500
529
|
set
|
501
530
|
end
|
502
531
|
|
532
|
+
def main_package_set
|
533
|
+
each_package_set.find(&:main?)
|
534
|
+
end
|
535
|
+
|
503
536
|
# Exception raised when a caller requires to use an excluded package
|
504
537
|
class ExcludedPackage < ConfigError
|
505
538
|
attr_reader :name
|
@@ -813,7 +846,11 @@ module Autoproj
|
|
813
846
|
end
|
814
847
|
end
|
815
848
|
|
816
|
-
|
849
|
+
# A mapping from names to layout placement, as found in the layout
|
850
|
+
# section of the manifest
|
851
|
+
attr_reader :normalized_layout
|
852
|
+
|
853
|
+
def compute_normalized_layout(result, layout_level, layout_data)
|
817
854
|
layout_data.each do |value|
|
818
855
|
if value.kind_of?(Hash)
|
819
856
|
subname, subdef = value.find { true }
|
@@ -877,7 +914,7 @@ module Autoproj
|
|
877
914
|
pkg.autobuild.description = manifest
|
878
915
|
package_manifests[package.name] = manifest
|
879
916
|
|
880
|
-
manifest.each_dependency do |name, is_optional|
|
917
|
+
manifest.each_dependency(pkg.modes) do |name, is_optional|
|
881
918
|
begin
|
882
919
|
if is_optional
|
883
920
|
package.optional_dependency name
|
data/lib/autoproj/ops/cache.rb
CHANGED
@@ -37,7 +37,7 @@ module Autoproj
|
|
37
37
|
FileUtils.mkdir_p File.dirname(pkg.importdir)
|
38
38
|
Autobuild::Subprocess.run("autoproj-cache", "import", Autobuild.tool(:git), "--git-dir", pkg.importdir, 'init', "--bare")
|
39
39
|
end
|
40
|
-
pkg.importer.update_remotes_configuration(pkg
|
40
|
+
pkg.importer.update_remotes_configuration(pkg)
|
41
41
|
|
42
42
|
with_retry(10) do
|
43
43
|
Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'remote', 'update', 'autobuild')
|
@@ -96,7 +96,7 @@ module Autoproj
|
|
96
96
|
fake_package.update = false
|
97
97
|
end
|
98
98
|
end
|
99
|
-
fake_package.import(only_local)
|
99
|
+
fake_package.import(only_local: only_local)
|
100
100
|
|
101
101
|
rescue Autobuild::ConfigException => e
|
102
102
|
raise ConfigError.new, "cannot import #{name}: #{e.message}", e.backtrace
|
@@ -177,9 +177,11 @@ module Autoproj
|
|
177
177
|
pkg_set
|
178
178
|
end
|
179
179
|
|
180
|
-
def queue_auto_imports_if_needed(queue, pkg_set)
|
180
|
+
def queue_auto_imports_if_needed(queue, pkg_set, root_set)
|
181
181
|
if pkg_set.auto_imports?
|
182
182
|
pkg_set.each_raw_imported_set do |import_vcs, import_options|
|
183
|
+
repository_id = repository_id_of(import_vcs)
|
184
|
+
import_vcs = root_set.overrides_for("pkg_set:#{repository_id}", import_vcs)
|
183
185
|
queue << [import_vcs, import_options, pkg_set]
|
184
186
|
end
|
185
187
|
end
|
@@ -191,10 +193,7 @@ module Autoproj
|
|
191
193
|
return "local:#{vcs.url}"
|
192
194
|
end
|
193
195
|
|
194
|
-
|
195
|
-
raw_local_dir = PackageSet.raw_local_dir_of(vcs)
|
196
|
-
fake_package = Tools.create_autobuild_package(vcs, name, raw_local_dir)
|
197
|
-
fake_package.importer.repository_id
|
196
|
+
vcs.create_autobuild_importer.repository_id
|
198
197
|
end
|
199
198
|
|
200
199
|
# Load the package set information
|
@@ -210,7 +209,7 @@ module Autoproj
|
|
210
209
|
by_repository_id = Hash.new
|
211
210
|
by_name = Hash.new
|
212
211
|
|
213
|
-
queue = queue_auto_imports_if_needed(Array.new, root_pkg_set)
|
212
|
+
queue = queue_auto_imports_if_needed(Array.new, root_pkg_set, root_pkg_set)
|
214
213
|
while !queue.empty?
|
215
214
|
vcs, options, imported_from = queue.shift
|
216
215
|
repository_id = repository_id_of(vcs)
|
@@ -258,7 +257,7 @@ module Autoproj
|
|
258
257
|
by_name[pkg_set.name] = [pkg_set, vcs, options, imported_from]
|
259
258
|
|
260
259
|
# Finally, queue the imports
|
261
|
-
queue_auto_imports_if_needed(queue, pkg_set)
|
260
|
+
queue_auto_imports_if_needed(queue, pkg_set, root_pkg_set)
|
262
261
|
end
|
263
262
|
|
264
263
|
cleanup_remotes_dir(package_sets)
|
@@ -0,0 +1,258 @@
|
|
1
|
+
module Autoproj
|
2
|
+
module Ops
|
3
|
+
class Snapshot
|
4
|
+
# Update version control information with new choices
|
5
|
+
#
|
6
|
+
# The two parameters are formatted as expected in the version_control
|
7
|
+
# and overrides fields in source.yml / overrides.yml, that is (in YAML)
|
8
|
+
#
|
9
|
+
# - package_name:
|
10
|
+
# version: '10'
|
11
|
+
# control: '20'
|
12
|
+
# info: '30'
|
13
|
+
#
|
14
|
+
# The two parameters are expected to only use full package names, and
|
15
|
+
# not regular expressions
|
16
|
+
#
|
17
|
+
# @param [Array<String=>Hash>] overrides the information that should augment
|
18
|
+
# the current state
|
19
|
+
# @param [Array<String=>Hash>] state the current state
|
20
|
+
# @param [Hash] the updated information
|
21
|
+
def self.merge_packets( overrides, state )
|
22
|
+
result = overrides.dup
|
23
|
+
overriden = overrides.map { |entry| entry.keys.first }.to_set
|
24
|
+
state.each do |pkg|
|
25
|
+
name, _ = pkg.first
|
26
|
+
if !overriden.include?(name)
|
27
|
+
result << pkg
|
28
|
+
end
|
29
|
+
end
|
30
|
+
result
|
31
|
+
end
|
32
|
+
|
33
|
+
def sort_versions(versions)
|
34
|
+
pkg_sets, pkgs = versions.partition { |n, _| n =~ /^pkg_set:/ }
|
35
|
+
pkg_sets.sort_by { |n, _| n.keys.first } +
|
36
|
+
pkgs.sort_by { |n, _| n.keys.first }
|
37
|
+
end
|
38
|
+
|
39
|
+
def save_versions( versions, versions_file, options = Hash.new )
|
40
|
+
options = Kernel.validate_options options,
|
41
|
+
replace: false
|
42
|
+
|
43
|
+
existing_versions = Array.new
|
44
|
+
if !options[:replace] && File.exists?(versions_file)
|
45
|
+
existing_versions = YAML.load( File.read( versions_file ) ) ||
|
46
|
+
Array.new
|
47
|
+
end
|
48
|
+
|
49
|
+
# create direcotry for versions file first
|
50
|
+
FileUtils.mkdir_p(File.dirname( versions_file ))
|
51
|
+
|
52
|
+
# augment the versions file with the updated versions
|
53
|
+
Snapshot.merge_packets( versions, existing_versions )
|
54
|
+
|
55
|
+
versions = sort_versions(versions)
|
56
|
+
|
57
|
+
# write the yaml file
|
58
|
+
File.open(versions_file, 'w') do |io|
|
59
|
+
io.write YAML.dump(versions)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.snapshot( packages, target_dir )
|
64
|
+
# todo
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :manifest
|
68
|
+
|
69
|
+
# Control what happens if a package fails to be snapshotted
|
70
|
+
#
|
71
|
+
# If true, the failure to snapshot a package should lead to a warning.
|
72
|
+
# Otherwise (the default), it leads to an error.
|
73
|
+
#
|
74
|
+
# @return [Boolean]
|
75
|
+
# @see initialize error_or_warn
|
76
|
+
def keep_going?; !!@keep_going end
|
77
|
+
|
78
|
+
def initialize(manifest, options = Hash.new)
|
79
|
+
@manifest = manifest
|
80
|
+
options = Kernel.validate_options options,
|
81
|
+
keep_going: false
|
82
|
+
@keep_going = options[:keep_going]
|
83
|
+
end
|
84
|
+
|
85
|
+
def snapshot_package_sets(target_dir = nil)
|
86
|
+
result = Array.new
|
87
|
+
manifest.each_package_set do |pkg_set|
|
88
|
+
next if pkg_set.local?
|
89
|
+
|
90
|
+
if vcs_info = pkg_set.snapshot(target_dir)
|
91
|
+
result << Hash["pkg_set:#{pkg_set.repository_id}", vcs_info]
|
92
|
+
else
|
93
|
+
error_or_warn(pkg_set, "cannot snapshot #{package_name}: importer snapshot failed")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
result
|
97
|
+
end
|
98
|
+
|
99
|
+
def error_or_warn(package, error_msg)
|
100
|
+
if keep_going?
|
101
|
+
Autoproj.warn error_msg
|
102
|
+
else
|
103
|
+
raise Autobuild::PackageException.new(package, 'snapshot'), error_msg
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def snapshot_packages(packages, target_dir = nil)
|
108
|
+
result = Array.new
|
109
|
+
packages.each do |package_name|
|
110
|
+
package = manifest.packages[package_name]
|
111
|
+
if !package
|
112
|
+
raise ArgumentError, "#{package_name} is not a known package"
|
113
|
+
end
|
114
|
+
importer = package.autobuild.importer
|
115
|
+
if !importer
|
116
|
+
error_or_warn(package, "cannot snapshot #{package_name} as it has no importer")
|
117
|
+
next
|
118
|
+
elsif !importer.respond_to?(:snapshot)
|
119
|
+
error_or_warn(package, "cannot snapshot #{package_name} as the #{importer.class} importer does not support it")
|
120
|
+
next
|
121
|
+
end
|
122
|
+
|
123
|
+
vcs_info = importer.snapshot(package.autobuild, target_dir)
|
124
|
+
if vcs_info
|
125
|
+
result << Hash[package_name, vcs_info]
|
126
|
+
else
|
127
|
+
error_or_warn(package, "cannot snapshot #{package_name}: importer snapshot failed")
|
128
|
+
end
|
129
|
+
end
|
130
|
+
result
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the list of existing version tags
|
134
|
+
def tags(package)
|
135
|
+
importer = package.importer
|
136
|
+
all_tags = importer.run_git_bare(package, 'tag')
|
137
|
+
all_tags.find_all do |tag_name|
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns a package that is used to store this installs import history
|
142
|
+
#
|
143
|
+
# Its importer is guaranteed to be a git importer
|
144
|
+
#
|
145
|
+
# @return [Autobuild::Package] a package whose importer is
|
146
|
+
# {Autobuild::Git}
|
147
|
+
def import_state_log_package
|
148
|
+
manifest.main_package_set.create_autobuild_package
|
149
|
+
end
|
150
|
+
|
151
|
+
def import_state_log_ref
|
152
|
+
"refs/autoproj"
|
153
|
+
end
|
154
|
+
|
155
|
+
DEFAULT_VERSIONS_FILE_BASENAME = "50-versions.yml"
|
156
|
+
|
157
|
+
def import_state_log_file
|
158
|
+
File.join(OVERRIDES_DIR, DEFAULT_VERSIONS_FILE_BASENAME)
|
159
|
+
end
|
160
|
+
|
161
|
+
def current_import_state
|
162
|
+
main = import_state_log_package
|
163
|
+
# Try to resolve the log ref, and extract the version file from it
|
164
|
+
begin
|
165
|
+
yaml = main.importer.show(main, import_state_log_ref, import_state_log_file)
|
166
|
+
YAML.load(yaml) || Array.new
|
167
|
+
rescue Autobuild::PackageException
|
168
|
+
Array.new
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def update_package_import_state(name, packages)
|
173
|
+
current_versions = current_import_state
|
174
|
+
if current_versions.empty?
|
175
|
+
# Do a full snapshot this time only
|
176
|
+
Autoproj.message " building initial autoproj import log, this may take a while"
|
177
|
+
packages = manifest.all_selected_packages.
|
178
|
+
find_all { |pkg| File.directory?(manifest.find_package(pkg).autobuild.srcdir) }
|
179
|
+
end
|
180
|
+
versions = snapshot_package_sets
|
181
|
+
versions += snapshot_packages(packages)
|
182
|
+
versions = Snapshot.merge_packets(versions, current_versions)
|
183
|
+
save_import_state(name, versions)
|
184
|
+
end
|
185
|
+
|
186
|
+
def save_import_state(name, versions)
|
187
|
+
versions = sort_versions(versions)
|
188
|
+
|
189
|
+
main = import_state_log_package
|
190
|
+
git_dir = main.importer.git_dir(main, false)
|
191
|
+
# Ensure that our ref is being logged
|
192
|
+
FileUtils.touch File.join(git_dir, 'logs', *import_state_log_ref.split("/"))
|
193
|
+
# Create the commit with the versions info
|
194
|
+
commit_id = Snapshot.create_commit(main, import_state_log_file, name) do |io|
|
195
|
+
YAML.dump(versions, io)
|
196
|
+
end
|
197
|
+
# And save it in our reflog
|
198
|
+
main.importer.run_git_bare(main, "update-ref", '-m', name, import_state_log_ref, commit_id)
|
199
|
+
end
|
200
|
+
|
201
|
+
# Create a git commit in which a file contains provided content
|
202
|
+
#
|
203
|
+
# The target git repository's current index and history is left
|
204
|
+
# unmodified. The only modification is the creation of a new dangling
|
205
|
+
# commit.
|
206
|
+
#
|
207
|
+
# It creates a temporary file and gives it to the block so that the file
|
208
|
+
# gets filled with the new content
|
209
|
+
#
|
210
|
+
# @yieldparam [Tempfile] io a temporary file
|
211
|
+
# @param [Autobuild::Package] a package object whose importer is a git
|
212
|
+
# importer. The git commit is created in this repository
|
213
|
+
# @param [String] path the file to be created or updated, relative to
|
214
|
+
# the root of the git repository
|
215
|
+
# @param [String] the commit message
|
216
|
+
# @return [String] the commit ID
|
217
|
+
def self.create_commit(pkg, path, message)
|
218
|
+
importer = pkg.importer
|
219
|
+
object_id = Tempfile.open 'autoproj-versions' do |io|
|
220
|
+
yield(io)
|
221
|
+
io.flush
|
222
|
+
importer.run_git_bare(
|
223
|
+
pkg, 'hash-object', '-w',
|
224
|
+
'--path', path, io.path).first
|
225
|
+
end
|
226
|
+
|
227
|
+
cacheinfo = ["100644", object_id, path]
|
228
|
+
if Autobuild::Git.at_least_version(2, 1)
|
229
|
+
cacheinfo = cacheinfo.join(",")
|
230
|
+
end
|
231
|
+
|
232
|
+
# Create the tree using a temporary index in order to not mess with
|
233
|
+
# the user's index state. read-tree initializes the new index and
|
234
|
+
# then we add the overrides file with update-index / write-tree
|
235
|
+
our_index = File.join(importer.git_dir(pkg, false), 'index.autoproj')
|
236
|
+
FileUtils.rm_f our_index
|
237
|
+
begin
|
238
|
+
ENV['GIT_INDEX_FILE'] = our_index
|
239
|
+
importer.run_git_bare(pkg, 'read-tree', 'HEAD')
|
240
|
+
# And add the new file
|
241
|
+
importer.run_git_bare(
|
242
|
+
pkg, 'update-index',
|
243
|
+
'--add', '--cacheinfo', *cacheinfo)
|
244
|
+
tree_id = importer.run_git_bare(pkg, 'write-tree').first
|
245
|
+
ensure
|
246
|
+
ENV.delete('GIT_INDEX_FILE')
|
247
|
+
FileUtils.rm_f our_index
|
248
|
+
end
|
249
|
+
|
250
|
+
head_id = importer.rev_parse(pkg, 'HEAD')
|
251
|
+
|
252
|
+
importer.run_git_bare(
|
253
|
+
pkg, 'commit-tree',
|
254
|
+
tree_id, '-p', head_id, input_streams: [message]).first
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
end
|