autoproj 2.0.0.rc37 → 2.0.0.rc38

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -2
  3. data/Rakefile +1 -1
  4. data/bin/autoproj_bootstrap +34 -2
  5. data/bin/autoproj_bootstrap.in +4 -2
  6. data/bin/autoproj_install +34 -2
  7. data/bin/autoproj_install.in +4 -2
  8. data/lib/autoproj.rb +9 -2
  9. data/lib/autoproj/autobuild.rb +13 -742
  10. data/lib/autoproj/autobuild_extensions/archive_importer.rb +44 -0
  11. data/lib/autoproj/autobuild_extensions/dsl.rb +439 -0
  12. data/lib/autoproj/autobuild_extensions/git.rb +116 -0
  13. data/lib/autoproj/autobuild_extensions/package.rb +159 -0
  14. data/lib/autoproj/autobuild_extensions/svn.rb +11 -0
  15. data/lib/autoproj/cli/base.rb +17 -18
  16. data/lib/autoproj/cli/clean.rb +1 -2
  17. data/lib/autoproj/cli/envsh.rb +1 -2
  18. data/lib/autoproj/cli/inspection_tool.rb +12 -21
  19. data/lib/autoproj/cli/locate.rb +130 -73
  20. data/lib/autoproj/cli/main.rb +31 -5
  21. data/lib/autoproj/cli/main_plugin.rb +79 -0
  22. data/lib/autoproj/cli/main_test.rb +19 -5
  23. data/lib/autoproj/cli/osdeps.rb +1 -2
  24. data/lib/autoproj/cli/patcher.rb +21 -0
  25. data/lib/autoproj/cli/query.rb +34 -41
  26. data/lib/autoproj/cli/show.rb +121 -52
  27. data/lib/autoproj/cli/status.rb +4 -5
  28. data/lib/autoproj/cli/tag.rb +1 -1
  29. data/lib/autoproj/cli/test.rb +7 -6
  30. data/lib/autoproj/cli/update.rb +8 -22
  31. data/lib/autoproj/cli/versions.rb +1 -2
  32. data/lib/autoproj/configuration.rb +1 -1
  33. data/lib/autoproj/environment.rb +2 -7
  34. data/lib/autoproj/exceptions.rb +10 -8
  35. data/lib/autoproj/find_workspace.rb +46 -12
  36. data/lib/autoproj/installation_manifest.rb +34 -25
  37. data/lib/autoproj/local_package_set.rb +86 -0
  38. data/lib/autoproj/manifest.rb +448 -503
  39. data/lib/autoproj/metapackage.rb +31 -5
  40. data/lib/autoproj/ops/configuration.rb +46 -45
  41. data/lib/autoproj/ops/import.rb +150 -60
  42. data/lib/autoproj/ops/install.rb +25 -1
  43. data/lib/autoproj/ops/loader.rb +4 -1
  44. data/lib/autoproj/ops/main_config_switcher.rb +4 -4
  45. data/lib/autoproj/ops/snapshot.rb +4 -3
  46. data/lib/autoproj/os_package_installer.rb +105 -46
  47. data/lib/autoproj/os_package_resolver.rb +63 -36
  48. data/lib/autoproj/package_definition.rb +1 -0
  49. data/lib/autoproj/package_managers/apt_dpkg_manager.rb +30 -27
  50. data/lib/autoproj/package_managers/bundler_manager.rb +64 -18
  51. data/lib/autoproj/package_managers/gem_manager.rb +4 -2
  52. data/lib/autoproj/package_managers/manager.rb +26 -7
  53. data/lib/autoproj/package_managers/shell_script_manager.rb +4 -4
  54. data/lib/autoproj/package_managers/zypper_manager.rb +1 -1
  55. data/lib/autoproj/package_manifest.rb +154 -137
  56. data/lib/autoproj/package_selection.rb +16 -2
  57. data/lib/autoproj/package_set.rb +352 -309
  58. data/lib/autoproj/query.rb +13 -1
  59. data/lib/autoproj/system.rb +2 -2
  60. data/lib/autoproj/test.rb +164 -11
  61. data/lib/autoproj/variable_expansion.rb +15 -42
  62. data/lib/autoproj/vcs_definition.rb +93 -76
  63. data/lib/autoproj/version.rb +1 -1
  64. data/lib/autoproj/workspace.rb +116 -80
  65. metadata +10 -2
