autobuild 1.7.10 → 1.7.11.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.
@@ -27,12 +27,15 @@ lib/autobuild/packages/gnumake.rb
27
27
  lib/autobuild/packages/import.rb
28
28
  lib/autobuild/packages/orogen.rb
29
29
  lib/autobuild/packages/pkgconfig.rb
30
+ lib/autobuild/packages/ruby.rb
31
+ lib/autobuild/utility.rb
30
32
  lib/autobuild/parallel.rb
31
33
  lib/autobuild/pkgconfig.rb
32
34
  lib/autobuild/reporting.rb
33
35
  lib/autobuild/subcommand.rb
34
36
  lib/autobuild/timestamps.rb
35
37
  lib/autobuild/version.rb
38
+ lib/autobuild/rake_task_extension.rb
36
39
  samples/openrobots.autobuild
37
40
  test/data/cvsroot.tar
38
41
  test/data/svnroot.tar
@@ -4,11 +4,40 @@ if defined? Rake::DSL
4
4
  include Rake::DSL
5
5
  end
6
6
 
7
+ module Autobuild
8
+ end
9
+
10
+ begin
11
+ require 'rmail'
12
+ require 'rmail/serialize'
13
+ Autobuild::HAS_RMAIL = true
14
+ rescue LoadError
15
+ Autobuild::HAS_RMAIL = false
16
+ end
17
+
18
+ require 'net/smtp'
19
+ require 'socket'
20
+ require 'etc'
21
+ require 'find'
22
+ require 'thread'
23
+ require 'pathname'
24
+ require 'shellwords'
25
+ require 'find'
26
+ require 'rake/tasklib'
27
+ require 'fileutils'
28
+
7
29
  require 'autobuild/version'
8
- require 'autobuild/config'
9
- require 'autobuild/configurable'
10
30
  require 'autobuild/environment'
11
31
  require 'autobuild/exceptions'
32
+ require 'autobuild/pkgconfig'
33
+ require 'autobuild/reporting'
34
+ require 'autobuild/subcommand'
35
+ require 'autobuild/timestamps'
36
+ require 'autobuild/parallel'
37
+ require 'autobuild/utility'
38
+ require 'autobuild/config'
39
+
40
+ require 'autobuild/importer'
12
41
  require 'autobuild/import/cvs'
13
42
  require 'autobuild/import/darcs'
14
43
  require 'autobuild/importer'
@@ -17,6 +46,9 @@ require 'autobuild/import/hg'
17
46
  require 'autobuild/import/svn'
18
47
  require 'autobuild/import/archive'
19
48
  require 'autobuild/import/tar'
49
+
50
+ require 'autobuild/package'
51
+ require 'autobuild/configurable'
20
52
  require 'autobuild/packages/autotools'
21
53
  require 'autobuild/packages/cmake'
22
54
  require 'autobuild/packages/genom'
@@ -24,9 +56,7 @@ require 'autobuild/packages/import'
24
56
  require 'autobuild/packages/orogen'
25
57
  require 'autobuild/packages/pkgconfig'
26
58
  require 'autobuild/packages/dummy'
27
- require 'autobuild/pkgconfig'
28
- require 'autobuild/reporting'
29
- require 'autobuild/subcommand'
30
- require 'autobuild/timestamps'
31
- require 'autobuild/parallel'
59
+ require 'autobuild/packages/ruby'
60
+
61
+ require 'autobuild/rake_task_extension'
32
62
 
@@ -33,14 +33,47 @@ end
33
33
  module Autobuild
34
34
  class << self
35
35
  %w{ nice srcdir prefix
36
- verbose debug do_update do_build do_rebuild do_forced_build only_doc do_doc doc_errors
36
+ verbose debug do_update do_build do_rebuild do_forced_build
37
37
  daemonize clean_log packages default_packages
38
- doc_prefix keep_oldlogs}.each do |name|
38
+ keep_oldlogs}.each do |name|
39
39
  attr_accessor name
40
40
  end
41
41
 
