autoproj 1.4.4 → 1.5.0

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.
@@ -12,7 +12,17 @@ ruby18:
12
12
  - dev-lang/ruby:1.8
13
13
 
14
14
  ruby19:
15
- debian,ubuntu:
15
+ debian:
16
+ squeeze,sid:
17
+ - ruby1.9.1
18
+ - ruby1.9.1-dev
19
+ - rubygems1.9.1
20
+ stable:
21
+ - ruby1.9.1
22
+ - ruby1.9.1-dev
23
+ - rubygems1.9.1
24
+
25
+ ubuntu:
16
26
  - ruby1.9.1
17
27
  - ruby1.9.1-dev
18
28
  - rubygems1.9.1
@@ -46,7 +56,7 @@ autoproj: gem
46
56
  # The following definitions are for the VCS and build systems
47
57
  git:
48
58
  debian,ubuntu: git-core
49
- gentoo: dev-util/git
59
+ gentoo: dev-vcs/git
50
60
  arch: git
51
61
  svn:
52
62
  debian,ubuntu: subversion
@@ -3,18 +3,6 @@ require 'utilrb/kernel/options'
3
3
  require 'nokogiri'
4
4
  require 'set'
5
5
 
6
- module Autobuild
7
- class Package
8
- def os_packages
9
- @os_packages || Array.new
10
- end
11
- def depends_on_os_package(name)
12
- @os_packages ||= Array.new
13
- @os_packages << name
14
- end
15
- end
16
- end
17
-
18
6
  module Autoproj
19
7
  @build_system_dependencies = Set.new
20
8
 
@@ -106,13 +94,22 @@ module Autoproj
106
94
  @type == 'local'
107
95
  end
108
96
 
97
+ def self.to_absolute_url(url, root_dir = nil)
98
+ # NOTE: we MUST use nil as default argument of root_dir as we don't
99
+ # want to call Autoproj.root_dir unless completely necessary
100
+ # (to_absolute_url might be called on installations that are being
101
+ # bootstrapped, and as such don't have a root dir yet).
102
+ url = Autoproj.single_expansion(url, 'HOME' => ENV['HOME'])
103
+ if url && url !~ /^(\w+:\/)?\/|^\w+\@|^(\w+\@)?[\w\.-]+:/
104
+ url = File.expand_path(url, root_dir || Autoproj.root_dir)
105
+ end
106
+ url
107
+ end
108
+
109
109
  def create_autobuild_importer
110
110
  return if type == "none"
111
111
 
112
- url = Autoproj.single_expansion(self.url, 'HOME' => ENV['HOME'])
113
- if url && url !~ /^(\w+:\/)?\/|^\w+\@|^(\w+\@)?[\w\.-]+:/
114
- url = File.expand_path(url, Autoproj.root_dir)
115
- end
112
+ url = VCSDefinition.to_absolute_url(self.url)
116
113
  Autobuild.send(type, url, options)
117
114
  end
118
115
 
@@ -196,26 +193,44 @@ module Autoproj
196
193
 
197
194
  # True if this source has already been checked out on the local autoproj
198
195
  # installation
199
- def present?; File.directory?(local_dir) end
196
+ def present?; File.directory?(raw_local_dir) end
200
197
  # True if this source is local, i.e. is not under a version control
201
198
  def local?; vcs.local? end
202
199
  # True if this source defines nothing
203
200
  def empty?
204
201
  !source_definition['version_control'] &&
205
202
  !each_package.find { true } &&
206
- !File.exists?(File.join(local_dir, "overrides.rb")) &&
207
- !File.exists?(File.join(local_dir, "init.rb"))
203
+ !File.exists?(File.join(raw_local_dir, "overrides.rb")) &&
204
+ !File.exists?(File.join(raw_local_dir, "init.rb"))
208
205
  end
209
206
 
210
- # The directory in which data for this source will be checked out
211
- def local_dir
207
+ def raw_local_dir
212
208
  if local?
213
- vcs.url
209
+ return vcs.url
214
210
  else
215
211
  File.join(Autoproj.remotes_dir, automatic_name)
216
212
  end
217
213
  end
218
214
 
