autoproj 1.12.6 → 1.13.0.b1
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/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
|