42
+ # @return [{String=>Class<Utility>}] the known utilities
43
+ # @see {register_utility_class}
44
+ attr_reader :utilities
45
+
46
+ def register_utility_class(name, klass)
47
+ utilities[name] = klass
48
+ singleton_class.class_eval do
49
+ attr_accessor "only_#{name}"
50
+ attr_accessor "do_#{name}"
51
+ attr_accessor "#{name}_prefix"
52
+ attr_accessor "pass_#{name}_errors"
53
+ end
54
+ instance_variable_set "@only_#{name}", false
55
+ instance_variable_set "@do_#{name}", false
56
+ instance_variable_set "@pass_#{name}_errors", false
57
+ instance_variable_set "@#{name}_prefix", name
58
+ end
59
+
60
+ def create_utility(utility_name, package)
61
+ if klass = utilities[utility_name]
62
+ package.utilities[utility_name] = klass.new(utility_name, package)
63
+ else raise ArgumentError, "there is no utility called #{utility_name}, available utilities are #{utilities.keys.sort.join(", ")}"
64
+ end
65
+ end
66
+
42
67
  # Configure the programs used by different packages
43
68
  attr_reader :programs
69
+ # A cache of entries in programs to their resolved full path
70
+ #
71
+ # @return [{String=>[String,String,String]}] the triplet (full path,
72
+ # tool name, value of ENV['PATH']). The last two values are used to
73
+ # invalidate the cache when needed
74
+ #
75
+ # @see tool_in_path
76
+ attr_reader :programs_in_path
44
77
  # The directory in which logs are saved. Defaults to PREFIX/log.
45
78
  attr_writer :logdir
46
79
 
@@ -52,6 +85,9 @@ module Autobuild
52
85
  do_build && !only_doc && packages.empty?
53
86
  end
54
87
  end
88
+ @utilities = Hash.new
89
+ register_utility_class 'doc', Utility
90
+ register_utility_class 'test', Utility
55
91
 
56
92
  @console = HighLine.new
57
93
 
@@ -74,11 +110,10 @@ module Autobuild
74
110
  DEFAULT_OPTIONS = { :nice => nil,
75
111
  :srcdir => Dir.pwd, :prefix => Dir.pwd, :logdir => nil,
76
112
  :verbose => false, :debug => false, :do_build => true, :do_forced_build => false, :do_rebuild => false, :do_update => true,
77
- :daemonize => false, :packages => [], :default_packages => [],
78
- :only_doc => false, :do_doc => true, :doc_errors => false,
79
- :doc_prefix => 'doc', :keep_oldlogs => false }
113
+ :daemonize => false, :packages => [], :default_packages => [], :keep_oldlogs => false }
80
114
 
81
115
  @programs = Hash.new
116
+ @programs_in_path = Hash.new
82
117
  DEFAULT_OPTIONS.each do |name, value|
83
118
  send("#{name}=", value)
84
119
  end
@@ -167,6 +202,40 @@ module Autobuild
167
202
  programs[name.to_sym] || programs[name.to_s] || name.to_s
168
203
  end
169
204
 
205
+ # Resolves the absolute path to a given tool
206
+ def tool_in_path(name)
207
+ path, path_name, path_env = programs_in_path[name]
208
+ current = tool(name)
209
+ if path_env != ENV['PATH'] || path_name != current
210
+ # Delete the current entry given that it is invalid
211
+ programs_in_path.delete(name)
212
+ if current[0, 1] == "/"
213
+ # This is already a full path
214
+ path = current
215
+ else
216
+ path = ENV['PATH'].split(':').
217
+ find { |dir| File.exists?(File.join(dir, current)) }
218
+ if path
219
+ path = File.join(path, current)
220
+ end
221
+ end
222
+
223
+ if !path
224
+ raise ArgumentError, "tool #{name}, set to #{current}, can not be found in PATH=#{path_env}"
225
+ end
226
+
227
+ # Verify that the new value is a file and is executable
228
+ if !File.file?(path)
229
+ raise ArgumentError, "tool #{name} is set to #{current}, but this resolves to #{path} which is not a file"
230
+ elsif !File.executable?(path)
231
+ raise ArgumentError, "tool #{name} is set to #{current}, but this resolves to #{path} which is not executable"
232
+ end
233
+ programs_in_path[name] = [path, current, ENV['PATH']]
234
+ end
235
+
236
+ return path
237
+ end
238
+
170
239
  # Gets autobuild options from the command line and returns the
171
240
  # remaining elements
172
241
  def commandline(args)
