autoproj 2.0.3 → 2.1.0.rc1

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +196 -10
  3. data/autoproj.gemspec +8 -8
  4. data/bin/alocate +12 -1
  5. data/bin/alog +8 -0
  6. data/bin/amake +12 -1
  7. data/bin/aup +12 -1
  8. data/bin/autoproj_bootstrap +15 -6
  9. data/bin/autoproj_install +15 -6
  10. data/lib/autoproj/cli/base.rb +15 -0
  11. data/lib/autoproj/cli/bootstrap.rb +3 -0
  12. data/lib/autoproj/cli/build.rb +6 -0
  13. data/lib/autoproj/cli/clean.rb +13 -5
  14. data/lib/autoproj/cli/doc.rb +8 -0
  15. data/lib/autoproj/cli/envsh.rb +3 -5
  16. data/lib/autoproj/cli/inspection_tool.rb +0 -16
  17. data/lib/autoproj/cli/main.rb +71 -52
  18. data/lib/autoproj/cli/main_test.rb +4 -0
  19. data/lib/autoproj/cli/osdeps.rb +5 -6
  20. data/lib/autoproj/cli/show.rb +1 -1
  21. data/lib/autoproj/cli/status.rb +77 -19
  22. data/lib/autoproj/cli/update.rb +16 -26
  23. data/lib/autoproj/configuration.rb +5 -0
  24. data/lib/autoproj/environment.rb +11 -1
  25. data/lib/autoproj/local_package_set.rb +2 -0
  26. data/lib/autoproj/manifest.rb +16 -0
  27. data/lib/autoproj/ops/cache.rb +3 -0
  28. data/lib/autoproj/ops/configuration.rb +3 -2
  29. data/lib/autoproj/ops/install.rb +13 -4
  30. data/lib/autoproj/ops/main_config_switcher.rb +3 -3
  31. data/lib/autoproj/ops/snapshot.rb +4 -7
  32. data/lib/autoproj/package_definition.rb +10 -0
  33. data/lib/autoproj/package_managers/bundler_manager.rb +1 -0
  34. data/lib/autoproj/package_managers/pip_manager.rb +1 -0
  35. data/lib/autoproj/package_set.rb +39 -6
  36. data/lib/autoproj/test.rb +8 -0
  37. data/lib/autoproj/version.rb +1 -1
  38. data/lib/autoproj/workspace.rb +13 -1
  39. data/samples/autoproj/README.md +60 -0
  40. data/samples/autoproj/init.rb +17 -18
  41. data/samples/autoproj/manifest +18 -34
  42. data/samples/autoproj/overrides.d/.gitattributes +1 -0
  43. data/samples/manifest.xml +2 -7
  44. metadata +64 -36
  45. data/samples/autoproj/README.txt +0 -52
  46. data/samples/autoproj/overrides.rb +0 -4
  47. data/samples/autoproj/overrides.yml +0 -18
  48. data/samples/osdeps.yml +0 -65
@@ -14,6 +14,7 @@ class Base
14
14
 
15
15
  def initialize(ws = Workspace.default)
16
16
  @ws = ws
17
+ @env_sh_updated = nil
17
18
  end
18
19
 
19
20
  # Normalizes the arguments given by the user on the command line
@@ -192,6 +193,20 @@ def self.validate_options(args, options)
192
193
 
193
194
  return args, remaining.to_sym_keys
194
195
  end
196
+
197
+ def export_env_sh(shell_helpers: ws.config.shell_helpers?)
198
+ @env_sh_updated = ws.export_env_sh(shell_helpers: shell_helpers)
199
+ end
200
+
201
+ def notify_env_sh_updated
202
+ return if @env_sh_updated.nil?
203
+
204
+ if @env_sh_updated
205
+ Autoproj.message " updated: #{ws.root_dir}/#{Autoproj::ENV_FILENAME}", :green
206
+ else
207
+ Autoproj.message " left unchanged: #{ws.root_dir}/#{Autoproj::ENV_FILENAME}", :green
208
+ end
209
+ end
195
210
  end