215
+ def user_local_dir
216
+ if local?
217
+ return vcs.url
218
+ else
219
+ File.join(Autoproj.config_dir, 'remotes', name)
220
+ end
221
+ end
222
+
223
+ # The directory in which data for this source will be checked out
224
+ def local_dir
225
+ ugly_dir = raw_local_dir
226
+ pretty_dir = user_local_dir
227
+ if File.symlink?(pretty_dir) && File.readlink(pretty_dir) == ugly_dir
228
+ pretty_dir
229
+ else
230
+ ugly_dir
231
+ end
232
+ end
233
+
219
234
  # A name generated from the VCS url
220
235
  def automatic_name
221
236
  vcs.to_s.gsub(/[^\w]/, '_')
@@ -237,7 +252,7 @@ module Autoproj
237
252
  raise InternalError, "source #{vcs} has not been fetched yet, cannot load description for it"
238
253
  end
239
254
 
240
- source_file = File.join(local_dir, "source.yml")
255
+ source_file = File.join(raw_local_dir, "source.yml")
241
256
  if !File.exists?(source_file)
242
257
  raise ConfigError, "source #{vcs.type}:#{vcs.url} should have a source.yml file, but does not"
243
258
  end
@@ -255,21 +270,30 @@ module Autoproj
255
270
  source_definition
256
271
  end
257
272
 
273
+ # Load and validate the name from the YAML hash
258
274
  def load_name
259
- definition = raw_description_file
275
+ definition = @source_definition || raw_description_file
260
276
  @name = definition['name']
261
- if @name == "local"
277
+
278
+ if @name !~ /^[\w_\.-]+$/
279
+ raise ConfigError, "invalid source name '#{@name}': source names can only contain alphanumeric characters, and .-_"
280
+ elsif @name == "local"
262
281
  raise ConfigError, "source #{self} is named 'local', but this is a reserved name"
263
282
  end
264
283
 
265
284
  rescue InternalError
266
285
  end
267
286
 
287
+ def source_file
288
+ File.join(local_dir, 'source.yml')
289
+ end
290
+
268
291
  # Load the source.yml file that describes this source, and resolve the
269
292
  # $BLABLA values that are in there. Use #raw_description_file to avoid
270
293
  # resolving those values
271
294
  def load_description_file
272
295
  @source_definition = raw_description_file
296
+ load_name
273
297
 
274
298
  # Compute the definition of constants
275
299
  begin
@@ -342,8 +366,12 @@ module Autoproj
342
366
  urls['HOME'] = ENV['HOME']
343
367
 
344
368
  all_vcs = source_definition['version_control']
345
- if all_vcs && !all_vcs.kind_of?(Array)
346
- raise ConfigError, "wrong format for the version_control field"
369
+ if all_vcs
370
+ if all_vcs.kind_of?(Hash)
371
+ raise ConfigError, "wrong format for the version_control field, you forgot the '-' in front of the package names"
372
+ elsif !all_vcs.kind_of?(Array)
373
+ raise ConfigError, "wrong format for the version_control field"
374
+ end
347
375
  end
348
376
 
349
377
  vcs_spec = Hash.new
@@ -412,7 +440,7 @@ module Autoproj
412
440
  Autoproj.normalize_vcs_definition(vcs_spec)
413
441
  end
414
442
  rescue ConfigError => e
415
- raise ConfigError, "#{e.message} in the source.yml file of #{name} (#{File.join(local_dir, "source.yml")})", e.backtrace
443
+ raise ConfigError, "#{e.message} in #{source_file}", e.backtrace
416
444
  end
417
445
 
418
446
  def each_package
@@ -439,8 +467,12 @@ module Autoproj
439
467
  def load_name
440
468
  end
441
469
 
470
+ def source_file
471
+ File.join(Autoproj.config_dir, "overrides.yml")
472
+ end
473
+
442
474
  def raw_description_file
443
- path = File.join(Autoproj.config_dir, "overrides.yml")
475
+ path = source_file
444
476
  if File.file?(path)
445
477
  begin
446
478
  data = YAML.load(File.read(path)) || Hash.new
@@ -458,7 +490,7 @@ module Autoproj
458
490
  PackageDefinition = Struct.new :autobuild, :user_block, :package_set, :file
459
491
 
460
492
  class Manifest
461
- FakePackage = Struct.new :text_name, :name, :srcdir, :importer
493
+ FakePackage = Struct.new :text_name, :name, :srcdir, :importer, :updated
462
494
  class FakePackage