@@ -192,7 +261,7 @@ module Autobuild
192
261
  opts.on("--rebuild", "clean and rebuild") do |v| Autobuild.do_forced_build = v end
193
262
  opts.on("--only-doc", "only generate documentation") do |v| Autobuild.only_doc = v end
194
263
  opts.on("--no-doc", "don't generate documentation") do |v| Autobuild.do_doc = v end
195
- opts.on("--doc-errors", "treat documentation failure as error") do |v| Autobuild.doc_errors = v end
264
+ opts.on("--doc-errors", "treat documentation failure as error") do |v| Autobuild.pass_doc_errors = v end
196
265
 
197
266
  opts.separator ""
198
267
  opts.separator "Program output"
@@ -239,7 +308,7 @@ module Autobuild
239
308
  end
240
309
  end
241
310
 
242
- def self.apply(packages, buildname = "autobuild")
311
+ def self.apply(packages, buildname = "autobuild", phases = [])
243
312
  if Autobuild.mail[:to]
244
313
  if !Autobuild::HAS_RMAIL
245
314
  Autobuild.warn "RMail is not available. Mail notification is disabled"
@@ -261,13 +330,16 @@ module Autobuild
261
330
  end
262
331
  end
263
332
 
264
- if Autobuild.only_doc
265
- phases = ['doc']
266
- else
267
- phases = ['import']
268
- phases += ['prepare', 'build'] if Autobuild.do_build
269
- phases << 'doc' if Autobuild.do_doc
333
+ if phases.empty?
334
+ if Autobuild.only_doc
335
+ phases = ['doc']
336
+ else
337
+ phases = ['import']
338
+ phases += ['prepare', 'build'] if Autobuild.do_build
339
+ phases << 'doc' if Autobuild.do_doc
340
+ end
270
341
  end
342
+
271
343
  phases.each do |phase|
272
344
  # We create a dummy task listing what needs to be done, and then we
273
345
  # call it
@@ -1,10 +1,3 @@
1
- require 'pathname'
2
- require 'autobuild/timestamps'
3
- require 'autobuild/environment'
4
- require 'autobuild/package'
5
- require 'autobuild/subcommand'
6
- require 'shellwords'
7
-
8
1
  module Autobuild
9
2
  # Base class for packages that require a configuration + build step.
10
3
  #
@@ -414,10 +414,9 @@ module Autobuild
414
414
  end
415
415
 
416
416
  require 'rbconfig'
417
- ruby_arch = File.basename(RbConfig::CONFIG['archdir'])
418
- candidates = %w{rubylibdir archdir sitelibdir sitearchdir vendorlibdir vendorarchdir}.
417
+ %w{rubylibdir archdir sitelibdir sitearchdir vendorlibdir vendorarchdir}.
419
418
  map { |key| RbConfig::CONFIG[key] }.