@@ -1,113 +1,170 @@
1
- require 'autoproj/cli/base'
1
+ require 'autoproj/cli/inspection_tool'
2
2
 
3
3
  module Autoproj
4
4
  module CLI
5
- class Locate < Base
5
+ # Deal with locating a package source or build directory in an existing
6
+ # workspace
7
+ #
8
+ # It is based on a installation manifest file, a YAML file generated to
9
+ # list that information and thus avoid loading the Autoproj
10
+ # configuration (which takes fairly long).
11
+ class Locate < InspectionTool
6
12
  class NotFound < RuntimeError; end
7
13
  class AmbiguousSelection < RuntimeError; end
8
14
 
9
- attr_reader :installation_manifest
10
-
11
- def initialize(ws = nil)
12
- super
13
- self.ws.load_config
14
-
15
- path = InstallationManifest.path_for_root(self.ws.root_dir)
16
- if !File.file?(path)
17
- raise ConfigError, "the installation manifest is not present, please run autoproj envsh to generate it"
15
+ attr_reader :packages
16
+ attr_reader :package_sets
17
+
18
+ # Create the locate CLI interface
19
+ #
20
+ # @param [Workspace] ws the workspace we're working on
21
+ # @param [InstallationManifest,nil] installation_manifest the
22
+ # manifest. If nil, loads the whole autoproj configuration and
23
+ # rebuilds the manifest
24
+ def initialize(ws = Workspace.default, installation_manifest: try_loading_installation_manifest(ws))
25
+ super(ws)
26
+ ws.load_config
27
+
28
+ if installation_manifest
29
+ update_from_installation_manifest(installation_manifest)
18
30
  end
31
+ end
19
32
 
20
- @installation_manifest = Autoproj::InstallationManifest.new(path)
21
- installation_manifest.load
33
+ def update_from_installation_manifest(installation_manifest)
34
+ @packages = installation_manifest.each_package.to_a
35
+ @package_sets = installation_manifest.each_package_set.to_a
22
36
  end
23
37
 
24
- def validate_options(selected, options)
25
- selected, options = super
26
- return selected.first, options
38
+ # Load the installation manifest
39
+ def try_loading_installation_manifest(ws = self.ws)
40
+ Autoproj::InstallationManifest.from_workspace_root(ws.root_dir)
41
+ rescue ConfigError
27
42
  end
28
43
 
29
- def result_value(pkg, options)
30
- if options[:build]
31
- if pkg.builddir
32
- pkg.builddir
33
- else
34
- raise ConfigError, "#{pkg.name} does not have a build directory"
35
- end
36
- else
37
- pkg.srcdir
44
+ # Find a package set that matches a given selection
45
+ #
46
+ # @param [String] selection a string that is matched against the
47
+ # package set name and its various directories. Directories are
48
+ # matched against the full path and must end with /
49
+ # @return [PackageSet,nil]
50
+ def find_package_set(selection)
51
+ package_sets.find do |pkg_set|
52
+ name = pkg_set.name
53
+ name == selection ||
54
+ selection.start_with?("#{pkg_set.raw_local_dir}/") ||
55
+ selection.start_with?("#{pkg_set.user_local_dir}/")
38
56
  end
39
57
  end
40
58
 