463
495
  def autoproj_name; name end
464
496
  def import
@@ -503,6 +535,10 @@ module Autoproj
503
535
 
504
536
  attr_reader :file
505
537
 
538
+ def auto_update?
539
+ !!data['auto_update']
540
+ end
541
+
506
542
  def initialize(file, data)
507
543
  @file = file
508
544
  @data = data
@@ -633,36 +669,26 @@ module Autoproj
633
669
  return @sources.each(&block)
634
670
  end
635
671
 
636
- # Load the local source first ...
672
+ all_sources = []
673
+
674
+ (data['package_sets'] || []).each do |spec|
675
+ all_sources << source_from_spec(spec, load_description)
676
+ end
677
+
678
+ # Now load the local source
637
679
  local = LocalSource.new
638
680
  if load_description
639
681
  local.load_description_file
640
682
  else
641
683
  local.load_name
642
684
  end
643
- if load_description
644
- if !local.empty?
645
- @sources = [local]
646
- else
647
- @sources = []
648
- end
649
- else
650
- yield(local)
651
- end
652
-
653
- return if !data['package_sets']
654
-
655
- data['package_sets'].each do |spec|
656
- source = source_from_spec(spec, load_description)
657
- if load_description
658
- @sources << source
659
- else
660
- yield(source)
661
- end
685
+ if !load_description || !local.empty?
686
+ all_sources << local
662
687
  end
663
688
 
689
+ all_sources.each(&block)
664
690
  if load_description
665
- @sources.each(&block)
691
+ @sources = all_sources
666
692
  end
667
693
  end
668
694
 
@@ -704,6 +730,13 @@ module Autoproj
704
730
  self
705
731
  end
706
732
 
733
+ # Creates an autobuild package whose job is to allow the import of a
734
+ # specific repository into a given directory.
735
+ #
736
+ # +vcs+ is the VCSDefinition file describing the repository, +text_name+
737
+ # the name used when displaying the import progress, +pkg_name+ the
738
+ # internal name used to represent the package and +into+ the directory
739
+ # in which the package should be checked out.
707
740
  def self.create_autobuild_package(vcs, text_name, pkg_name, into)
708
741
  importer = vcs.create_autobuild_importer
709
742
  return if !importer # updates have been disabled by using the 'none' type
@@ -716,6 +749,9 @@ module Autoproj
716
749
  raise ConfigError, "cannot import #{name}: #{e.message}", e.backtrace
717
750
  end
718
751
 
752
+ # Imports or updates a source (remote or otherwise).
753
+ #
754
+ # See create_autobuild_package for informations about the arguments.
719
755
  def self.update_source(vcs, text_name, pkg_name, into)
720
756
  fake_package = create_autobuild_package(vcs, text_name, pkg_name, into)
721
757
  fake_package.import
@@ -724,15 +760,38 @@ module Autoproj
724
760
  raise ConfigError, "cannot import #{name}: #{e.message}", e.backtrace
725
761
  end
726
762
 
763
+ # Updates the main autoproj configuration
727
764
  def update_yourself
728
765
  Manifest.update_source(vcs, "autoproj main configuration", "autoproj_conf", Autoproj.config_dir)
729
766
  end
730
767
 
768
+ # Updates all the remote sources in ROOT_DIR/.remotes, as well as the
769
+ # symbolic links in ROOT_DIR/autoproj/remotes
731
770
  def update_remote_sources
732
771
  # Iterate on the remote sources, without loading the source.yml
733
772
  # file (we're not ready for that yet)
773
+ sources = []
734
774
  each_remote_source(false) do |source|
735
- Manifest.update_source(source.vcs, source.name || source.vcs.url, source.automatic_name, source.local_dir)
775
+ Manifest.update_source(source.vcs, source.name || source.vcs.url, source.automatic_name, source.raw_local_dir)
776
+ sources << source
777
+ end
778
+
779
+ # Check for directories in ROOT_DIR/.remotes that do not map to a
780
+ # source repository, and remove them
781
+ Dir.glob(File.join(Autoproj.remotes_dir, '*')).each do |dir|
782
+ dir = File.expand_path(dir)
783
+ if File.directory?(dir) && !sources.any? { |s| s.raw_local_dir == dir }
784
+ FileUtils.rm_rf dir
785
+ end
786
+ end
787
+
788
+ remotes_symlinks_dir = File.join(Autoproj.config_dir, 'remotes')
789
+ FileUtils.rm_rf remotes_symlinks_dir
790
+ FileUtils.mkdir remotes_symlinks_dir
791
+ # Create symbolic links from .remotes/weird_url to
792
+ # autoproj/remotes/name
793
+ each_remote_source(false) do |source|
794
+ FileUtils.ln_sf source.raw_local_dir, File.join(remotes_symlinks_dir, source.name)
736
795
  end