420
- map { |path| path.gsub(/.*lib(?:32|64)?\/(\w*ruby\/)/, '\\1') }.
419
+ map { |path| path.gsub(/.*lib(?:32|64)?\//, '\\1') }.
421
420
  each do |subdir|
422
421
  if File.directory?("#{newprefix}/lib/#{subdir}")
423
422
  env_add_path("RUBYLIB", "#{newprefix}/lib/#{subdir}")
@@ -32,6 +32,30 @@ module Autobuild
32
32
  # Known URI schemes for +url+
33
33
  VALID_URI_SCHEMES = [ 'file', 'http', 'https', 'ftp' ]
34
34
 
35
+ class << self
36
+ # The directory in which downloaded files are saved
37
+ #
38
+ # It defaults, by order of priority, to the archives/ subdirectory
39
+ # of the environment variable AUTOBUILD_CACHE_DIR (if set), to the
40
+ # AUTOBUILD_ARCHIVES_CACHE_DIR (if set) environment variable and to
41
+ # #{prefix}/cache
42
+ def cachedir
43
+ if @cachedir then @cachedir
44
+ elsif dir = ENV['AUTOBUILD_ARCHIVES_CACHE_DIR']
45
+ @cachedir = File.expand_path(dir)
46
+ elsif dir = ENV['AUTOBUILD_CACHE_DIR']
47
+ @cachedir = File.join(File.expand_path(dir), 'archives')
48
+ else
49
+ @cachedir = "#{Autobuild.prefix}/cache"
50
+ end
51
+ end
52
+
53
+ # Sets the directory in which files get cached
54
+ attr_writer :cachedir
55
+ end
56
+
57
+ @cachedir = nil
58
+
35
59
  # Returns the unpack mode from the file name
36
60
  def self.filename_to_mode(filename)
37
61
  case filename
@@ -112,7 +136,7 @@ module Autobuild
112
136
  size = File.stat(@url.path).size
113
137
  mtime = File.stat(@url.path).mtime
114
138
  else
115
- open @url, :content_length_proc => lambda { |size| } do |file|
139
+ open @url, :content_length_proc => lambda { |v| size = v } do |file|
116
140
  mtime = file.last_modified
117
141
  end
118
142
  end
@@ -163,7 +187,9 @@ module Autobuild
163
187
  # The unpack mode. One of Zip, Bzip, Gzip or Plain
164
188
  attr_reader :mode
165
189
  # The directory in which remote files are cached
166
- def cachedir; @options[:cachedir] end
190
+ #
191
+ # Defaults to ArchiveImporter.cachedir
192
+ attr_accessor :cachedir
167
193
  # The directory contained in the tar file
168
194
  #
169
195
  # DEPRECATED use #archive_dir instead
@@ -192,7 +218,7 @@ module Autobuild
192
218
  if !@options.has_key?(:update_cached_file)
193
219
  @options[:update_cached_file] = false
194
220
  end
195
- @options[:cachedir] ||= "#{Autobuild.prefix}/cache"
221
+ @cachedir = @options[:cachedir] || ArchiveImporter.cachedir
196
222
 
197
223
  relocate(url)
198
224
  end
@@ -214,7 +240,11 @@ module Autobuild
214
240
  end
215
241
  end
216
242
 
217
- def update(package) # :nodoc:
243
+ def update(package,only_local = false) # :nodoc:
244
+ if only_local
245
+ Autobuild.warn "The importer #{self.class} does not support local updates, skipping #{self}"
246
+ return
247
+ end
218
248
  needs_update = update_cache(package)
219
249
 
220
250
  if !File.file?(checkout_digest_stamp(package))
@@ -1,7 +1,3 @@
1
- require 'autobuild/config'
2
- require 'autobuild/subcommand'
3
- require 'autobuild/importer'
4
-
5
1
  module Autobuild
6
2
  class CVSImporter < Importer
7
3
  # Creates a new importer which gets the module +name+ from the
@@ -38,7 +34,11 @@ module Autobuild
38
34
 
39
35
  private
40
36
 
41
- def update(package) # :nodoc:
37
+ def update(package,only_local=false) # :nodoc:
38
+ if only_local
39
+ Autobuild.warn "The importer #{self.class} does not support local updates, skipping #{self}"
40
+ return
41
+ end
42
42
  Dir.chdir(package.srcdir) do
43
43
  if !File.exists?("#{package.srcdir}/CVS/Root")
44
44
  raise ConfigException.new(package, 'import'), "#{package.srcdir} is not a CVS working copy"
@@ -22,7 +22,11 @@ module Autobuild
22
22
 
23
23
  private
24
24
 
25
- def update(package) # :nodoc:
25
+ def update(package,only_local=false) # :nodoc:
26
+ if only_local
27
+ Autobuild.warn "The importer #{self.class} does not support local updates, skipping #{self}"
28
+ return
29
+ end
26
30
  if !File.directory?( File.join(package.srcdir, '_darcs') )
27
31
  raise ConfigException.new(package, 'import'), "#{package.srcdir} is not a Darcs repository"
28
32
  end
@@ -5,6 +5,36 @@ require 'utilrb/kernel/options'
5
5
 
6
6
  module Autobuild
7
7
  class Git < Importer
8
+ class << self
9
+ # Sets the default alternates path used by all Git importers
10
+ #
11
+ # Setting it explicitly overrides any value we get from the
12
+ # AUTOBUILD_CACHE_DIR and AUTOBUILD_GIT_CACHE_DIR environment
13
+ # variables.
14
+ #
15
+ # @see default_alternates
16
+ attr_writer :default_alternates
17
+
18
+ # A default list of repositories that should be used as reference
19
+ # repositories for all Git importers
20
+ #
21
+ # It is initialized (by order of priority) using the
22
+ # AUTOBUILD_GIT_CACHE_DIR and AUTOBUILD_CACHE_DIR environment
23
+ # variables
24
+ #
25
+ # @return [Array]
26
+ # @see default_alternates=, Git#alternates
27
+ def default_alternates
28
+ if @default_alternates then @default_alternates
29
+ elsif cache_dir = ENV['AUTOBUILD_GIT_CACHE_DIR']
30
+ @default_alternates = cache_dir.split(':').map { |path| File.expand_path(path) }
31
+ elsif cache_dir = ENV['AUTOBUILD_CACHE_DIR']
32
+ @default_alternates = cache_dir.split(':').map { |path| File.join(File.expand_path(path), 'git') }
33
+ else Array.new
34
+ end
35
+ end
36
+ end
37
+
8
38
  # Creates an importer which tracks the given repository
9
39
  # and branch. +source+ is [repository, branch]
10
40
  #
@@ -14,6 +44,7 @@ module Autobuild
14
44
  # Autobuild.programs['git'] = 'my_git_tool'
15
45
  def initialize(repository, branch = nil, options = {})
16
46
  @repository = repository.to_str
47
+ @alternates = Git.default_alternates.dup
17
48
 
18
49
  if branch.respond_to?(:to_hash)
19
50
  options = branch.to_hash
@@ -28,11 +59,12 @@ module Autobuild
28
59
  Autobuild.warn " Autobuild.git 'git://gitorious.org/rock/buildconf.git', :branch => 'master'"
29
60
  end
30
61
 
31
- gitopts, common = Kernel.filter_options options, :push_to => nil, :branch => nil, :tag => nil, :commit => nil
62
+ gitopts, common = Kernel.filter_options options, :push_to => nil, :branch => nil, :tag => nil, :commit => nil, :with_submodules => false
32
63
  if gitopts[:branch] && branch
33
64
  raise ConfigException, "git branch specified with both the option hash and the explicit parameter"
34
65
  end
35
66
  @push_to = gitopts[:push_to]
67
+ @with_submodules = gitopts[:with_submodules]
36
68
  branch = gitopts[:branch] || branch
37
69
  tag = gitopts[:tag]
38
70
  commit = gitopts[:commit]
@@ -40,6 +72,7 @@ module Autobuild
40
72
  @branch = branch || 'master'
41
73
  @tag = tag
42
74
  @commit = commit
75
+ @remote_name = 'autobuild'
43
76
  super(common)
44
77
  end
45
78
 
@@ -50,6 +83,11 @@ module Autobuild
50
83
  "git:#{repository}"
51
84
  end
52
85
 
86
+ # The name of the remote that should be set up by the importer
87
+ #
88
+ # Defaults to 'autobuild'
89
+ attr_accessor :remote_name
90
+
53
91
  # The remote repository URL.
54
92
  #
55
93
  # See also #push_to
@@ -67,6 +105,11 @@ module Autobuild
67
105
  # Defaults to #branch
68
106
  attr_writer :remote_branch
69
107
 
108
+ # Set to true if checkout should be done with submodules
109
+ #
110
+ # Defaults to #false
111
+ attr_writer :with_submodules
112
+
70
113
  # The branch this importer is tracking
71
114
  #
72
115
  # If set, both commit and tag have to be nil.
@@ -77,6 +120,24 @@ module Autobuild
77
120
  # If not set, it defaults to #branch
78
121
  attr_writer :local_branch
79
122
 
123
+ # A list of local (same-host) repositories that will be used instead of
124
+ # the remote one when possible. It has one major issue (see below), so
125
+ # use at your own risk.
126
+ #
127
+ # The paths must point to the git directory, so either the .git
128
+ # directory in a checked out git repository, or the repository itself in
129
+ # a bare repository.
130
+ #
131
+ # A default reference repository can be given through the
132
+ # AUTOBUILD_GIT_CACHE environment variable.
133
+ #
134
+ # Note that it has the major caveat that if objects disappear from the
135
+ # reference repository, the current one will be broken. See the git
136
+ # documentation for more information.
137
+ #
138
+ # @return [Array<String>]
139
+ attr_accessor :alternates
140
+
80
141
  # The branch that should be used on the local clone
81
142
  #
82
143
  # Defaults to #branch
@@ -106,6 +167,10 @@ module Autobuild
106
167
  # a fast-forward
107
168
  def merge?; !!@merge end
108
169
 
170
+ #Return true if the git checkout should be done with submodules
171
+ #detaul it false
172
+ def with_submodules?; !!@with_submodules end
173
+
109
174
  # Set the merge flag. See #merge?
110
175
  def merge=(flag); @merge = flag end
111
176
 
@@ -151,70 +216,73 @@ module Autobuild
151
216
  end
152
217
  end
153
218
 
219
+ def update_cache(package, cache_dir, phase)
220
+ remote_name = package.name.gsub(/[^\w]/, '_')
221
+ Subprocess.run(*git, "remote.#{remote_name}.url", repository)
222
+ Subprocess.run(*git, "remote.#{remote_name}.fetch", "+refs/heads/*:refs/remotes/#{remote_name}/*")
223
+ Subprocess.run(*git, 'fetch', '--tags', remote_name)
224
+ end
225
+
226
+ # Updates the git repository's configuration for the target remote
227
+ def update_remotes_configuration(package, phase)
228
+ git = [package, phase, Autobuild.tool(:git), '--git-dir', File.join(package.importdir, '.git'), 'config', '--replace-all']
229
+ Subprocess.run(*git, "remote.#{remote_name}.url", repository)
230
+ if push_to
231
+ Subprocess.run(*git, "remote.#{remote_name}.pushurl", push_to)
232
+ end
233
+ Subprocess.run(*git, "remote.#{remote_name}.fetch", "+refs/heads/*:refs/remotes/#{remote_name}/*")
234
+
235
+ if remote_branch && local_branch
236
+ Subprocess.run(*git, "remote.#{remote_name}.push", "refs/heads/#{local_branch}:refs/heads/#{remote_branch}")
237
+ else
238
+ Subprocess.run(*git, "remote.#{remote_name}.push", "refs/heads/*:refs/heads/*")
239
+ end
240
+
241
+ if local_branch
242
+ Subprocess.run(*git, "branch.#{local_branch}.remote", remote_name)
243
+ Subprocess.run(*git, "branch.#{local_branch}.merge", "refs/heads/#{local_branch}")
244
+ end
245
+ end
246
+
154
247
  # Fetches updates from the remote repository. Returns the remote commit
155
248
  # ID on success, nil on failure. Expects the current directory to be the
156
249
  # package's source directory.
157
250
  def fetch_remote(package)
158
251
  validate_importdir(package)
159
- Dir.chdir(package.importdir) do
160
- # If we are checking out a specific commit, we don't know which
161
- # branch to refer to in git fetch. So, we have to set up the
162
- # remotes and call git fetch directly (so that all branches get
163
- # fetch)
164
- #
165
- # Otherwise, do git fetch now
166
- #
167
- # Doing it now is better as it makes sure that we replace the
168
- # configuration parameters only if the repository and branch are
169
- # OK (i.e. we keep old working configuration instead)
170
- if branch || tag
171
- Subprocess.run(package, :import, Autobuild.tool('git'), 'fetch', repository, branch || tag)
172
- elsif commit
173
- Subprocess.run(package, :import, Autobuild.tool('git'), 'fetch', repository)
174
- end
175
-
176
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
177
- "--replace-all", "remote.autobuild.url", repository)
178
- if push_to
179
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
180
- "--replace-all", "remote.autobuild.pushurl", push_to)
181
- end
182
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
183
- "--replace-all", "remote.autobuild.fetch", "+refs/heads/*:refs/remotes/autobuild/*")
184
-
185
- if remote_branch && local_branch
186
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
187
- "--replace-all", "remote.autobuild.push", "refs/heads/#{local_branch}:refs/heads/#{remote_branch}")
188
- else
189
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
190
- "--replace-all", "remote.autobuild.push", "refs/heads/*:refs/heads/*")
191
- end
192
-
193
- if local_branch
194
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
195
- "--replace-all", "branch.#{local_branch}.remote", "autobuild")
196
- Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
197
- "--replace-all", "branch.#{local_branch}.merge", "refs/heads/#{local_branch}")
198
- end
199
-
200
- # Now get the actual commit ID from the FETCH_HEAD file, and
201
- # return it
202
- commit_id = if File.readable?( File.join('.git', 'FETCH_HEAD') )
203
- fetch_commit = File.readlines( File.join('.git', 'FETCH_HEAD') ).
204
- delete_if { |l| l =~ /not-for-merge/ }
205
- if !fetch_commit.empty?
206
- fetch_commit.first.split(/\s+/).first
207
- end
208
- end
209
-
210
- # Update the remote tag if needs be
211
- if branch && commit_id
212
- Subprocess.run(package, :import, Autobuild.tool('git'), 'update-ref',
213
- "-m", "updated by autobuild", "refs/remotes/autobuild/#{remote_branch}", commit_id)
252
+ git = [package, :import, Autobuild.tool('git'), '--git-dir', File.join(package.importdir, '.git')]
253
+
254
+ # If we are checking out a specific commit, we don't know which
255
+ # branch to refer to in git fetch. So, we have to set up the
256
+ # remotes and call git fetch directly (so that all branches get
257
+ # fetch)
258
+ #
259
+ # Otherwise, do git fetch now
260
+ #
261
+ # Doing it now is better as it makes sure that we replace the
262
+ # configuration parameters only if the repository and branch are
263
+ # OK (i.e. we keep old working configuration instead)
264
+ refspec = [branch || tag].compact
265
+ Subprocess.run(*git, 'fetch', '--tags', repository, *refspec)
266
+
267
+ update_remotes_configuration(package, :import)
268
+
269
+ # Now get the actual commit ID from the FETCH_HEAD file, and
270
+ # return it
271
+ commit_id = if File.readable?( File.join(package.importdir, '.git', 'FETCH_HEAD') )
272
+ fetch_commit = File.readlines( File.join(package.importdir, '.git', 'FETCH_HEAD') ).
273
+ delete_if { |l| l =~ /not-for-merge/ }
274
+ if !fetch_commit.empty?
275
+ fetch_commit.first.split(/\s+/).first
214
276
  end