41
- def run(selection, options = Hash.new)
42
- if !selection
43
- if options[:build]
44
- puts ws.prefix_dir
45
- else
46
- puts ws.root_dir
59
+ def find_packages(selection)
60
+ selection_rx = Regexp.new(Regexp.quote(selection))
61
+ candidates = []
62
+ packages.each do |pkg|
63
+ name = pkg.name
64
+ if name == selection || selection.start_with?("#{pkg.srcdir}/")
65
+ return [pkg]
66
+ elsif pkg.respond_to?(:builddir) && pkg.builddir && selection.start_with?("#{pkg.builddir}/")
67
+ return [pkg]
68
+ elsif name =~ selection_rx
69
+ candidates << pkg
47
70
  end
48
- return
49
71
  end
72
+ return candidates
73
+ end
50
74
 
51
- if File.directory?(selection)
52
- selection = File.expand_path(selection)
53
- end
75
+ def find_packages_with_directory_shortnames(selection)
76
+ *directories, basename = *selection.split('/')
77
+ dirname_rx = directories.
78
+ map { |d| "#{Regexp.quote(d)}\\w*" }.
79
+ join("/")
80
+
81
+ rx = Regexp.new("#{dirname_rx}/#{Regexp.quote(basename)}")
82
+ rx_strict = Regexp.new("#{dirname_rx}/#{Regexp.quote(basename)}$")
54
83
 
55
- selection_rx = Regexp.new(Regexp.quote(selection))
56
84
  candidates = []
57
- installation_manifest.each do |pkg|
85
+ candidates_strict = []
86
+ packages.each do |pkg|
58
87
  name = pkg.name
59
- if name == selection || pkg.srcdir == selection
60
- puts result_value(pkg, options)
61
- return
62
- elsif name =~ selection_rx || selection.start_with?(pkg.srcdir) || (selection.start_with?(pkg.builddir) if pkg.builddir)
88
+ if name =~ rx
63
89
  candidates << pkg
64
90
  end
91
+ if name =~ rx_strict
92
+ candidates_strict << pkg
93
+ end
65
94
  end
66
95
 
67
- if candidates.empty?
68
- # Try harder. Match directory prefixes
69
- directories = selection.split('/')
70
- rx = directories.
71
- map { |d| "#{Regexp.quote(d)}\\w*" }.
72
- join("/")
73
- rx = Regexp.new(rx)
74
-
75
- rx_strict = directories[0..-2].
76
- map { |d| "#{Regexp.quote(d)}\\w*" }.
77
- join("/")
78
- rx_strict = Regexp.new("#{rx_strict}/#{Regexp.quote(directories.last)}$")
79
-
80
- candidates_strict = []
81
- installation_manifest.each do |pkg|
82
- name = pkg.name
83
- if name =~ rx
84
- candidates << pkg
85
- end
86
- if name =~ rx_strict
87
- candidates_strict << pkg
88
- end
96
+ if candidates.size > 1 && candidates_strict.size == 1
97
+ candidates_strict
98
+ else
99
+ candidates
100
+ end
101
+ end
102
+
103
+ def initialize_from_workspace
104
+ initialize_and_load
105
+ finalize_setup # this exports the manifest
106
+
107
+ @packages = ws.manifest.each_autobuild_package.to_a
108
+ @package_sets = ws.manifest.each_package_set.to_a
109
+ end
110
+
111
+ def run(selections, cache: !!packages, build: false, prefix: false)
112
+ if !cache
113
+ initialize_from_workspace
114
+ end
115
+
116
+ if selections.empty?
117
+ if prefix || build
118
+ puts ws.prefix_dir
119
+ else
120
+ puts ws.root_dir
89
121
  end
122
+ end
90
123
 
91
- if candidates.size > 1 && candidates_strict.size == 1
92
- candidates = candidates_strict
124
+ selections.each do |string|
125
+ if File.directory?(string)
126
+ string = "#{File.expand_path(string)}/"
93
127
  end
128
+ puts location_of(string, build: build, prefix: prefix)
129
+ end
130
+ end
131
+
132
+ def location_of(selection, prefix: false, build: false)
133
+ if pkg_set = find_package_set(selection)
134
+ return pkg_set.user_local_dir
94
135
  end
95
136
 
