autoproj 1.10.2 → 1.11.0.b1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Manifest.txt +9 -0
  3. data/Rakefile +4 -0
  4. data/bin/aup +5 -1
  5. data/bin/autolocate +1 -82
  6. data/bin/autoproj +6 -56
  7. data/bin/autoproj-bootstrap +31 -3
  8. data/bin/autoproj-cache +3 -60
  9. data/bin/autoproj-clean +1 -1
  10. data/bin/autoproj-create-set +0 -0
  11. data/bin/autoproj-doc +1 -1
  12. data/bin/autoproj-envsh +0 -0
  13. data/bin/autoproj-list +1 -1
  14. data/bin/autoproj-locate +17 -16
  15. data/bin/autoproj-query +0 -0
  16. data/bin/autoproj-show +0 -0
  17. data/bin/autoproj-switch-config +23 -0
  18. data/bin/autoproj-test +2 -2
  19. data/bin/autoproj_bootstrap +354 -210
  20. data/bin/autoproj_bootstrap.in +8 -0
  21. data/bin/autoproj_stress_test +1 -1
  22. data/lib/autoproj.rb +7 -0
  23. data/lib/autoproj/autobuild.rb +14 -35
  24. data/lib/autoproj/build_option.rb +104 -0
  25. data/lib/autoproj/cmdline.rb +62 -355
  26. data/lib/autoproj/configuration.rb +161 -0
  27. data/lib/autoproj/gitorious.rb +31 -20
  28. data/lib/autoproj/installation_manifest.rb +7 -1
  29. data/lib/autoproj/manifest.rb +124 -342
  30. data/lib/autoproj/ops/build.rb +107 -0
  31. data/lib/autoproj/ops/cache.rb +82 -0
  32. data/lib/autoproj/ops/configuration.rb +302 -0
  33. data/lib/autoproj/ops/loader.rb +97 -0
  34. data/lib/autoproj/ops/main_config_switcher.rb +271 -0
  35. data/lib/autoproj/ops/tools.rb +54 -0
  36. data/lib/autoproj/options.rb +26 -178
  37. data/lib/autoproj/osdeps.rb +49 -9
  38. data/lib/autoproj/package_set.rb +168 -87
  39. data/lib/autoproj/system.rb +6 -23
  40. data/lib/autoproj/variable_expansion.rb +0 -1
  41. data/lib/autoproj/vcs_definition.rb +23 -0
  42. data/lib/autoproj/version.rb +1 -1
  43. metadata +17 -7