737
796
  end
738
797
 
@@ -772,7 +831,8 @@ module Autoproj
772
831
  # by S1
773
832
  def load_importers
774
833
  packages.each_value do |pkg|
775
- vcs = importer_definition_for(pkg.autobuild.name, pkg.package_set)
834
+ vcs = importer_definition_for(pkg.autobuild.name, pkg.package_set) ||
835
+ importer_definition_for("default", pkg.package_set)
776
836
 
777
837
  if vcs
778
838
  Autoproj.add_build_system_dependency vcs.type
@@ -876,21 +936,6 @@ module Autoproj
876
936
  yield
877
937
  end
878
938
 
879
- def handle_enabled_packages(selected_packages)
880
- handled_packages = Set.new
881
- each_package_set(selected_packages) do |name, packages, enabled_packages|
882
- packages -= handled_packages
883
- enabled_packages -= handled_packages
884
-
885
- in_sublayout(name, packages) do
886
- if !packages.empty?
887
- yield(name, packages, enabled_packages)
888
- end
889
- end
890
- handled_packages |= packages
891
- end
892
- end
893
-
894
939
  def default_packages
895
940
  names = if layout = data['layout']
896
941
  layout_packages(layout, true)
@@ -925,10 +970,7 @@ module Autoproj
925
970
  manifest = PackageManifest.load(package, manifest_path)
926
971
  package_manifests[package.name] = manifest
927
972
 
928
- manifest.each_package_dependency do |name|
929
- if Autoproj.verbose
930
- STDERR.puts " #{package.name} depends on #{name}"
931
- end
973
+ manifest.each_dependency do |name|
932
974
  begin
933
975
  package.depends_on name
934
976
  rescue Autobuild::ConfigException => e
@@ -959,18 +1001,14 @@ module Autoproj
959
1001
  required_os_packages = Set.new
960
1002
  package_os_deps = Hash.new { |h, k| h[k] = Array.new }
961
1003
  packages.each do |pkg_name|
962
- if manifest = package_manifests[pkg_name]
963
- manifest.each_os_dependency.each do |osdep_name|
964
- package_os_deps[osdep_name] << pkg_name
965
- required_os_packages << osdep_name
966
- end
1004
+ pkg = Autobuild::Package[pkg_name]
1005
+ if !pkg
1006
+ raise InternalError, "internal error: #{pkg_name} is not a package"
967
1007
  end
968
1008
 
969
- if pkg = Autobuild::Package[pkg_name]
970
- pkg.os_packages.each do |osdep_name|
971
- package_os_deps[osdep_name] << pkg_name
972
- required_os_packages << osdep_name
973
- end
1009
+ pkg.os_packages.each do |osdep_name|
1010
+ package_os_deps[osdep_name] << pkg_name
1011
+ required_os_packages << osdep_name
974
1012
  end
975
1013
  end
976
1014
 
@@ -1020,11 +1058,12 @@ module Autoproj
1020
1058
  if layout_name[0..-1] =~ Regexp.new("#{sel}\/?$")
1021
1059
  expanded_packages.concat(packages.to_a)
1022
1060
  else
1023
- packages = packages.find_all do |pkg_name|
1024
- sel =~ Regexp.new(Regexp.quote(layout_name + pkg_name))
1061
+ match = Regexp.new("^#{Regexp.quote(sel)}")
1062
+ Autobuild::Package.each(true) do |name, pkg|
1063
+ if pkg.srcdir =~ match
1064
+ expanded_packages << name
1065
+ end
1025
1066
  end
1026
- expanded_packages.concat(packages)
1027
- !packages.empty?
1028
1067
  end
1029
1068
  end
1030
1069
  end
@@ -1032,14 +1071,19 @@ module Autoproj
1032
1071
  end