277
+ end
215
278
 
216
- commit_id
279
+ # Update the remote tag if needs be
280
+ if branch && commit_id
281
+ Subprocess.run(*git, 'update-ref',
282
+ "-m", "updated by autobuild", "refs/remotes/#{remote_name}/#{remote_branch}", commit_id)
217
283
  end
284
+
285
+ commit_id
218
286
  end
219
287
 
220
288
  # Returns a Importer::Status object that represents the status of this
@@ -224,7 +292,7 @@ module Autobuild
224
292
  validate_importdir(package)
225
293
  remote_commit = nil
226
294
  if only_local
227
- remote_commit = `git show-ref -s refs/remotes/autobuild/#{remote_branch}`.chomp
295
+ remote_commit = `git show-ref -s refs/remotes/#{remote_name}/#{remote_branch}`.chomp
228
296
  else
229
297
  remote_commit =
230
298
  begin fetch_remote(package)
@@ -355,10 +423,48 @@ module Autobuild
355
423
  Status.new(status, fetch_commit, head_commit, common_commit)
356
424
  end
357
425
 
358
- def update(package)
426
+ # Updates the git alternates file in the already checked out package to
427
+ # match {#alternates}
428
+ #
429
+ # @param [Package] package the already checked-out package
430
+ # @return [void]
431
+ def update_alternates(package)
432
+ alternates_path = File.join(package.importdir, '.git', 'objects', 'info', 'alternates')
433
+ current_alternates =
434
+ if File.file?(alternates_path)
435
+ File.readlines(alternates_path).map(&:strip).find_all { |l| !l.empty? }
436
+ else Array.new
437
+ end
438
+
439
+ alternates = self.alternates.map do |path|
440
+ File.join(path, 'objects')
441
+ end
442
+
443
+ if current_alternates.sort != alternates.sort
444
+ # Warn that something is fishy, but assume that the user knows
445
+ # what he is doing
446
+ package.warn "%s: the list of git alternates listed in the repository differs from the one set up in autobuild."
447
+ package.warn "%s: I will update, but that is dangerous"
448
+ package.warn "%s: using git alternates is for advanced users only, who know git very well."
449
+ package.warn "%s: Don't complain if something breaks"
450
+ end
451
+ if alternates.empty?
452
+ FileUtils.rm_f alternates_path
453
+ else
454
+ File.open(alternates_path, 'w') do |io|
455
+ io.write alternates.join("\n")
456
+ end
457
+ end
458
+ end
459
+
460
+ def update(package,only_local = false)
359
461
  validate_importdir(package)