196
211
  end
197
212
  end
@@ -80,6 +80,9 @@ def run(buildconf_info, options)
80
80
  raise
81
81
  end
82
82
  end
83
+
84
+ def notify_env_sh_updated
85
+ end
83
86
  end
84
87
  end
85
88
  end
@@ -8,6 +8,10 @@ def validate_options(selected_packages, options)
8
8
  selected_packages, options =
9
9
  super(selected_packages, options.merge(
10
10
  checkout_only: true, aup: options[:amake]))
11
+
12
+ if options[:no_deps_shortcut]
13
+ options[:deps] = false
14
+ end
11
15
  if options[:deps].nil?
12
16
  options[:deps] =
13
17
  !(options[:rebuild] || options[:force])
@@ -70,6 +74,8 @@ def run(selected_packages, options)
70
74
  Autobuild.do_build = true
71
75
  ops.build_packages(source_packages, parallel: parallel)
72
76
  Autobuild.apply(source_packages, "autoproj-build", ['install'])
77
+ ensure
78
+ export_env_sh
73
79
  end
74
80
  end
75
81
  end
@@ -1,4 +1,5 @@
1
1
  require 'autoproj/cli/inspection_tool'
2
+ require 'tty/prompt'
2
3
 
3
4
  module Autoproj
4
5
  module CLI
@@ -6,8 +7,8 @@ class Clean < InspectionTool
6
7
  def validate_options(packages, options)
7
8
  packages, options = super
8
9
  if packages.empty? && !options[:all]
9
- opt = BuildOption.new("", "boolean", {:doc => "this is going to clean all packages. Is that really what you want ?"}, nil)
10
- if !opt.ask(false)
10
+ prompt = TTY::Prompt.new
11
+ if !prompt.yes?("this is going to clean all packages. Is that really what you want ?")
11
12
  raise Interrupt
12
13
  end
13
14
  end
@@ -17,10 +18,17 @@ def validate_options(packages, options)
17
18
  def run(selection, options = Hash.new)
18
19
  initialize_and_load
19
20
  packages, _ = normalize_command_line_package_selection(selection)
21
+
22
+ deps = if options.has_key?(:deps)
23
+ options[:deps]
24
+ else
25
+ selection.empty?
26
+ end
27
+
20
28
  source_packages, * = resolve_selection(
21
- selection,
22
- recursive: false)
23
- if packages.empty?
29
+ packages,
30
+ recursive: deps)
31
+ if source_packages.empty?
24
32
  raise ArgumentError, "no packages or OS packages match #{selection.join(" ")}"
25
33
  end
26
34
 
@@ -3,6 +3,14 @@
3
3
  module Autoproj
4
4
  module CLI
5
5
  class Doc < InspectionTool
6
+ def validate_options(packages, options)
7
+ packages, options = super
8
+ if options[:no_deps_shortcut]
9
+ options[:deps] = false
10
+ end
11
+ return packages, options
12
+ end
13
+
6
14
  def run(user_selection, deps: true)
7
15
  initialize_and_load
8
16
  packages, _ =
@@ -7,13 +7,11 @@ def validate_options(_unused, options = Hash.new)
7
7
  options
8
8
  end
9
9
 
10
- def run(options = Hash.new)
10
+ def run(**options)
11
11
  initialize_and_load
12
+ shell_helpers = options.fetch(:shell_helpers, ws.config.shell_helpers?)
12
13
  finalize_setup(Array.new)
13
-
14
- options = Kernel.validate_options options,
15
- shell_helpers: ws.config.shell_helpers?
16
- ws.export_env_sh(shell_helpers: options[:shell_helpers])
14
+ export_env_sh(shell_helpers: shell_helpers)
17
15
  end
18
16
  end
19
17
  end