1033
1072
  end
1034
1073
 
1035
- # The singleton manifest object on which the current run works
1036
1074
  class << self
1075
+ # The singleton manifest object on which the current run works
1037
1076
  attr_accessor :manifest
1077
+
1078
+ # The operating system package definitions
1079
+ attr_accessor :osdeps
1038
1080
  end
1039
1081
 
1040
1082
  class PackageManifest
1041
1083
  def self.load(package, file)
1042
- doc = Nokogiri::XML(File.read(file))
1084
+ doc = Nokogiri::XML(File.read(file)) do |c|
1085
+ c.noblanks
1086
+ end
1043
1087
  PackageManifest.new(package, doc)
1044
1088
  end
1045
1089
 
@@ -1053,6 +1097,15 @@ module Autoproj
1053
1097
  @xml = doc
1054
1098
  end
1055
1099
 
1100
+ def each_dependency(&block)
1101
+ if block_given?
1102
+ each_os_dependency(&block)
1103
+ each_package_dependency(&block)
1104
+ else
1105
+ enum_for(:each_dependency, &block)
1106
+ end
1107
+ end
1108
+
1056
1109
  def each_os_dependency
1057
1110
  if block_given?
1058
1111
  xml.xpath('//rosdep').each do |node|
@@ -2,12 +2,12 @@ require 'tempfile'
2
2
  module Autoproj
3
3
  class OSDependencies
4
4
  def self.load(file)
5
- data =
6
- begin
7
- YAML.load(File.read(file))
8
- rescue ArgumentError => e
9
- raise ConfigError, "error in #{file}: #{e.message}"
10
- end
5
+ begin
6
+ data = YAML.load(File.read(file))
7
+ verify_definitions(data)
8
+ rescue ArgumentError => e
9
+ raise ConfigError, "error in #{file}: #{e.message}"
10
+ end
11
11
 
12
12
  OSDependencies.new(data)
13
13
  end
@@ -47,6 +47,23 @@ module Autoproj
47
47
  @definitions = definitions.merge(info.definitions)
48
48
  end
49
49
 
50
+ def self.verify_definitions(hash = nil)
51
+ hash ||= definitions
52
+ hash.each do |key, value|
53
+ if !key.kind_of?(String)
54
+ raise ArgumentError, "invalid osdeps definition: found an #{key.class}. Don't forget to put quotes around numbers"
55
+ end
56
+ next if !value
57
+ if value.kind_of?(Array) || value.kind_of?(Hash)
58
+ verify_definitions(value)
59
+ else
60
+ if !value.kind_of?(String)
61
+ raise ArgumentError, "invalid osdeps definition: found an #{value.class}. Don't forget to put quotes around numbers"
62
+ end
63
+ end
64
+ end
65
+ end
66
+
50
67
  def operating_system
51
68
  if @operating_system
52
69
  return @operating_system
@@ -144,7 +161,9 @@ module Autoproj
144
161
  version_entry = data.find do |version_list, data|
145
162
  version_list.to_s.split(',').
146
163
  map(&:downcase).
147
- any? { |v| os_version.include?(v) }
164
+ any? do |v|
165
+ os_version.any? { |osv| Regexp.new(v) =~ osv }
166
+ end
148
167
  end
149
168
 
150
169
  if !version_entry
@@ -168,8 +187,24 @@ module Autoproj
168
187
  "\n" + shell_snippets
169
188
  end
170
189
 
190
+ # Returns true if there is an operating-system package with that name,
191
+ # and false otherwise
192
+ def has?(name)
193
+ partition_packages([name].to_set)
194
+ true
195
+ rescue ConfigError
196
+ false
197
+ end
198
+
171
199
  # call-seq:
172
200
  # partition_packages(package_names) => os_packages, gem_packages
201
+ #
202
+ # Resolves the package names listed in +package_set+, and returns a set
203
+ # of packages that have to be installed using the platform's native
204
+ # package manager, and the set of packages that have to be installed
205
+ # using Ruby's package manager, RubyGems.
206
+ #
207
+ # Raises ConfigError if no package can be found
173
208
  def partition_packages(package_set, package_osdeps = Hash.new)
174
209
  package_set = package_set.
175
210
  map { |name| OSDependencies.aliases[name] || name }.