96
- if candidates.size > 1
137
+ matching_packages = find_packages(selection)
138
+ if matching_packages.empty?
139
+ matching_packages = find_packages_with_directory_shortnames(selection)
140
+ end
141
+
142
+ if matching_packages.size > 1
97
143
  # If there is more than one candidate, check if there are some that are not
98
144
  # present on disk
99
- present = candidates.find_all { |pkg| File.directory?(pkg.srcdir) }
145
+ present = matching_packages.find_all { |pkg| File.directory?(pkg.srcdir) }
100
146
  if present.size == 1
101
- candidates = present
147
+ matching_packages = present
102
148
  end
103
149
  end
104
150
 
105
- if candidates.empty?
106
- raise ArgumentError, "cannot find #{selection} in the current autoproj installation"
107
- elsif candidates.size > 1
108
- raise ArgumentError, "multiple packages match #{selection} in the current autoproj installation: #{candidates.map(&:name).sort.join(", ")}"
151
+ if matching_packages.empty?
152
+ raise NotFound, "cannot find '#{selection}' in the current autoproj installation"
153
+ elsif matching_packages.size > 1
154
+ raise AmbiguousSelection, "multiple packages match '#{selection}' in the current autoproj installation: #{matching_packages.map(&:name).sort.join(", ")}"
109
155
  else
110
- puts result_value(candidates.first, options)
156
+ pkg = matching_packages.first
157
+ if prefix
158
+ pkg.prefix
159
+ elsif build
160
+ if pkg.respond_to?(:builddir) && pkg.builddir
161
+ pkg.builddir
162
+ else
163
+ raise ArgumentError, "#{pkg.name} does not have a build directory"
164
+ end
165
+ else
166
+ pkg.srcdir
167
+ end
111
168
  end
112
169
  end
113
170
  end
@@ -1,6 +1,7 @@
1
1
  require 'thor'
2
2
  require 'tty/color'
3
3
  require 'autoproj/cli/main_test'
4
+ require 'autoproj/cli/main_plugin'
4
5
 
5
6
  module Autoproj
6
7
  module CLI
@@ -27,7 +28,7 @@ class Main < Thor
27
28
  default: TTY::Color.color?
28
29
 
29
30
  no_commands do
30
- def run_autoproj_cli(filename, classname, report_options, *args)
31
+ def run_autoproj_cli(filename, classname, report_options, *args, **extra_options)
31
32
  require "autoproj/cli/#{filename}"
32
33
  Autoproj.report(Hash[silent: !options[:debug], debug: options[:debug]].merge(report_options)) do
33
34
  options = self.options.dup
@@ -37,7 +38,7 @@ def run_autoproj_cli(filename, classname, report_options, *args)
37
38
  options[:only_local] = options.delete('local')
38
39
  end
39
40
  cli = CLI.const_get(classname).new
40
- run_args = cli.validate_options(args, options)
41
+ run_args = cli.validate_options(args, options.merge(extra_options))
41
42
  cli.run(*run_args)
42
43
  end
43
44
  end
@@ -54,7 +55,7 @@ def bootstrap(*args)
54
55
  if !File.directory?(File.join(Dir.pwd, '.autoproj'))
55
56
  require 'autoproj/ops/install'
56
57
  ops = Autoproj::Ops::Install.new(Dir.pwd)
57
- remaining = ops.parse_options(args)
58
+ ops.parse_options(args)
58
59
  ops.run
59
60
  exec Gem.ruby, $0, 'bootstrap', *args
60
61
  end
@@ -75,6 +76,9 @@ def envsh
75
76
  desc: "use the VCS information as 'versions --no-local' would detect it instead of the one in the configuration"
76
77
  option :parallel, aliases: :p, type: :numeric,
77
78
  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
78
82
  def status(*packages)
79
83
  run_autoproj_cli(:status, :Status, Hash[], *packages)
80
84
  end
@@ -163,10 +167,14 @@ def clean(*packages)
163
167
  end
164
168
 
165
169
  desc 'locate [PACKAGE]', 'return the path to the given package, or the path to the root if no packages are given on the command line'