@@ -44,22 +44,6 @@ def finalize_setup(packages = [], non_imported_packages: :ignore, recursive: tru
44
44
  return source_packages, osdep_packages, resolved_selection, config_selected
45
45
  end
46
46
  end
47
-
48
- def load_all_available_package_manifests
49
- # Load the manifest for packages that are already present on the
50
- # file system
51
- ws.manifest.each_autobuild_package do |pkg|
52
- if pkg.checked_out?
53
- begin
54
- ws.manifest.load_package_manifest(pkg.name)
55
- rescue Interrupt
56
- raise
57
- rescue Exception => e
58
- Autoproj.warn "cannot load package manifest for #{pkg.name}: #{e.message}"
59
- end
60
- end
61
- end
62
- end
63
47
  end
64
48
  end
65
49
  end
@@ -11,21 +11,16 @@ def self.basic_setup
11
11
  end
12
12
 
13
13
  class Main < Thor
14
- class_option :verbose, type: :boolean,
15
- desc: 'turns verbose output',
16
- default: false
17
- class_option :debug, type: :boolean,
18
- desc: 'turns debugging output',
19
- default: false
20
- class_option :silent, type: :boolean,
21
- desc: 'tell autoproj to not display anything',
22
- default: false
23
- class_option :color, type: :boolean,
24
- desc: 'enables or disables colored display (enabled by default if the terminal supports it)',
25
- default: TTY::Color.color?
26
- class_option :progress, type: :boolean,
27
- desc: 'enables or disables progress display (enabled by default if the terminal supports it)',
28
- default: TTY::Color.color?
14
+ class_option :verbose, type: :boolean, default: false,
15
+ desc: 'turns verbose output'
16
+ class_option :debug, type: :boolean, default: false,
17
+ desc: 'turns debugging output'
18
+ class_option :silent, type: :boolean, default: false,
19
+ desc: 'tell autoproj to not display anything'
20
+ class_option :color, type: :boolean, default: TTY::Color.color?,
21
+ desc: 'enables or disables colored display (enabled by default if the terminal supports it)'
22
+ class_option :progress, type: :boolean, default: TTY::Color.color?,
23
+ desc: 'enables or disables progress display (enabled by default if the terminal supports it)'
29
24
 
30
25
  no_commands do
31
26
  def run_autoproj_cli(filename, classname, report_options, *args, **extra_options)
@@ -38,18 +33,20 @@ def run_autoproj_cli(filename, classname, report_options, *args, **extra_options
38
33
  options[:only_local] = options.delete('local')
39
34
  end
40
35
  cli = CLI.const_get(classname).new
41
- run_args = cli.validate_options(args, options.merge(extra_options))
42
- cli.run(*run_args)
36
+ begin
37
+ run_args = cli.validate_options(args, options.merge(extra_options))
38
+ cli.run(*run_args)
39
+ ensure
40
+ cli.notify_env_sh_updated
41
+ end
43
42
  end
44
43
  end
45
44
  end
46
45
 
47
46
  desc 'bootstrap VCS_TYPE VCS_URL VCS_OPTIONS', 'bootstraps a new autoproj installation. This is usually not called directly, but called from the autoproj_bootstrap standalone script'
48
- option :reuse,
49
- banner: 'DIR',
47
+ option :reuse, banner: 'DIR',
50
48
  desc: 'reuse packages already built within the DIR autoproj workspace in this installation, if DIR is not given, reuses the installation whose env.sh is currently sourced'
51
- option :seed_config,
52
- banner: 'SEED_CONFIG',
49
+ option :seed_config, banner: 'SEED_CONFIG',
53
50
  desc: "a configuration file used to seed the bootstrap's configuration"
54
51
  def bootstrap(*args)
55
52
  if !File.directory?(File.join(Dir.pwd, '.autoproj'))
@@ -76,16 +73,19 @@ def envsh
76
73
  desc: "use the VCS information as 'versions --no-local' would detect it instead of the one in the configuration"
77
74
  option :parallel, aliases: :p, type: :numeric,
78
75
  desc: 'maximum number of parallel jobs'
79
- option :deps, type: :boolean,
80
- desc: 'whether only the status of the given packages should be displayed, or of their dependencies as well',
81
- default: true
76
+ option :deps, type: :boolean, default: true,
77
+ desc: 'whether only the status of the given packages should be displayed, or of their dependencies as well. -n is a shortcut for --no-deps'
78
+ option :no_deps_shortcut, hide: true, aliases: '-n', type: :boolean,
79
+ desc: 'provide -n for --no-deps'
82
80
  def status(*packages)
83
81
  run_autoproj_cli(:status, :Status, Hash[], *packages)
84
82
  end
85
83
 
86
84
  desc 'doc [PACKAGES]', 'generate API documentation for packages that support it'
87
- option :deps, desc: 'control whether documentation should be generated only for the packages given on the command line, or also for their dependencies',
88
- type: :boolean, default: true
85
+ option :deps, type: :boolean, default: true,
86
+ desc: 'control whether documentation should be generated only for the packages given on the command line, or also for their dependencies. -n is a shortcut for --no-deps'
87
+ option :no_deps_shortcut, hide: true, aliases: '-n', type: :boolean,
88
+ desc: 'provide -n for --no-deps'
89
89
  def doc(*packages)
90
90
  run_autoproj_cli(:doc, :Doc, Hash[], *packages)
91
91
  end
@@ -95,15 +95,15 @@ def doc(*packages)
95
95
  desc: 'behave like aup'
96
96
  option :all, default: false, hide: true, type: :boolean,
97
97
  desc: 'when in aup mode, update all packages instead of only the local one'
98
- option :keep_going, aliases: :k, type: :boolean,
99
- banner: '',
98
+ option :keep_going, aliases: :k, type: :boolean, banner: '',
100
99
  desc: 'do not stop on build or checkout errors'
101
100
  option :config, type: :boolean,
102
101
  desc: "(do not) update configuration. The default is to update configuration if explicitely selected or if no additional arguments are given on the command line, and to not do it if packages are explicitely selected on the command line"
102
+ option :bundler, type: :boolean,
103
+ desc: "(do not) update bundler. This is automatically enabled only if no arguments are given on the command line"
103
104
  option :autoproj, type: :boolean,
104
105
  desc: "(do not) update autoproj. This is automatically enabled only if no arguments are given on the command line"
105
- option :osdeps, type: :boolean,
106
- default: true,
106
+ option :osdeps, type: :boolean, default: true,
107
107
  desc: "enable or disable osdeps handling"
108
108
  option :from, type: :string,
109
109
  desc: 'use this existing autoproj installation to check out the packages (for importers that support this)'
@@ -114,7 +114,9 @@ def doc(*packages)
114
114
  option :osdeps_filter_uptodate, default: true, type: :boolean,
115
115
  desc: 'controls whether the osdeps subsystem should filter up-to-date packages or not'
116
116
  option :deps, default: true, type: :boolean,
117
- desc: 'whether the package dependencies should be recursively updated (the default) or not'
117
+ desc: 'whether the package dependencies should be recursively updated (the default) or not. -n is a shortcut for --no-deps'
118
+ option :no_deps_shortcut, hide: true, aliases: '-n', type: :boolean,
119
+ desc: 'provide -n for --no-deps'
118
120
  option :reset, default: false, type: :boolean,
119
121
  desc: "forcefully resets the repository to the state expected by autoproj's configuration",
120
122
  long_desc: "The default is to update the repository if possible, and leave it alone otherwise. With --reset, autoproj update might come back to an older commit than the repository's current state"
@@ -144,9 +146,18 @@ def update(*packages)
144
146
  option :osdeps, type: :boolean,
145
147
  desc: 'controls whether missing osdeps should be installed. In rebuild mode, also controls whether the osdeps should be reinstalled or not (the default is to reinstall them)'
146
148
  option :deps, type: :boolean,
147
- desc: 'in force or rebuild modes, control whether the force/rebuild action should apply only on the packages given on the command line, or on their dependencies as well (the default is --no-deps)'
149
+ desc: "controls whether the operation should apply to the package's dependencies as well. -n is a shortcut for --no-deps",
150
+ long_desc: <<-EOD
151
+ Without --force or --rebuild, the default is true (the build will apply to all packages).
152
+ With --force or --rebuild, control whether the force/rebuild action should apply
153
+ only on the packages given on the command line, or on their dependencies as well.
154
+ In this case, the default is false
155
+ EOD
156
+ option :no_deps_shortcut, hide: true, aliases: '-n', type: :boolean,
157
+ desc: 'provide -n for --no-deps'
148
158
  option :parallel, aliases: :p, type: :numeric,
149
159
  desc: 'maximum number of parallel jobs'
160
+
150
161
  def build(*packages)
151
162
  run_autoproj_cli(:build, :Build, Hash[silent: false], *packages)
152
163
  end
@@ -161,7 +172,22 @@ def cache(*cache_dir)
161
172
  end
162
173
 
163
174
  desc 'clean [PACKAGES]', 'remove build byproducts for the given packages'
164
- option :all,
175
+ long_desc <<-EODESC
176
+ Remove build byproducts from disk
177
+
178
+ To avoid mistakes, 'clean' will ask for confirmation if no packages
179
+ are provided on the command line. Use --all to bypass this check (e.g.
180
+ in automated scripts)
181
+
182
+ When packages are explicitely provided on the command line, autoproj
183
+ will by default not clean the package dependencies. However, when
184
+ no packages are provided on the command line, all the workspace
185
+ packages will be cleaned. Use --deps=f or --deps=t to override
186
+ these defaults.
187
+ EODESC
188
+ option :deps, type: :boolean,
189
+ desc: "clean the given packages as well as their dependencies"
190
+ option :all, type: :boolean,
165
191
  desc: 'bypass the safety question when you mean to clean all packages'
166
192
  def clean(*packages)
167
193
  run_autoproj_cli(:clean, :Clean, Hash[], *packages)
@@ -195,9 +221,10 @@ def reconfigure
195
221
  desc: "compare to the given baseline. if 'true', the comparison will ignore any override, otherwise it will take into account overrides only up to the given package set"
196
222
  option :env, type: :boolean,
197
223
  desc: "display the package's own environment", default: false
198
- option :short, desc: 'display a package summary with one package line'
199
- option :recursive, desc: 'display the package and their dependencies (the default is to only display selected packages)',
200
- type: :boolean, default: false
224
+ option :short,
225
+ desc: 'display a package summary with one package line'
226
+ option :recursive, type: :boolean, default: false,
227
+ desc: 'display the package and their dependencies (the default is to only display selected packages)'
201
228
  def show(*packages)
202
229
  run_autoproj_cli(:show, :Show, Hash[], *packages)
203
230
  end
@@ -210,9 +237,7 @@ def osdeps(*packages)
210
237
  end
211
238
 
212
239
  desc 'versions [PACKAGES]', 'generate a version file for the given packages, or all packages if none are given'
213
- option :config, type: :boolean,
214
- default: nil,
215
- banner: '',
240
+ option :config, type: :boolean, default: nil, banner: '',
216
241
  desc: "controls whether the package sets should be versioned as well",
217
242
  long_desc: <<-EOD
218
243
  This is the default if no packages are given on the command line, or if the
@@ -223,22 +248,18 @@ def osdeps(*packages)
223
248
  autoproj versions autoproj/ # versions only the configuration
224
249
  autoproj versions autoproj a/package # versions the configuration and the specified package(s)
225
250
  EOD
226
- option :keep_going, aliases: :k, type: :boolean,
227
- default: false,
228
- banner: '',
251
+ option :keep_going, aliases: :k, type: :boolean, default: false, banner: '',
229
252
  desc: 'do not stop if some package cannot be versioned'
230
- option :replace, type: :boolean,
231
- default: false,
253
+ option :replace, type: :boolean, default: false,
232
254
  desc: 'in combination with --save, controls whether an existing file should be updated or replaced'
233
- option :deps, type: :boolean,
234
- default: false,
255
+ option :deps, type: :boolean, default: false,
235
256
  desc: 'whether both packages and their dependencies should be versioned, or only the selected packages (the latter is the default)'
236
257
  option :local, type: :boolean, default: false,
237
258
  desc: 'whether we should access the remote server to verify that the snapshotted state is present'
238
259
  option :save, type: :string,
239
260
  desc: 'save to the given file instead of displaying it on the standard output'
240
261
  def versions(*packages)
241
- run_autoproj_cli(:versions, :Versions, Hash[], *packages)
262
+ run_autoproj_cli(:versions, :Versions, Hash[], *packages, deps: true)
242
263
  end
243
264
 
244
265
  stop_on_unknown_option! :log
@@ -270,8 +291,7 @@ def reset(version_id)
270
291
  EOD
271
292
  option :package_sets, type: :boolean,
272
293
  desc: 'commit the package set state as well (enabled by default)'
273
- option :keep_going, aliases: :k, type: :boolean,
274
- banner: '',
294
+ option :keep_going, aliases: :k, type: :boolean, banner: '',
275
295
  desc: 'do not stop on build or checkout errors'
276
296
  option :message, aliases: :m, type: :string,
277
297
  desc: 'the message to use for the new commit (the default is to mention the creation of the tag)'
@@ -290,13 +310,12 @@ def tag(tag_name = nil, *packages)
290
310
  EOD
291
311
  option :package_sets, type: :boolean,
292
312
  desc: 'commit the package set state as well (enabled by default)'
293
- option :keep_going, aliases: :k, type: :boolean,
294
- banner: '',
313
+ option :keep_going, aliases: :k, type: :boolean, banner: '',
295
314
  desc: 'do not stop on build or checkout errors'
296
315
  option :message, aliases: :m, type: :string,
297
316
  desc: 'the message to use for the new commit (the default is to mention the creation of the tag)'
298
317
  def commit(*packages)
299
- run_autoproj_cli(:commit, :Commit, Hash[], *packages)
318
+ run_autoproj_cli(:commit, :Commit, Hash[], *packages, deps: true)
300
319
  end
301
320
 
302
321
  desc 'switch-config VCS URL [OPTIONS]', 'switches the main build configuration'
@@ -50,6 +50,9 @@ def list(*packages)
50
50
  end
51
51
 
52
52
  desc 'exec [PACKAGES]', 'execute the tests for the given packages, or all if no packages are given on the command line'
53
+ option :keep_going, aliases: :k, type: :boolean,
54
+ banner: '',
55
+ desc: 'do not stop on build or checkout errors'
53
56
  option :deps, type: :boolean, default: false,
54
57
  desc: 'controls whether to execute the tests of the dependencies of the packages given on the command line (the default is not)'
55
58
  option :fail, type: :boolean, default: true,
@@ -61,6 +64,7 @@ def exec(*packages)
61
64
  report do
62
65
  cli = Test.new
63
66
  Autobuild.pass_test_errors = options[:fail]
67
+ Autobuild.ignore_errors = options[:keep_going]
64
68
  Autobuild::TestUtility.coverage_enabled = options[:coverage]
65
69
  args = cli.validate_options(packages, deps: options[:deps])
66
70
  cli.run(*args)
@@ -3,19 +3,18 @@
3
3
  module Autoproj
4
4
  module CLI
5
5
  class OSDeps < InspectionTool
6
- def run(user_selection, options = Hash.new)
6
+ def run(user_selection, update: true, **options)
7
7
  initialize_and_load
8
8
  _, osdep_packages, resolved_selection, _ =
9
9
  finalize_setup(user_selection)
10
10
 
11
- options = Kernel.validate_options options,
12
- update: true,
13
- shell_helpers: ws.config.shell_helpers?
11
+ shell_helpers = options.fetch(:shell_helpers, ws.config.shell_helpers?)
12
+
14
13
  ws.install_os_packages(
15
14
  osdep_packages,
16
15
  run_package_managers_without_packages: true,
17
- install_only: !options[:update])
18
- ws.export_env_sh(shell_helpers: options[:shell_helpers])
16
+ install_only: !update)
17
+ export_env_sh(shell_helpers: shell_helpers)
19
18
  end
20
19
  end
21
20
  end
@@ -31,7 +31,7 @@ def run(user_selection, short: false, recursive: false, mainline: false, env: fa
31
31
  Autoproj.error "no package set, packages or OS packages match #{user_selection.join(" ")}"
32
32
  return
33
33
  elsif !source_packages.empty? || !all_matching_osdeps.empty?
34
- load_all_available_package_manifests
34
+ ws.load_all_available_package_manifests
35
35
  revdeps = ws.manifest.compute_revdeps
36
36
  end
37
37
 
@@ -1,10 +1,15 @@
1
1
  require 'autoproj/cli/inspection_tool'
2
+ require 'tty-spinner'
2
3
 
3
4
  module Autoproj
4
5
  module CLI
5
6
  class Status < InspectionTool
6
7
  def validate_options(packages, options)
7
8
  packages, options = super
9
+ options[:progress] = Autobuild.progress_display_enabled?
10
+ if options[:no_deps_shortcut]
11
+ options[:deps] = false
12
+ end
8
13
  if options[:deps].nil? && packages.empty?
9
14
  options[:deps] = true
10
15
  end
@@ -28,13 +33,21 @@ def run(user_selection, options = Hash.new)
28
33
 
29
34
  if !options.has_key?(:parallel) && options[:only_local]
30
35
  options[:parallel] = 1
36
+ else
37
+ options[:parallel] ||= ws.config.parallel_import_level
31
38
  end
32
39
 
33
40
  if options[:config]
34
41
  pkg_sets = ws.manifest.each_package_set.to_a
35
42
  if !pkg_sets.empty?
36
43
  Autoproj.message("autoproj: displaying status of configuration", :bold)
37
- display_status(pkg_sets, parallel: options[:parallel], snapshot: options[:snapshot], only_local: options[:only_local])
44
+ display_status(
45
+ pkg_sets,
46
+ parallel: options[:parallel],
47
+ snapshot: options[:snapshot],
48
+ only_local: options[:only_local],
49
+ progress: options[:progress])
50
+
38
51
  STDERR.puts
39
52
  end
40
53
  end
@@ -43,7 +56,12 @@ def run(user_selection, options = Hash.new)
43
56
  packages = packages.sort.map do |pkg_name|
44
57
  ws.manifest.find_package_definition(pkg_name)
45
58
  end
46
- display_status(packages, parallel: options[:parallel], snapshot: options[:snapshot], only_local: options[:only_local])
59
+ display_status(
60
+ packages,
61
+ parallel: options[:parallel],
62
+ snapshot: options[:snapshot],
63
+ only_local: options[:only_local],
64
+ progress: options[:progress])
47
65
  end
48
66
 
49
67
  def snapshot_overrides_vcs?(importer, vcs, snapshot)
@@ -132,34 +150,85 @@ def status_of_package(package_description, only_local: false, snapshot: false)
132
150
  package_status
133
151
  end
134
152
 
135
- StatusResult = Struct.new :uncommitted, :local, :remote
136
- def display_status(packages, options = Hash.new)
153
+ def each_package_status(packages, parallel: ws.config.parallel_import_level, snapshot: false, only_local: false, progress: nil)
154
+ return enum_for(__method__) if !block_given?
155
+
137
156
  result = StatusResult.new
138
157
 
139
- parallel = options[:parallel] || ws.config.parallel_import_level
140
158
  executor = Concurrent::FixedThreadPool.new(parallel, max_length: 0)
141
159
  interactive, noninteractive = packages.partition do |pkg|
142
160
  pkg.autobuild.importer && pkg.autobuild.importer.interactive?
143
161
  end
144
162
  noninteractive = noninteractive.map do |pkg|
145
163
  future = Concurrent::Future.execute(executor: executor) do
146
- status_of_package(pkg, snapshot: options[:snapshot], only_local: options[:only_local])
164
+ status_of_package(pkg, snapshot: snapshot, only_local: only_local)
147
165
  end
148
166
  [pkg, future]
149
167
  end
150
168
 
151
- sync_packages = ""
152
169
  (noninteractive + interactive).each do |pkg, future|
153
170
  if future
171
+ if progress
172
+ wait_timeout = 1
173
+ while true
174
+ future.wait(wait_timeout)
175
+ if future.complete?
176
+ break
177
+ else
178
+ wait_timeout = 0.2
179
+ progress.call(pkg)
180
+ end
181
+ end
182
+ end
183
+
154
184
  if !(status = future.value)
155
185
  raise future.reason
156
186
  end
157
- else status = status_of_package(pkg, snapshot: options[:snapshot], only_local: options[:only_local])
187
+ else status = status_of_package(pkg, snapshot: snapshot, only_local: only_local)
158
188
  end
159
189
 
160
190
  result.uncommitted ||= status.uncommitted
161
191
  result.local ||= status.local
162
192
  result.remote ||= status.remote
193
+ yield(pkg, status)
194
+ end
195
+ result
196
+
197
+ rescue Interrupt
198
+ Autoproj.warn "Interrupted, waiting for pending jobs to finish"
199
+ raise
200
+ rescue Exception => e
201
+ Autoproj.error "internal error: #{e}, waiting for pending jobs to finish"
202
+ raise
203
+ ensure
204
+ executor.shutdown
205
+ executor.wait_for_termination
206
+ end
207
+
208
+ StatusResult = Struct.new :uncommitted, :local, :remote
209
+ def display_status(packages, parallel: ws.config.parallel_import_level, snapshot: false, only_local: false, progress: true)
210
+ sync_packages = ""
211
+ spinner = nil
212
+
213
+ if progress
214
+ progress = lambda do |pkg|
215
+ if !spinner
216
+ if !sync_packages.empty?
217
+ Autoproj.message("#{sync_packages}: #{Autoproj.color("local and remote are in sync", :green)}")
218
+ sync_packages = ""
219
+ end
220
+
221
+ spinner = TTY::Spinner.new("[:spinner] #{pkg.name}", clear: true)
222
+ end
223
+ spinner.spin
224
+ end
225
+ end
226
+
227
+ result = each_package_status(packages, parallel: parallel, progress: progress) do |pkg, status|
228
+ if spinner
229
+ spinner.stop
230
+ spinner = nil
231
+ end
163
232
 
164
233
  pkg_name = pkg.name
165
234
  if status.sync && status.msg.empty?
@@ -197,18 +266,7 @@ def display_status(packages, options = Hash.new)
197
266
  Autoproj.message("#{sync_packages}: #{Autoproj.color("local and remote are in sync", :green)}")
198
267
  end
199
268
  return result
200
-
201
- rescue Interrupt
202
- Autoproj.warn "Interrupted, waiting for pending jobs to finish"
203
- raise
204
- rescue Exception => e
205
- Autoproj.error "internal error: #{e}, waiting for pending jobs to finish"
206
- raise
207
- ensure
208
- executor.shutdown
209
- executor.wait_for_termination
210
269
  end
211
-
212
270
  end
213
271
  end
214
272
  end