462
+ update_alternates(package)
360
463
  Dir.chdir(package.importdir) do
361
- fetch_commit = fetch_remote(package)
464
+ #Checking if we should only merge our repro to remotes/HEAD without updateing from the remote side...
465
+ if !only_local
466
+ fetch_commit = fetch_remote(package)
467
+ end
362
468
 
363
469
  # If we are tracking a commit/tag, just check it out and return
364
470
  if commit || tag
@@ -429,17 +535,25 @@ module Autobuild
429
535
  FileUtils.mkdir_p base_dir
430
536
  end
431
537
 
538
+ clone_options = ['-o', remote_name]
539
+
540
+ if with_submodules?
541
+ clone_options << '--recurse-submodules'
542
+ end
543
+ alternates.each do |path|
544
+ clone_options << '--reference' << path
545
+ end
432
546
  Subprocess.run(package, :import,
433
- Autobuild.tool('git'), 'clone', '-o', 'autobuild', repository, package.importdir)
547
+ Autobuild.tool('git'), 'clone', *clone_options, repository, package.importdir)
434
548
 
435
549
  Dir.chdir(package.importdir) do
436
550
  if push_to
437
551
  Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
438
- "--replace-all", "remote.autobuild.pushurl", push_to)
552
+ "--replace-all", "remote.#{remote_name}.pushurl", push_to)
439
553
  end