170
+ option :cache, type: :boolean,
171
+ desc: 'controls whether the resolution should be done by loading the whole configuration (false, slow) or through a cache file (the default)'
172
+ option :prefix, aliases: :p, type: :boolean,
173
+ desc: "outputs the package's prefix directory instead of its source directory"
166
174
  option :build, aliases: :b, type: :boolean,
167
175
  desc: "outputs the package's build directory instead of its source directory"
168
- def locate(package = nil)
169
- run_autoproj_cli(:locate, :Locate, Hash[], *Array(package))
176
+ def locate(*packages)
177
+ run_autoproj_cli(:locate, :Locate, Hash[], *packages)
170
178
  end
171
179
 
172
180
  desc 'reconfigure', 'pass through all configuration questions'
@@ -184,6 +192,9 @@ def reconfigure
184
192
  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"
185
193
  option :env, type: :boolean,
186
194
  desc: "display the package's own environment", default: false
195
+ option :short, desc: 'display a package summary with one package line'
196
+ option :recursive, desc: 'display the package and their dependencies (the default is to only display selected packages)',
197
+ type: :boolean, default: false
187
198
  def show(*packages)
188
199
  run_autoproj_cli(:show, :Show, Hash[], *packages)
189
200
  end
@@ -335,6 +346,21 @@ def install_stage2(root_dir, *vars)
335
346
  end
336
347
  ops.stage2(*vars)
337
348
  end
349
+
350
+ desc 'plugin', 'interface to manage autoproj plugins'
351
+ subcommand 'plugin', MainPlugin
352
+
353
+ desc 'patch', 'applies patches necessary for the selected package',
354
+ hide: true
355
+ def patch(*packages)
356
+ run_autoproj_cli(:patcher, :Patcher, Hash[], *packages, patch: true)
357
+ end
358
+
359
+ desc 'unpatch', 'remove any patch applied on the selected package',
360
+ hide: true
361
+ def unpatch(*packages)
362
+ run_autoproj_cli(:patcher, :Patcher, Hash[], *packages, patch: false)
363
+ end
338
364
  end
339
365
  end
340
366
  end
@@ -0,0 +1,79 @@
1
+ module Autoproj
2
+ module CLI
3
+ class MainPlugin < Thor
4
+ namespace 'plugin'
5
+
6
+ no_commands do
7
+ def ws
8
+ @ws ||= Workspace.from_pwd
9
+ end
10
+
11
+ def install_plugins
12
+ ws.load_config
13
+ ws.update_autoproj(restart_on_update: false)
14
+ end
15
+
16
+ def read_plugin_list
17
+ ws.load_config
18
+ ws.config.get('plugins', Hash.new)
19
+ end
20
+
21
+ def write_plugin_list(plugins)
22
+ ws.load_config
23
+ ws.config.set('plugins', plugins)
24
+ ws.save_config
25
+ end
26
+ end
27
+
28
+ desc 'install NAME', 'install or upgrade an autoproj plugin'
29
+ option :version, desc: 'a gem version constraint',
30
+ type: 'string', default: '>= 0'
31
+ option :git, desc: 'checkout a git repository instead of downloading the gem',
32
+ type: 'string'
33
+ option :path, desc: 'use the plugin that is already present on this path',
34
+ type: 'string'
35
+ def install(name)
36
+ require 'autoproj'
37
+
38
+ gem_options = Hash.new
39
+ if options[:git] && options[:path]
40
+ raise ArgumentError, "you can provide only one of --git or --path"
41
+ elsif options[:git]
42
+ gem_options[:git] = options[:git]
43
+ elsif options[:path]
44
+ gem_options[:path] = options[:path]
45
+ end
46
+
47
+ plugins = read_plugin_list
48
+ updated_plugins = plugins.merge(name => [options[:version], gem_options])
49
+ write_plugin_list(updated_plugins)
50
+ begin
51
+ install_plugins
52
+ rescue Exception
53
+ write_plugin_list(plugins)
54
+ install_plugins
55
+ raise
56
+ end
57
+ end
58
+
59
+ desc 'list', 'list installed plugins'
60
+ def list
61
+ require 'autoproj'
62
+ read_plugin_list.sort_by(&:first).each do |name, (version, options)|
63
+ args = [version, *options.map { |k, v| "#{k}: \"#{v}\"" }]
64
+ puts "#{name}: #{args.join(", ")}"
65
+ end
66
+ end
67
+
68
+ desc 'remove NAME', 'uninstall a plugin'
69
+ def remove(name)
70
+ require 'autoproj'
71
+ plugins = read_plugin_list
72
+ updated_plugins = plugins.dup
73
+ updated_plugins.delete(name)
74
+ write_plugin_list(updated_plugins)
75
+ install_plugins
76
+ end
77
+ end
78
+ end
79
+ end
@@ -4,13 +4,21 @@ class MainTest < Thor
4
4
  namespace 'test'