@@ -0,0 +1,107 @@
1
+ module Autoproj
2
+ module Ops
3
+ # Operations related to building packages
4
+ #
5
+ # Note that these do not perform import or osdeps installation. It is
6
+ # assumed that the packages that should be built have been cleanly
7
+ # imported
8
+ class Build
9
+ # The manifest on which we operate
10
+ # @return [Manifest]
11
+ attr_reader :manifest
12
+ # Whether we should update the OS dependencies before building. It
13
+ # controls the behaviour of {rebuild_all} as well as
14
+ # {build_packages}
15
+ attr_predicate :update_os_dependencies?, true
16
+
17
+ def initialize(manifest, update_os_dependencies = true)
18
+ @manifest = manifest
19
+ self.update_os_dependencies = update_os_dependencies
20
+ end
21
+
22
+ # Triggers a rebuild of all packages
23
+ #
24
+ # It rebuilds (i.e. does a clean + build) of all packages declared
25
+ # in the manifest's layout. It also performs a reinstall of all
26
+ # non-OS-specific managers that support it (e.g. RubyGems) if
27
+ # {update_os_dependencies?} is set to true (the default)
28
+ def rebuild_all
29
+ if update_os_dependencies?
30
+ # We also reinstall the osdeps that provide the
31
+ # functionality
32
+ managers = manifest.osdeps.setup_package_handlers
33
+ managers.each do |mng|
34
+ if mng.respond_to?(:reinstall)
35
+ mng.reinstall
36
+ end
37
+ end
38
+ end
39
+
40
+ packages = manifest.all_layout_packages
41
+ rebuild_packages(packages, packages)
42
+ end
43
+
44
+ # Triggers a rebuild of a subset of all packages
45
+ #
46
+ # @param [Array<String>] selected_packages the list of package names
47
+ # that should be rebuilt
48
+ # @param [Array<String>] all_enabled_packages the list of package names
49
+ # for which a build should be triggered (usually selected_packages
50
+ # plus dependencies)
51
+ # @return [void]
52
+ def rebuild_packages(selected_packages, all_enabled_packages)
53
+ selected_packages.each do |pkg_name|
54
+ Autobuild::Package[pkg_name].prepare_for_rebuild
55
+ end
56
+ build_packages(all_enabled_packages)
57
+ end
58
+
59
+ # Triggers a force-build of all packages
60
+ #
61
+ # Unlike a rebuild, a force-build forces the package to go through
62
+ # all build steps (even if they are not needed) but does not clean
63
+ # the current build byproducts beforehand
64
+ #
65
+ def force_build_all
66
+ packages = manifest.all_layout_packages
67
+ rebuild_packages(packages, packages)
68
+ end
69
+
70
+ # Triggers a force-build of a subset of all packages
71
+ #
72
+ # Unlike a rebuild, a force-build forces the package to go through
73
+ # all build steps (even if they are not needed) but does not clean
74
+ # the current build byproducts beforehand
75
+ #
76
+ # This method force-builds of all packages declared
77
+ # in the manifest's layout
78
+ #
79
+ # @param [Array<String>] selected_packages the list of package names
80
+ # that should be rebuilt
81
+ # @param [Array<String>] all_enabled_packages the list of package names
82
+ # for which a build should be triggered (usually selected_packages
83
+ # plus dependencies)
84
+ # @return [void]
85
+ def force_build_packages(selected_packages, all_enabled_packages)
86
+ selected_packages.each do |pkg_name|
87
+ Autobuild::Package[pkg_name].prepare_for_forced_build
88
+ end
89
+ build_packages(all_enabled_packages)
90
+ end
91
+
92
+ # Builds the listed packages
93
+ #
94
+ # Only build steps that are actually needed will be performed. See
95
+ # {force_build_packages} and {rebuild_packages} to override this
96
+ #
97
+ # @param [Array<String>] all_enabled_packages the list of package
98
+ # names of the packages that should be rebuilt
99
+ # @return [void]
100
+ def build_packages(all_enabled_packages)
101
+ Autobuild.do_rebuild = false
102
+ Autobuild.do_forced_build = false
103
+ Autobuild.apply(all_enabled_packages, "autoproj-build", ['build'])
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,82 @@
1
+ module Autoproj
2
+ module Ops
3
+ class Cache
4
+ attr_reader :cache_dir
5
+ attr_reader :manifest
6
+
7
+ def initialize(cache_dir, manifest)
8
+ @cache_dir = cache_dir
9
+ @manifest = manifest
10
+ end
11
+
12
+ def with_retry(count)
13
+ (count + 1).times do |i|
14
+ begin
15
+ break yield
16
+ rescue Autobuild::SubcommandFailed
17
+ if i == count
18
+ raise
19
+ else
20
+ Autobuild.message " failed, retrying (#{i}/#{count})"
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ def git_cache_dir
27
+ File.join(cache_dir, 'git')
28
+ end
29
+
30
+ def cache_git(pkg)
31
+ pkg.importdir = File.join(git_cache_dir, pkg.name)
32
+ pkg.importer.local_branch = nil
33
+ pkg.importer.remote_branch = nil
34
+ pkg.importer.remote_name = 'autobuild'
35
+
36
+ if !File.directory?(pkg.importdir)
37
+ FileUtils.mkdir_p File.dirname(pkg.importdir)
38
+ Autobuild::Subprocess.run("autoproj-cache", "import", Autobuild.tool(:git), "--git-dir", pkg.importdir, 'init', "--bare")
39
+ end
40
+ pkg.importer.update_remotes_configuration(pkg, 'autoproj-cache')
41
+
42
+ with_retry(10) do
43
+ Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'remote', 'update', 'autobuild')
44
+ end
45
+ Autobuild::Subprocess.run('autoproj-cache', :import, Autobuild.tool('git'), '--git-dir', pkg.importdir, 'gc', '--prune=all')
46
+ end
47
+
48
+ def archive_cache_dir
49
+ File.join(cache_dir, 'archives')
50
+ end
51
+
52
+ def cache_archive(pkg)
53
+ pkg.importer.cachedir = archive_cache_dir
54
+ with_retry(10) do
55
+ pkg.importer.update_cache(pkg)
56
+ end
57
+ end
58
+
59
+ def create_or_update
60
+ FileUtils.mkdir_p cache_dir
61
+
62
+ packages = manifest.each_autobuild_package.
63
+ sort_by(&:name)
64
+ total = packages.size
65
+ Autoproj.message "Handling #{total} packages"
66
+ packages.each_with_index do |pkg, i|
67
+ case pkg.importer
68
+ when Autobuild::Git
69
+ Autoproj.message " [#{i}/#{total}] caching #{pkg.name} (git)"
70
+ cache_git(pkg)
71
+ when Autobuild::ArchiveImporter
72
+ Autoproj.message " [#{i}/#{total}] caching #{pkg.name} (archive)"
73
+ cache_archive(pkg)
74
+ else
75
+ Autoproj.message " [#{i}/#{total}] not caching #{pkg.name} (cannot cache #{pkg.importer.class})"
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
82
+
@@ -0,0 +1,302 @@
1
+ module Autoproj
2
+ module Ops
3
+ #--
4
+ # NOTE: indentation is wrong to let git track the history properly
5
+ #+++
6
+
7
+ # Implementation of the operations to manage the configuration
8
+ class Configuration
9
+ # The manifest object that represents the autoproj configuration
10
+ #
11
+ # @return [Manifest]
12
+ attr_reader :manifest
13
+
14
+ # The loader object that should be used to load files such as init.rb
15
+ attr_reader :loader
16
+
17
+ # The main configuration directory
18
+ #
19
+ # @return [String]
20
+ attr_reader :config_dir
21
+
22
+ # The autoproj install we should update from (if any)
23
+ #
24
+ # @return [nil,InstallationManifest]
25
+ attr_reader :update_from
26
+
27
+ # The object that allows us to install OS dependencies
28
+ def osdeps
29
+ Autoproj.osdeps
30
+ end
31
+
32
+ # The path in which remote package sets should be exposed to the
33
+ # user
34
+ #
35
+ # @return [String]
36
+ def remotes_dir
37
+ Autoproj.remotes_dir
38
+ end
39
+
40
+ # The path in which remote package sets should be exposed to the
41
+ # user
42
+ #
43
+ # @return [String]
44
+ def remotes_user_dir
45
+ File.join(config_dir, "remotes")
46
+ end
47
+
48
+ # @param [Manifest] manifest
49
+ # @param [Loader] loader
50
+ # @option options [InstallationManifest] :update_from
51
+ # (CmdLine.update_from) another autoproj installation from which we
52
+ # should update (instead of the normal VCS)
53
+ def initialize(manifest, loader, options = Hash.new)
54
+ options = Kernel.validate_options options,
55
+ :update_from => CmdLine.update_from
56
+ @manifest = manifest
57
+ @loader = loader
58
+ @update_from = options[:update_from]
59
+ @config_dir = Autoproj.config_dir
60
+ @remote_update_message_displayed = false
61
+ end
62
+
63
+ # Imports or updates a source (remote or otherwise).
64
+ #
65
+ # See create_autobuild_package for informations about the arguments.
66
+ def self.update_configuration_repository(vcs, name, into, options = Hash.new)
67
+ options = Kernel.validate_options options, update_from: nil, only_local: false
68
+ update_from, only_local = options.values_at(:update_from, :only_local)
69
+
70
+ fake_package = Tools.create_autobuild_package(vcs, name, into)
71
+ if update_from
72
+ # Define a package in the installation manifest that points to
73
+ # the desired folder in other_root
74
+ relative_path = Pathname.new(into).
75
+ relative_path_from(Pathname.new(Autoproj.root_dir)).to_s
76
+ other_dir = File.join(update_from.path, relative_path)
77
+ if File.directory?(other_dir)
78
+ update_from.packages.unshift(
79
+ InstallationManifest::Package.new(fake_package.name, other_dir, File.join(other_dir, 'install')))
80
+ end
81
+
82
+ # Then move the importer there if possible
83
+ if fake_package.importer.respond_to?(:pick_from_autoproj_root)
84
+ if !fake_package.importer.pick_from_autoproj_root(fake_package, other_root)
85
+ fake_package.update = false
86
+ end
87
+ else
88
+ fake_package.update = false
89
+ end
90
+ end
91
+ fake_package.import(only_local)
92
+
93
+ rescue Autobuild::ConfigException => e
94
+ raise ConfigError.new, "cannot import #{name}: #{e.message}", e.backtrace
95
+ end
96
+
97
+ # Update the main configuration repository
98
+ #
99
+ # @return [Boolean] true if something got updated or checked out,
100
+ # and false otherwise
101
+ def update_main_configuration(only_local = false)
102
+ self.class.update_configuration_repository(
103
+ manifest.vcs,
104
+ "autoproj main configuration",
105
+ config_dir,
106
+ update_from: update_from,
107
+ only_local: only_local)
108
+ end
109
+
110
+ # Update or checkout a remote package set, based on its VCS definition
111
+ #
112
+ # @param [VCSDefinition] vcs the package set VCS
113
+ # @return [Boolean] true if something got updated or checked out,
114
+ # and false otherwise
115
+ def update_remote_package_set(vcs, only_local = false)
116
+ name = PackageSet.name_of(manifest, vcs)
117
+ raw_local_dir = PackageSet.raw_local_dir_of(vcs)
118
+
119
+ return if !Autobuild.do_update && File.exists?(raw_local_dir)
120
+
121
+ # YUK. I am stopping there in the refactoring
122
+ # TODO: figure out a better way
123
+ if !@remote_update_message_displayed
124
+ Autoproj.message("autoproj: updating remote definitions of package sets", :bold)
125
+ @remote_update_message_displayed = true
126
+ end
127
+ osdeps.install([vcs.type])
128
+ self.class.update_configuration_repository(
129
+ vcs, name, raw_local_dir,
130
+ update_from: update_from,
131
+ only_local: only_local)
132
+ end
133
+
134
+ # Create the user-visible directory for a remote package set
135
+ #
136
+ # @param [VCSDefinition] vcs the package set VCS
137
+ # @return [String] the full path to the created user dir
138
+ def create_remote_set_user_dir(vcs)
139
+ name = PackageSet.name_of(manifest, vcs)
140
+ raw_local_dir = PackageSet.raw_local_dir_of(vcs)
141
+ FileUtils.mkdir_p(remotes_user_dir)
142
+ symlink_dest = File.join(remotes_user_dir, name)
143
+
144
+ # Check if the current symlink is valid, and recreate it if it
145
+ # is not
146
+ if File.symlink?(symlink_dest)
147
+ dest = File.readlink(symlink_dest)
148
+ if dest != raw_local_dir
149
+ FileUtils.rm_f symlink_dest
150
+ Autoproj.create_symlink(raw_local_dir, symlink_dest)
151
+ end
152
+ else
153
+ FileUtils.rm_f symlink_dest
154
+ Autoproj.create_symlink(raw_local_dir, symlink_dest)
155
+ end
156
+
157
+ symlink_dest
158
+ end
159
+
160
+ def load_package_set(vcs, options, imported_from)
161
+ pkg_set = PackageSet.new(manifest, vcs)
162
+ pkg_set.auto_imports = options[:auto_imports]
163
+ loader.load_if_present(pkg_set, pkg_set.local_dir, 'init.rb')
164
+ pkg_set.load_description_file
165
+ if imported_from
166
+ pkg_set.imported_from << imported_from
167
+ imported_from.imports << pkg_set
168
+ else
169
+ pkg_set.explicit = true
170
+ end
171
+ pkg_set
172
+ end
173
+
174
+ def queue_auto_imports_if_needed(queue, pkg_set)
175
+ if pkg_set.auto_imports?
176
+ pkg_set.each_raw_imported_set do |import_vcs, import_options|
177
+ queue << [import_vcs, import_options, pkg_set]
178
+ end
179
+ end
180
+ queue
181
+ end
182
+
183
+ # Load the package set information
184
+ #
185
+ # It loads the package set information as required by {manifest} and
186
+ # makes sure that they are either updated (if Autobuild.do_update is
187
+ # true), or at least checked out.
188
+ #
189
+ # @yieldparam [String] osdep the name of an osdep required to import the
190
+ # package sets
191
+ def load_and_update_package_sets(root_pkg_set, only_local = false)
192
+ package_sets = [root_pkg_set]
193
+ seen_already = Set.new
194
+ by_name = Hash.new
195
+
196
+ queue = queue_auto_imports_if_needed(Array.new, root_pkg_set)
197
+ while !queue.empty?
198
+ vcs, options, imported_from = queue.shift
199
+ next if seen_already.include?(vcs)
200
+ seen_already << vcs
201
+
202
+ if !vcs.local?
203
+ update_remote_package_set(vcs, only_local)
204
+ create_remote_set_user_dir(vcs)
205
+ end
206
+
207
+ name = PackageSet.name_of(manifest, vcs)
208
+ if already_loaded = by_name[name]
209
+ already_loaded_pkg_set, already_loaded_vcs = *already_loaded
210
+ if already_loaded_vcs != vcs
211
+ if imported_from
212
+ Autoproj.warn "#{imported_from.name} auto-imports a package set from #{vcs}, but a package set with the same name (#{name}) has already been imported from #{already_loaded_vcs}, I am skipping this one"
213
+ else
214
+ Autoproj.warn "the manifest refers to a package set from #{vcs}, but a package set with the same name (#{name}) has already been imported from #{already_loaded_vcs}, I am skipping this one"
215
+ end
216
+ end
217
+
218
+ if imported_from
219
+ already_loaded_pkg_set.imported_from << imported_from
220
+ imported_from.imports << already_loaded_pkg_set
221
+ end
222
+ next
223
+ end
224
+
225
+ pkg_set = load_package_set(vcs, options, imported_from)
226
+ package_sets << pkg_set
227
+
228
+ by_name[pkg_set.name] = [pkg_set, vcs, options, imported_from]
229
+
230
+ # Finally, queue the imports
231
+ queue_auto_imports_if_needed(queue, pkg_set)
232
+ end
233
+ cleanup_remotes_dir(package_sets)
234
+ cleanup_remotes_user_dir(package_sets)
235
+ package_sets
236
+ end
237
+
238
+ # Removes from {remotes_dir} the directories that do not match a package
239
+ # set
240
+ def cleanup_remotes_dir(package_sets = manifest.package_sets)
241
+ # Cleanup the .remotes and remotes_symlinks_dir directories
242
+ Dir.glob(File.join(remotes_dir, '*')).each do |dir|
243
+ dir = File.expand_path(dir)
244
+ if File.directory?(dir) && !package_sets.find { |pkg| pkg.raw_local_dir == dir }
245
+ FileUtils.rm_rf dir
246
+ end
247
+ end
248
+ end
249
+
250
+ # Removes from {remotes_user_dir} the directories that do not match a
251
+ # package set
252
+ def cleanup_remotes_user_dir(package_sets = manifest.package_sets)
253
+ Dir.glob(File.join(remotes_user_dir, '*')).each do |file|
254
+ file = File.expand_path(file)
255
+ if File.symlink?(file) && !package_sets.find { |pkg_set| pkg_set.user_local_dir == file }
256
+ FileUtils.rm_f file
257
+ end
258
+ end
259
+ end
260
+
261
+ def sort_package_sets_by_import_order(package_sets)
262
+ sorted = Array.new
263
+ queue = package_sets.dup
264
+ while !queue.empty?
265
+ pkg_set = queue.shift
266
+ if pkg_set.imports.any? { |imported_set| !sorted.include?(imported_set) }
267
+ queue.push(pkg_set)
268
+ else
269
+ sorted << pkg_set
270
+ end
271
+ end
272
+ sorted
273
+ end
274
+
275
+ def update_configuration(only_local = false)
276
+ # Load the installation's manifest a first time, to check if we should
277
+ # update it ... We assume that the OS dependencies for this VCS is already
278
+ # installed (i.e. that the user did not remove it)
279
+ if manifest.vcs && !manifest.vcs.local?
280
+ update_main_configuration(only_local)
281
+ manifest_path = File.join(config_dir, 'manifest')
282
+ manifest.load(manifest_path)
283
+ end
284
+
285
+ root_pkg_set = LocalPackageSet.new(manifest)
286
+ root_pkg_set.load_description_file
287
+ root_pkg_set.explicit = true
288
+ package_sets = load_and_update_package_sets(root_pkg_set, only_local)
289
+ package_sets = sort_package_sets_by_import_order(package_sets)
290
+ package_sets.each do |pkg_set|
291
+ manifest.register_package_set(pkg_set)
292
+ end
293
+ # YUK. I am stopping there in the refactoring
294
+ # TODO: figure out a better way
295
+ if @remote_update_message_displayed
296
+ Autoproj.message
297
+ end
298
+ end
299
+ end
300
+ end
301
+ end
302
+