440
554
  if local_branch && remote_branch
441
555
  Subprocess.run(package, :import, Autobuild.tool('git'), 'config',
442
- "--replace-all", "remote.autobuild.push", "refs/heads/#{local_branch}:refs/heads/#{remote_branch}")
556
+ "--replace-all", "remote.#{remote_name}.push", "refs/heads/#{local_branch}:refs/heads/#{remote_branch}")
443
557
  end
444
558
 
445
559
  # If we are tracking a commit/tag, just check it out
@@ -453,10 +567,10 @@ module Autobuild
453
567
  current_branch = `git symbolic-ref HEAD`.chomp
454
568
  if current_branch == "refs/heads/#{local_branch}"
455
569
  Subprocess.run(package, :import, Autobuild.tool('git'),
456
- 'reset', '--hard', "autobuild/#{branch}")
570
+ 'reset', '--hard', "#{remote_name}/#{branch}")
457
571
  else
458
572
  Subprocess.run(package, :import, Autobuild.tool('git'),
459
- 'checkout', '-b', local_branch, "autobuild/#{branch}")
573
+ 'checkout', '-b', local_branch, "#{remote_name}/#{branch}")
460
574
  end
461
575
  end
462
576
  end
@@ -466,6 +580,38 @@ module Autobuild
466
580
  def relocate(repository)
467
581
  @repository = repository
468
582
  end
583
+
584
+ # Tests whether the given directory is a git repository
585
+ def self.can_handle?(path)
586
+ File.directory?(File.join(path, '.git'))
587
+ end
588
+
589
+ # Returns a hash that represents the configuration of a git importer
590
+ # based on the information contained in the git configuration
591
+ #
592
+ # @raise [ArgumentError] if the path does not point to a git repository
593
+ def self.vcs_definition_for(path)
594
+ if !can_handle?(path)
595
+ raise ArgumentError, "#{path} is not a git repository"
596
+ end
597
+
598
+ Dir.chdir(path) do
599
+ vars = `git config -l`.
600
+ split("\n").
601
+ inject(Hash.new) do |h, line|
602
+ k, v = line.strip.split('=', 2)
603
+ h[k] = v
604
+ h
605
+ end
606
+ url = vars["remote.#{remote_name}.url"] ||
607
+ vars['remote.origin.url']
608
+ if url
609
+ return Hash[:type => :git, :url => url]
610
+ else
611
+ return Hash[:type => :git]
612
+ end
613
+ end
614
+ end
469
615
  end
470
616
 
471
617
  # Creates a git importer which gets the source for the given repository and branch