5
5
 
6
6
  default_command 'exec'
7
+
8
+ no_commands do
9
+ def report(report_options = Hash.new)
10
+ Autoproj.report(Hash[silent: !options[:debug], debug: options[:debug]].merge(report_options)) do
11
+ yield
12
+ end
13
+ end
14
+ end
7
15
 
8
16
  desc 'enable [PACKAGES]', 'enable tests for the given packages (or for all packages if none are given)'
9
17
  option :deps, type: :boolean, default: false,
10
18
  desc: 'controls whether the dependencies of the packages given on the command line should be enabled as well (the default is not)'
11
19
  def enable(*packages)
12
20
  require 'autoproj/cli/test'
13
- Autoproj.report(silent: true) do
21
+ report(silent: true) do
14
22
  cli = Test.new
15
23
  args = cli.validate_options(packages, options)
16
24
  cli.enable(*args)
@@ -22,7 +30,7 @@ def enable(*packages)
22
30
  desc: 'controls whether the dependencies of the packages given on the command line should be disabled as well (the default is not)'
23
31
  def disable(*packages)
24
32
  require 'autoproj/cli/test'
25
- Autoproj.report(silent: true) do
33
+ report(silent: true) do
26
34
  cli = Test.new
27
35
  args = cli.validate_options(packages, options)
28
36
  cli.disable(*args)
@@ -30,11 +38,11 @@ def disable(*packages)
30
38
  end
31
39
 
32
40
  desc 'list [PACKAGES]', 'show test enable/disable status for the given packages (or all packages if none are given)'
33
- option :deps, type: :boolean, default: false,
41
+ option :deps, type: :boolean, default: true,
34
42
  desc: 'controls whether the dependencies of the packages given on the command line should be disabled as well (the default is not)'
35
43
  def list(*packages)
36
44
  require 'autoproj/cli/test'
37
- Autoproj.report(silent: true) do
45
+ report(silent: true) do
38
46
  cli = Test.new
39
47
  args = cli.validate_options(packages, options)
40
48
  cli.list(*args)
@@ -44,10 +52,16 @@ def list(*packages)
44
52
  desc 'exec [PACKAGES]', 'execute the tests for the given packages, or all if no packages are given on the command line'
45
53
  option :deps, type: :boolean, default: false,
46
54
  desc: 'controls whether to execute the tests of the dependencies of the packages given on the command line (the default is not)'
55
+ option :fail, type: :boolean, default: true,
56
+ desc: 'return with a nonzero exit code if the test does not pass'
57
+ option :coverage, type: :boolean, default: false,
58
+ desc: 'whether code coverage should be generated if possible'
47
59
  def exec(*packages)
48
60
  require 'autoproj/cli/test'
49
- Autoproj.report do
61
+ report do
50
62
  cli = Test.new
63
+ Autobuild.pass_test_errors = options[:fail]
64
+ Autobuild::TestUtility.coverage_enabled = options[:coverage]
51
65
  args = cli.validate_options(packages, options)
52
66
  cli.run(*args)
53
67
  end