autobuild 1.17.0 → 1.18.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +107 -0
- data/Gemfile +2 -1
- data/Rakefile +1 -4
- data/autobuild.gemspec +14 -11
- data/bin/autobuild +4 -3
- data/lib/autobuild.rb +4 -5
- data/lib/autobuild/build_logfile.rb +6 -4
- data/lib/autobuild/config.rb +90 -40
- data/lib/autobuild/configurable.rb +30 -18
- data/lib/autobuild/environment.rb +126 -120
- data/lib/autobuild/exceptions.rb +48 -31
- data/lib/autobuild/import/archive.rb +134 -82
- data/lib/autobuild/import/cvs.rb +28 -24
- data/lib/autobuild/import/darcs.rb +13 -16
- data/lib/autobuild/import/git-lfs.rb +37 -30
- data/lib/autobuild/import/git.rb +231 -179
- data/lib/autobuild/import/hg.rb +23 -18
- data/lib/autobuild/import/svn.rb +48 -29
- data/lib/autobuild/importer.rb +530 -499
- data/lib/autobuild/mail_reporter.rb +77 -77
- data/lib/autobuild/package.rb +171 -101
- data/lib/autobuild/packages/autotools.rb +47 -42
- data/lib/autobuild/packages/cmake.rb +71 -65
- data/lib/autobuild/packages/dummy.rb +9 -8
- data/lib/autobuild/packages/genom.rb +1 -1
- data/lib/autobuild/packages/gnumake.rb +19 -13
- data/lib/autobuild/packages/import.rb +2 -6
- data/lib/autobuild/packages/orogen.rb +32 -31
- data/lib/autobuild/packages/pkgconfig.rb +2 -2
- data/lib/autobuild/packages/python.rb +7 -2
- data/lib/autobuild/packages/ruby.rb +22 -17
- data/lib/autobuild/parallel.rb +35 -39
- data/lib/autobuild/pkgconfig.rb +25 -13
- data/lib/autobuild/progress_display.rb +23 -23
- data/lib/autobuild/rake_task_extension.rb +6 -6
- data/lib/autobuild/reporting.rb +38 -26
- data/lib/autobuild/subcommand.rb +72 -65
- data/lib/autobuild/test.rb +8 -7
- data/lib/autobuild/test_utility.rb +10 -9
- data/lib/autobuild/timestamps.rb +28 -23
- data/lib/autobuild/tools.rb +17 -16
- data/lib/autobuild/utility.rb +16 -18
- data/lib/autobuild/version.rb +1 -1
- metadata +39 -38
data/lib/autobuild/import/cvs.rb
CHANGED
@@ -6,15 +6,14 @@ class CVSImporter < Importer
|
|
6
6
|
# [:cvsco] options to give to 'cvs co'. Default: -P.
|
7
7
|
#
|
8
8
|
# This importer uses the 'cvs' tool to perform the import. It defaults
|
9
|
-
# to 'cvs' and can be configured by doing
|
9
|
+
# to 'cvs' and can be configured by doing
|
10
10
|
# Autobuild.programs['cvs'] = 'my_cvs_tool'
|
11
11
|
def initialize(root_name, options = {})
|
12
|
-
cvsopts, common = Kernel.filter_options options,
|
12
|
+
cvsopts, common = Kernel.filter_options options,
|
13
|
+
module: nil, cvsup: '-dP', cvsco: '-P'
|
13
14
|
@root = root_name
|
14
15
|
@module = cvsopts[:module]
|
15
|
-
|
16
|
-
raise ArgumentError, "no module given"
|
17
|
-
end
|
16
|
+
raise ArgumentError, "no module given" unless @module
|
18
17
|
|
19
18
|
@options_up = cvsopts[:cvsup] || '-dP'
|
20
19
|
@options_up = Array[*@options_up]
|
@@ -27,53 +26,59 @@ def initialize(root_name, options = {})
|
|
27
26
|
attr_reader :options_co
|
28
27
|
# Array of options to give to 'cvs update'
|
29
28
|
attr_reader :options_up
|
30
|
-
|
31
|
-
# Returns the module to get
|
32
|
-
def modulename; @module end
|
33
29
|
|
34
|
-
|
30
|
+
# Returns the module to get
|
31
|
+
def modulename
|
32
|
+
@module
|
33
|
+
end
|
35
34
|
|
36
35
|
def update(package, options = Hash.new) # :nodoc:
|
37
36
|
if options[:only_local]
|
38
|
-
package.warn "%s: the CVS importer does not support
|
37
|
+
package.warn "%s: the CVS importer does not support "\
|
38
|
+
"local updates, skipping"
|
39
39
|
return false
|
40
40
|
end
|
41
41
|
|
42
|
-
|
43
|
-
raise ConfigException.new(package, 'import'),
|
42
|
+
unless File.exist?("#{package.srcdir}/CVS/Root")
|
43
|
+
raise ConfigException.new(package, 'import'),
|
44
|
+
"#{package.srcdir} is not a CVS working copy"
|
44
45
|
end
|
45
46
|
|
46
|
-
root = File.open("#{package.srcdir}/CVS/Root"
|
47
|
-
mod = File.open("#{package.srcdir}/CVS/Repository"
|
47
|
+
root = File.open("#{package.srcdir}/CVS/Root", &:read).chomp
|
48
|
+
mod = File.open("#{package.srcdir}/CVS/Repository", &:read).chomp
|
48
49
|
|
49
50
|
# Remove any :ext: in front of the root
|
50
51
|
root = root.gsub(/^:ext:/, '')
|
51
52
|
expected_root = @root.gsub(/^:ext:/, '')
|
52
53
|
# Remove the optional ':' between the host and the path
|
53
|
-
root = root.
|
54
|
-
expected_root = expected_root.
|
54
|
+
root = root.delete(':')
|
55
|
+
expected_root = expected_root.delete(':')
|
55
56
|
|
56
57
|
if root != expected_root || mod != @module
|
57
58
|
raise ConfigException.new(package, 'import'),
|
58
|
-
"checkout in #{package.srcdir} is from #{root}:#{mod},
|
59
|
+
"checkout in #{package.srcdir} is from #{root}:#{mod}, "\
|
60
|
+
"was expecting #{expected_root}:#{@module}"
|
59
61
|
end
|
60
62
|
package.run(:import, Autobuild.tool(:cvs), 'up', *@options_up,
|
61
63
|
retry: true, working_directory: package.importdir)
|
62
|
-
|
64
|
+
# no easy way to check if package was updated, keep previous
|
65
|
+
# behavior and consider updated
|
66
|
+
true
|
63
67
|
end
|
64
68
|
|
65
|
-
def checkout(package,
|
69
|
+
def checkout(package, _options = Hash.new) # :nodoc:
|
66
70
|
head, tail = File.split(package.srcdir)
|
67
71
|
cvsroot = @root
|
68
|
-
|
69
|
-
FileUtils.mkdir_p(head)
|
70
|
-
package.run(:import, Autobuild.tool(:cvs), '-d', cvsroot, 'co',
|
72
|
+
|
73
|
+
FileUtils.mkdir_p(head) unless File.directory?(head)
|
74
|
+
package.run(:import, Autobuild.tool(:cvs), '-d', cvsroot, 'co',
|
75
|
+
'-d', tail, *@options_co, modulename,
|
71
76
|
retry: true, working_directory: head)
|
72
77
|
end
|
73
78
|
end
|
74
79
|
|
75
80
|
# Returns the CVS importer which will get the +name+ module in repository
|
76
|
-
# +repo+. The allowed values in +options+ are described in CVSImporter.new.
|
81
|
+
# +repo+. The allowed values in +options+ are described in CVSImporter.new.
|
77
82
|
def self.cvs(root, options = {}, backward_compatibility = nil)
|
78
83
|
if backward_compatibility
|
79
84
|
backward_compatibility[:module] = options
|
@@ -83,4 +88,3 @@ def self.cvs(root, options = {}, backward_compatibility = nil)
|
|
83
88
|
end
|
84
89
|
end
|
85
90
|
end
|
86
|
-
|
@@ -4,13 +4,13 @@
|
|
4
4
|
|
5
5
|
module Autobuild
|
6
6
|
class DarcsImporter < Importer
|
7
|
-
# Creates a new importer which gets the source from the Darcs
|
8
|
-
# +source+ # The following values are allowed in +options+:
|
7
|
+
# Creates a new importer which gets the source from the Darcs
|
8
|
+
# repository +source+ # The following values are allowed in +options+:
|
9
9
|
# [:get] options to give to 'darcs get'.
|
10
10
|
# [:pull] options to give to 'darcs pull'.
|
11
11
|
#
|
12
12
|
# This importer uses the 'darcs' tool to perform the import. It defaults
|
13
|
-
# to 'darcs' and can be configured by doing
|
13
|
+
# to 'darcs' and can be configured by doing
|
14
14
|
# Autobuild.programs['darcs'] = 'my_darcs_tool'
|
15
15
|
def initialize(source, options = {})
|
16
16
|
@source = source
|
@@ -19,32 +19,30 @@ def initialize(source, options = {})
|
|
19
19
|
@pull = [*options[:pull]]
|
20
20
|
@get = [*options[:get]]
|
21
21
|
end
|
22
|
-
|
23
|
-
private
|
24
22
|
|
25
23
|
def update(package, options = Hash.new) # :nodoc:
|
26
24
|
if options[:only_local]
|
27
|
-
package.warn "%s: the darcs importer does not support
|
25
|
+
package.warn "%s: the darcs importer does not support "\
|
26
|
+
"local updates, skipping"
|
28
27
|
return false
|
29
28
|
end
|
30
|
-
|
29
|
+
unless File.directory?(File.join(package.srcdir, '_darcs'))
|
31
30
|
raise ConfigException.new(package, 'import'),
|
32
31
|
"#{package.srcdir} is not a Darcs repository"
|
33
32
|
end
|
34
33
|
|
35
|
-
package.run(:import, @program,
|
36
|
-
|
34
|
+
package.run(:import, @program, 'pull', '--all',
|
35
|
+
"--repodir=#{package.srcdir}", '--set-scripts-executable',
|
36
|
+
@source, *@pull, retry: true)
|
37
37
|
true # no easy to know if package was updated, keep previous behavior
|
38
38
|
end
|
39
39
|
|
40
|
-
def checkout(package,
|
40
|
+
def checkout(package, _options = Hash.new) # :nodoc:
|
41
41
|
basedir = File.dirname(package.srcdir)
|
42
|
-
unless File.directory?(basedir)
|
43
|
-
FileUtils.mkdir_p(basedir)
|
44
|
-
end
|
42
|
+
FileUtils.mkdir_p(basedir) unless File.directory?(basedir)
|
45
43
|
|
46
|
-
package.run(:import, @program,
|
47
|
-
|
44
|
+
package.run(:import, @program, 'get', '--set-scripts-executable',
|
45
|
+
@source, package.srcdir, *@get, retry: true)
|
48
46
|
end
|
49
47
|
end
|
50
48
|
|
@@ -54,4 +52,3 @@ def self.darcs(source, options = {})
|
|
54
52
|
DarcsImporter.new(source, options)
|
55
53
|
end
|
56
54
|
end
|
57
|
-
|
@@ -3,41 +3,48 @@
|
|
3
3
|
Autobuild::Git.default_config['filter.lfs.required'] = 'false'
|
4
4
|
|
5
5
|
module Autobuild
|
6
|
-
|
7
|
-
|
8
|
-
Autobuild.warn "#{package.name} uses git LFS but it is not installed, files may be missing from checkout"
|
9
|
-
end
|
10
|
-
|
11
|
-
lfs_dir = File.join(package.srcdir, '.git', 'lfs')
|
12
|
-
if File.directory?(lfs_dir)
|
13
|
-
importer.run_git(package, 'lfs', 'install', '--force', '--local', '--skip-smudge')
|
6
|
+
def self.lfs_setup(importer, package)
|
7
|
+
importer.run_git(package, 'lfs', 'install', '--force', '--local', '--skip-smudge')
|
14
8
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
else
|
23
|
-
importer.run_git_bare(package, 'config', '--local', 'lfs.fetchinclude', includes)
|
9
|
+
includes = importer.options.fetch(:lfs_include, '')
|
10
|
+
if includes.empty?
|
11
|
+
begin
|
12
|
+
importer.run_git_bare(package, 'config', '--local',
|
13
|
+
'--unset', 'lfs.fetchinclude')
|
14
|
+
rescue SubcommandFailed => e
|
15
|
+
raise if e.status != 5
|
24
16
|
end
|
17
|
+
else
|
18
|
+
importer.run_git_bare(package, 'config', '--local',
|
19
|
+
'lfs.fetchinclude', includes)
|
20
|
+
end
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
else
|
34
|
-
importer.run_git_bare(package, 'config', '--local', 'lfs.fetchexclude', excludes)
|
22
|
+
excludes = importer.options.fetch(:lfs_exclude, '')
|
23
|
+
if excludes.empty?
|
24
|
+
begin
|
25
|
+
importer.run_git_bare(package, 'config', '--local',
|
26
|
+
'--unset', 'lfs.fetchexclude')
|
27
|
+
rescue SubcommandFailed => e
|
28
|
+
raise if e.status != 5
|
35
29
|
end
|
30
|
+
else
|
31
|
+
importer.run_git_bare(package, 'config', '--local',
|
32
|
+
'lfs.fetchexclude', excludes)
|
33
|
+
end
|
36
34
|
|
37
|
-
|
38
|
-
|
39
|
-
end
|
35
|
+
if importer.options[:lfs] != false
|
36
|
+
importer.run_git(package, 'lfs', 'pull', importer.remote_name)
|
40
37
|
end
|
41
38
|
end
|
42
|
-
end
|
43
39
|
|
40
|
+
Git.add_post_hook(always: true) do |importer, package|
|
41
|
+
wants_lfs = (importer.options[:lfs] != false && importer.uses_lfs?(package))
|
42
|
+
if wants_lfs && !Git.lfs_installed?
|
43
|
+
Autobuild.warn "#{package.name} uses git LFS but it is not installed, "\
|
44
|
+
"files may be missing from checkout"
|
45
|
+
end
|
46
|
+
|
47
|
+
lfs_dir = File.join(package.srcdir, '.git', 'lfs')
|
48
|
+
Autobuild.lfs_setup(importer, package) if File.directory?(lfs_dir)
|
49
|
+
end
|
50
|
+
end
|
data/lib/autobuild/import/git.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require 'autobuild/importer'
|
4
4
|
require 'utilrb/kernel/options'
|
5
5
|
require 'open3'
|
6
|
+
require 'English'
|
6
7
|
|
7
8
|
module Autobuild
|
8
9
|
class Git < Importer
|
@@ -27,8 +28,10 @@ class << self
|
|
27
28
|
# @see default_alternates=, Git#alternates
|
28
29
|
def default_alternates
|
29
30
|
if @default_alternates then @default_alternates
|
30
|
-
elsif cache_dirs = Importer.cache_dirs('git')
|
31
|
-
@default_alternates = cache_dirs.map
|
31
|
+
elsif (cache_dirs = Importer.cache_dirs('git'))
|
32
|
+
@default_alternates = cache_dirs.map do |path|
|
33
|
+
File.join(File.expand_path(path), '%s')
|
34
|
+
end
|
32
35
|
else Array.new
|
33
36
|
end
|
34
37
|
end
|
@@ -44,11 +47,13 @@ def self.default_config
|
|
44
47
|
#
|
45
48
|
# @return [String]
|
46
49
|
def self.version
|
47
|
-
version = Subprocess.run('git', 'setup', Autobuild.tool(:git), '--version').
|
50
|
+
version = Subprocess.run('git', 'setup', Autobuild.tool(:git), '--version').
|
51
|
+
first
|
48
52
|
if version =~ /^git version (\d[\d\.]+)/
|
49
53
|
$1.split(".").map { |i| Integer(i) }
|
50
54
|
else
|
51
|
-
raise ArgumentError, "cannot parse git version string #{version},
|
55
|
+
raise ArgumentError, "cannot parse git version string #{version}, "\
|
56
|
+
"was expecting something looking like 'git version 2.1.0'"
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
@@ -58,9 +63,7 @@ def self.version
|
|
58
63
|
# @return [Integer] -1 if actual is greater than required,
|
59
64
|
# 0 if equal, and 1 if actual is smaller than required
|
60
65
|
def self.compare_versions(actual, required)
|
61
|
-
if actual.size > required.size
|
62
|
-
return -compare_versions(required, actual)
|
63
|
-
end
|
66
|
+
return -compare_versions(required, actual) if actual.size > required.size
|
64
67
|
|
65
68
|
actual += [0] * (required.size - actual.size)
|
66
69
|
actual.zip(required).each do |v_act, v_req|
|
@@ -90,18 +93,19 @@ def self.at_least_version(*version)
|
|
90
93
|
# @param [String] branch deprecated, use the 'branch' named option
|
91
94
|
# instead
|
92
95
|
#
|
93
|
-
# @option options [String] push_to (repository) the URL to set up as
|
94
|
-
# the remote(s). Note that it is not used internally by
|
95
|
-
#
|
96
|
-
#
|
96
|
+
# @option options [String] push_to (repository) the URL to set up as
|
97
|
+
# push_to URL in the remote(s). Note that it is not used internally by
|
98
|
+
# this class
|
99
|
+
# @option options [String] branch (master) the branch we should track.
|
100
|
+
# It is used both as {#local_branch} and {#remote_branch}
|
97
101
|
# @option options [String] tag (nil) a tag at which we should pin the
|
98
102
|
# checkout. Cannot be given at the same time than :commit
|
99
103
|
# @option options [String] commit (nil) a commit ID at which we should pin the
|
100
104
|
# checkout. Cannot be given at the same time than :tag
|
101
|
-
# @option options [String] repository_id (git:#{repository}) a string
|
102
|
-
# uniquely identify a repository. The meaning is
|
103
|
-
# instance, autoproj uses repository_id to check
|
104
|
-
# importers fetches from the same repository.
|
105
|
+
# @option options [String] repository_id (git:#{repository}) a string
|
106
|
+
# that allows to uniquely identify a repository. The meaning is
|
107
|
+
# caller-specific. For instance, autoproj uses repository_id to check
|
108
|
+
# whether two Git importers fetches from the same repository.
|
105
109
|
# @option options [Boolean] with_submodules (false) whether the importer should
|
106
110
|
# checkout and update submodules. Note that in an autobuild-based
|
107
111
|
# workflow, it is recommended to not use submodules but checkout all
|
@@ -115,15 +119,19 @@ def initialize(repository, branch = nil, options = {})
|
|
115
119
|
@merge = false
|
116
120
|
|
117
121
|
if branch.respond_to?(:to_hash)
|
118
|
-
|
122
|
+
options = branch.to_hash
|
123
|
+
branch = nil
|
119
124
|
end
|
120
125
|
|
121
126
|
if branch
|
122
|
-
Autobuild.warn "the git importer now expects you to provide the branch
|
127
|
+
Autobuild.warn "the git importer now expects you to provide the branch "\
|
128
|
+
"as a named option"
|
123
129
|
Autobuild.warn "this form is deprecated:"
|
124
|
-
Autobuild.warn "
|
130
|
+
Autobuild.warn "Autobuild.git 'git://gitorious.org/rock/buildconf.git',"
|
131
|
+
Autobuild.warn " 'master'"
|
125
132
|
Autobuild.warn "and should be replaced by"
|
126
|
-
Autobuild.warn "
|
133
|
+
Autobuild.warn "Autobuild.git 'git://gitorious.org/rock/buildconf.git',"
|
134
|
+
Autobuild.warn " branch: 'master'"
|
127
135
|
end
|
128
136
|
|
129
137
|
gitopts, common = Kernel.filter_options options,
|
@@ -138,7 +146,8 @@ def initialize(repository, branch = nil, options = {})
|
|
138
146
|
with_submodules: false,
|
139
147
|
single_branch: false
|
140
148
|
if gitopts[:branch] && branch
|
141
|
-
raise ConfigException, "git branch specified with both the option hash
|
149
|
+
raise ConfigException, "git branch specified with both the option hash "\
|
150
|
+
"and the explicit parameter"
|
142
151
|
end
|
143
152
|
gitopts[:branch] ||= branch
|
144
153
|
|
@@ -152,6 +161,10 @@ def initialize(repository, branch = nil, options = {})
|
|
152
161
|
@additional_remotes = Array.new
|
153
162
|
end
|
154
163
|
|
164
|
+
def vcs_fingerprint(package)
|
165
|
+
rev_parse(package, 'HEAD')
|
166
|
+
end
|
167
|
+
|
155
168
|
# The name of the remote that should be set up by the importer
|
156
169
|
#
|
157
170
|
# Defaults to 'autobuild'
|
@@ -240,13 +253,17 @@ def remote_branch
|
|
240
253
|
# True if it is allowed to merge remote updates automatically. If false
|
241
254
|
# (the default), the import will fail if the updates do not resolve as
|
242
255
|
# a fast-forward
|
243
|
-
def merge
|
256
|
+
def merge?
|
257
|
+
@merge
|
258
|
+
end
|
244
259
|
|
245
260
|
# Set the merge flag. See #merge?
|
246
|
-
|
261
|
+
attr_writer :merge
|
247
262
|
|
248
263
|
# Whether the git checkout should be done with submodules
|
249
|
-
def with_submodules
|
264
|
+
def with_submodules?
|
265
|
+
@with_submodules
|
266
|
+
end
|
250
267
|
|
251
268
|
# Whether 'clone' should fetch only the remote branch, or all the
|
252
269
|
# branches
|
@@ -255,16 +272,14 @@ def single_branch?
|
|
255
272
|
end
|
256
273
|
|
257
274
|
# Set the {#single_branch?} predicate
|
258
|
-
|
259
|
-
@single_branch = !!flag
|
260
|
-
end
|
275
|
+
attr_writer :single_branch
|
261
276
|
|
262
277
|
# @api private
|
263
278
|
#
|
264
279
|
# Verifies that the package's {Package#importdir} points to a git
|
265
280
|
# repository
|
266
281
|
def validate_importdir(package)
|
267
|
-
|
282
|
+
git_dir(package, true)
|
268
283
|
end
|
269
284
|
|
270
285
|
# @api private
|
@@ -276,16 +291,16 @@ def validate_importdir(package)
|
|
276
291
|
# @return [(String,Symbol),nil] either the path to the git folder and
|
277
292
|
# :bare or :normal, or nil if path is not a git repository.
|
278
293
|
def self.resolve_git_dir(path)
|
279
|
-
|
280
|
-
if
|
281
|
-
dir = path
|
282
|
-
end
|
294
|
+
gitdir = File.join(path, '.git')
|
295
|
+
path = gitdir if File.exist?(gitdir)
|
283
296
|
|
284
|
-
result = `#{Autobuild.tool(:git)} --git-dir="#{
|
285
|
-
|
297
|
+
result = `#{Autobuild.tool(:git)} --git-dir="#{path}" rev-parse \
|
298
|
+
--is-bare-repository 2>&1`
|
299
|
+
if $CHILD_STATUS.success?
|
286
300
|
if result.strip == "true"
|
287
|
-
|
288
|
-
else
|
301
|
+
[path, :bare]
|
302
|
+
else
|
303
|
+
[path, :normal]
|
289
304
|
end
|
290
305
|
end
|
291
306
|
end
|
@@ -337,13 +352,15 @@ def self.git_dir(package, require_working_copy)
|
|
337
352
|
# @return [void]
|
338
353
|
# @raise ConfigException if dir/style are nil, or if
|
339
354
|
# require_working_copy is true and style is :bare
|
340
|
-
def self.validate_git_dir(package, require_working_copy,
|
355
|
+
def self.validate_git_dir(package, require_working_copy, _dir, style)
|
341
356
|
if !style
|
342
357
|
raise ConfigException.new(package, 'import', retry: false),
|
343
|
-
"while importing #{package.name}, #{package.importdir}
|
358
|
+
"while importing #{package.name}, #{package.importdir} "\
|
359
|
+
"does not point to a git repository"
|
344
360
|
elsif require_working_copy && (style == :bare)
|
345
361
|
raise ConfigException.new(package, 'import', retry: false),
|
346
|
-
"while importing #{package.name}, #{package.importdir}
|
362
|
+
"while importing #{package.name}, #{package.importdir} "\
|
363
|
+
"points to a bare git repository but a working copy was required"
|
347
364
|
end
|
348
365
|
end
|
349
366
|
|
@@ -355,11 +372,13 @@ def self.validate_git_dir(package, require_working_copy, dir, style)
|
|
355
372
|
# @raise [ArgumentError] if one of the tags is unknown
|
356
373
|
def delta_between_tags(package, from_tag, to_tag)
|
357
374
|
pkg_tags = tags(package)
|
358
|
-
|
359
|
-
raise ArgumentError, "tag '#{from_tag}' is unknown to #{package.name}
|
375
|
+
unless pkg_tags.key?(from_tag)
|
376
|
+
raise ArgumentError, "tag '#{from_tag}' is unknown to #{package.name} "\
|
377
|
+
"-- known tags are: #{pkg_tags.keys}"
|
360
378
|
end
|
361
|
-
|
362
|
-
raise ArgumentError, "tag '#{to_tag}' is unknown to #{package.name}
|
379
|
+
unless pkg_tags.key?(to_tag)
|
380
|
+
raise ArgumentError, "tag '#{to_tag}' is unknown to #{package.name} "\
|
381
|
+
"-- known tags are: #{pkg_tags.keys}"
|
363
382
|
end
|
364
383
|
|
365
384
|
from_commit = pkg_tags[from_tag]
|
@@ -377,14 +396,14 @@ def delta_between_tags(package, from_tag, to_tag)
|
|
377
396
|
# @return [Hash<String,String>] a mapping from a tag name to its commit
|
378
397
|
# ID
|
379
398
|
def tags(package, options = Hash.new)
|
380
|
-
|
399
|
+
unless options.fetch(:only_local, false)
|
381
400
|
run_git_bare(package, 'fetch', '--tags')
|
382
401
|
end
|
383
402
|
tag_list = run_git_bare(package, 'show-ref', '--tags').map(&:strip)
|
384
403
|
tags = Hash.new
|
385
404
|
tag_list.each do |entry|
|
386
405
|
commit_to_tag = entry.split(" ")
|
387
|
-
tags[commit_to_tag[1].sub("refs/tags/","")] = commit_to_tag[0]
|
406
|
+
tags[commit_to_tag[1].sub("refs/tags/", "")] = commit_to_tag[0]
|
388
407
|
end
|
389
408
|
tags
|
390
409
|
end
|
@@ -405,14 +424,17 @@ def run_git(package, *args)
|
|
405
424
|
#
|
406
425
|
# (see Git#run_git)
|
407
426
|
def self.run_git(package, *args)
|
408
|
-
options =
|
409
|
-
|
410
|
-
|
411
|
-
|
427
|
+
options =
|
428
|
+
if args.last.kind_of?(Hash)
|
429
|
+
args.pop
|
430
|
+
else
|
431
|
+
Hash.new
|
432
|
+
end
|
412
433
|
|
413
434
|
working_directory = File.dirname(git_dir(package, true))
|
414
435
|
package.run(:import, Autobuild.tool(:git), *args,
|
415
|
-
Hash[resolved_env: Hash.new,
|
436
|
+
Hash[resolved_env: Hash.new,
|
437
|
+
working_directory: working_directory].merge(options))
|
416
438
|
end
|
417
439
|
|
418
440
|
# @api private
|
@@ -428,10 +450,13 @@ def run_git_bare(package, *args)
|
|
428
450
|
#
|
429
451
|
# (see Git#run_git_bare)
|
430
452
|
def self.run_git_bare(package, *args)
|
431
|
-
options =
|
432
|
-
|
433
|
-
|
434
|
-
|
453
|
+
options =
|
454
|
+
if args.last.kind_of?(Hash)
|
455
|
+
args.pop
|
456
|
+
else
|
457
|
+
Hash.new
|
458
|
+
end
|
459
|
+
|
435
460
|
package.run(:import, Autobuild.tool(:git),
|
436
461
|
'--git-dir', git_dir(package, false),
|
437
462
|
*args, Hash[resolved_env: Hash.new].merge(options))
|
@@ -441,14 +466,21 @@ def self.run_git_bare(package, *args)
|
|
441
466
|
#
|
442
467
|
# Set a remote up in the repositorie's configuration
|
443
468
|
def setup_remote(package, remote_name, repository, push_to = repository)
|
444
|
-
run_git_bare(package, 'config', '--replace-all',
|
445
|
-
|
446
|
-
run_git_bare(package, 'config', '--replace-all',
|
469
|
+
run_git_bare(package, 'config', '--replace-all',
|
470
|
+
"remote.#{remote_name}.url", repository)
|
471
|
+
run_git_bare(package, 'config', '--replace-all',
|
472
|
+
"remote.#{remote_name}.pushurl", push_to || repository)
|
473
|
+
run_git_bare(package, 'config', '--replace-all',
|
474
|
+
"remote.#{remote_name}.fetch",
|
475
|
+
"+refs/heads/*:refs/remotes/#{remote_name}/*")
|
447
476
|
|
448
477
|
if remote_branch && local_branch
|
449
|
-
run_git_bare(package, 'config', '--replace-all',
|
478
|
+
run_git_bare(package, 'config', '--replace-all',
|
479
|
+
"remote.#{remote_name}.push",
|
480
|
+
"refs/heads/#{local_branch}:#{remote_branch_to_ref(remote_branch)}")
|
450
481
|
else
|
451
|
-
run_git_bare(package, 'config', '--replace-all',
|
482
|
+
run_git_bare(package, 'config', '--replace-all',
|
483
|
+
"remote.#{remote_name}.push", "refs/heads/*:refs/heads/*")
|
452
484
|
end
|
453
485
|
end
|
454
486
|
|
@@ -473,18 +505,21 @@ def update_remotes_configuration(package)
|
|
473
505
|
end
|
474
506
|
|
475
507
|
if local_branch
|
476
|
-
run_git_bare(package, 'config', '--replace-all',
|
477
|
-
|
508
|
+
run_git_bare(package, 'config', '--replace-all',
|
509
|
+
"branch.#{local_branch}.remote", remote_name)
|
510
|
+
run_git_bare(package, 'config', '--replace-all',
|
511
|
+
"branch.#{local_branch}.merge", remote_branch_to_ref(local_branch))
|
478
512
|
end
|
479
513
|
end
|
480
514
|
|
481
515
|
# Resolve a commit ref to a tag or commit ID
|
482
516
|
def describe_rev(package, rev)
|
483
|
-
tag = run_git_bare(package, 'describe',
|
484
|
-
|
517
|
+
tag = run_git_bare(package, 'describe',
|
518
|
+
'--tags', '--exact-match', rev).first.strip
|
519
|
+
[true, tag.encode('UTF-8')]
|
485
520
|
rescue Autobuild::SubcommandFailed
|
486
521
|
commit = rev_parse(package, rev)
|
487
|
-
|
522
|
+
[false, commit.encode('UTF-8')]
|
488
523
|
end
|
489
524
|
|
490
525
|
# Enumerates the ref that are present on the remote
|
@@ -492,12 +527,11 @@ def describe_rev(package, rev)
|
|
492
527
|
# @yieldparam [String] ref_name the ref name
|
493
528
|
# @yieldparam [String] commit_id the ref's commit ID
|
494
529
|
def each_remote_ref(package)
|
495
|
-
return enum_for(__method__, package)
|
530
|
+
return enum_for(__method__, package) unless block_given?
|
531
|
+
|
496
532
|
run_git_bare(package, 'ls-remote', repository).each do |line|
|
497
533
|
commit_id, ref_name = line.split(/\s+/)
|
498
|
-
if ref_name !~ /\^/
|
499
|
-
yield(ref_name, commit_id)
|
500
|
-
end
|
534
|
+
yield(ref_name, commit_id) if ref_name !~ /\^/
|
501
535
|
end
|
502
536
|
end
|
503
537
|
|
@@ -508,7 +542,7 @@ def each_remote_ref(package)
|
|
508
542
|
# package's source directory.
|
509
543
|
def fetch_remote(package, options = Hash.new)
|
510
544
|
validate_importdir(package)
|
511
|
-
|
545
|
+
unless options[:refspec]
|
512
546
|
raise ArgumentError, "required argument 'refspec' not given"
|
513
547
|
end
|
514
548
|
|
@@ -532,13 +566,14 @@ def fetch_remote(package, options = Hash.new)
|
|
532
566
|
|
533
567
|
# Now get the actual commit ID from the FETCH_HEAD file, and
|
534
568
|
# return it
|
535
|
-
if File.readable?(
|
536
|
-
fetched_commits = File.readlines(
|
569
|
+
if File.readable?(File.join(git_dir, 'FETCH_HEAD'))
|
570
|
+
fetched_commits = File.readlines(File.join(git_dir, 'FETCH_HEAD')).
|
537
571
|
find_all { |l| l !~ /not-for-merge/ }.
|
538
572
|
map { |line| line.split(/\s+/).first }
|
539
|
-
refspec.zip(fetched_commits).each do |
|
540
|
-
if
|
541
|
-
run_git_bare(package, 'update-ref', "-m", "updated by autobuild",
|
573
|
+
refspec.zip(fetched_commits).each do |spec, commit_id|
|
574
|
+
if spec =~ %r{^refs/heads/(.*)$}
|
575
|
+
run_git_bare(package, 'update-ref', "-m", "updated by autobuild",
|
576
|
+
"refs/remotes/#{remote_name}/#{$1}", commit_id)
|
542
577
|
end
|
543
578
|
end
|
544
579
|
|
@@ -576,16 +611,16 @@ def self.has_uncommitted_changes?(package, with_untracked_files = false)
|
|
576
611
|
# one is returned by this method
|
577
612
|
# @return [String] the commit ID as a string
|
578
613
|
def current_remote_commit(package, options = Hash.new)
|
579
|
-
|
580
|
-
options = Hash[only_local: options]
|
581
|
-
end
|
614
|
+
options = Hash[only_local: options] unless options.kind_of?(Hash)
|
582
615
|
only_local = options.delete(:only_local)
|
583
616
|
|
584
617
|
if only_local
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
618
|
+
unless remote_branch.start_with?("refs/")
|
619
|
+
refspec =
|
620
|
+
options[:refspec] ||
|
621
|
+
("refs/tags/#{tag}" if tag) ||
|
622
|
+
"refs/remotes/#{remote_name}/#{remote_branch}"
|
623
|
+
end
|
589
624
|
unless (refspec = Array(refspec).first)
|
590
625
|
raise ArgumentError, "cannot use only_local with no tag,"\
|
591
626
|
" and an absolute remote ref"
|
@@ -594,10 +629,12 @@ def current_remote_commit(package, options = Hash.new)
|
|
594
629
|
begin
|
595
630
|
run_git_bare(package, 'show-ref', '-s', refspec).first.strip
|
596
631
|
rescue SubcommandFailed
|
597
|
-
raise PackageException.new(package, "import"),
|
632
|
+
raise PackageException.new(package, "import"),
|
633
|
+
"cannot resolve #{refspec}"
|
598
634
|
end
|
599
635
|
else
|
600
|
-
refspec =
|
636
|
+
refspec =
|
637
|
+
options[:refspec] ||
|
601
638
|
("refs/tags/#{tag}" if tag) ||
|
602
639
|
remote_branch_to_ref(remote_branch)
|
603
640
|
begin fetch_remote(package, refspec: refspec)
|
@@ -610,23 +647,28 @@ def current_remote_commit(package, options = Hash.new)
|
|
610
647
|
# Returns a {Status} object that represents the status of this package
|
611
648
|
# w.r.t. the expected remote repository and branch
|
612
649
|
def status(package, options = Hash.new)
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
650
|
+
only_local =
|
651
|
+
if options.kind_of?(Hash)
|
652
|
+
options.fetch(:only_local, false)
|
653
|
+
else
|
654
|
+
options
|
655
|
+
end
|
618
656
|
|
619
657
|
validate_importdir(package)
|
620
|
-
|
658
|
+
_pinned_state, target_commit, = determine_target_state(
|
659
|
+
package, only_local: only_local)
|
621
660
|
|
622
661
|
status = merge_status(package, target_commit)
|
623
662
|
status.uncommitted_code = self.class.has_uncommitted_changes?(package)
|
624
|
-
if current_branch = self.current_branch(package)
|
663
|
+
if (current_branch = self.current_branch(package))
|
625
664
|
if current_branch != "refs/heads/#{local_branch}"
|
626
|
-
status.unexpected_working_copy_state <<
|
665
|
+
status.unexpected_working_copy_state <<
|
666
|
+
"working copy is on branch #{current_branch}, "\
|
667
|
+
"the autoproj configuration expected it to be on #{local_branch}"
|
627
668
|
end
|
628
669
|
else
|
629
|
-
status.unexpected_working_copy_state <<
|
670
|
+
status.unexpected_working_copy_state <<
|
671
|
+
"working copy is on a detached HEAD"
|
630
672
|
end
|
631
673
|
status
|
632
674
|
end
|
@@ -642,7 +684,8 @@ def has_commit?(package, commit_id)
|
|
642
684
|
end
|
643
685
|
|
644
686
|
def has_branch?(package, branch_name)
|
645
|
-
run_git_bare(package, 'show-ref', '-q', '--verify',
|
687
|
+
run_git_bare(package, 'show-ref', '-q', '--verify',
|
688
|
+
remote_branch_to_ref(branch_name))
|
646
689
|
true
|
647
690
|
rescue SubcommandFailed => e
|
648
691
|
if e.status == 1
|
@@ -675,16 +718,13 @@ def detached_head?(package)
|
|
675
718
|
def current_branch(package)
|
676
719
|
run_git_bare(package, 'symbolic-ref', 'HEAD', '-q').first.strip
|
677
720
|
rescue SubcommandFailed => e
|
678
|
-
if e.status
|
679
|
-
return
|
680
|
-
else raise
|
681
|
-
end
|
721
|
+
raise if e.status != 1
|
682
722
|
end
|
683
723
|
|
684
724
|
# Checks if the current branch is the target branch. Expects that the
|
685
725
|
# current directory is the package's directory
|
686
726
|
def on_local_branch?(package)
|
687
|
-
if current_branch = self.current_branch(package)
|
727
|
+
if (current_branch = self.current_branch(package))
|
688
728
|
current_branch == "refs/heads/#{local_branch}"
|
689
729
|
end
|
690
730
|
end
|
@@ -723,7 +763,9 @@ def needs_update?
|
|
723
763
|
end
|
724
764
|
|
725
765
|
def log(package, from, to)
|
726
|
-
log = package.importer.run_git_bare(
|
766
|
+
log = package.importer.run_git_bare(
|
767
|
+
package, 'log', '--encoding=UTF-8',
|
768
|
+
"--pretty=format:%h %cr %cn %s", "#{from}..#{to}")
|
727
769
|
log.map do |line|
|
728
770
|
line.strip.encode
|
729
771
|
end
|
@@ -740,12 +782,12 @@ def log(package, from, to)
|
|
740
782
|
# @return [String] the commit ID
|
741
783
|
# @raise [PackageException] if name cannot be found
|
742
784
|
def rev_parse(package, name, object_type = "commit")
|
743
|
-
if object_type
|
744
|
-
name = "#{name}^{#{object_type}}"
|
745
|
-
end
|
785
|
+
name = "#{name}^{#{object_type}}" if object_type
|
746
786
|
run_git_bare(package, 'rev-parse', '-q', '--verify', name).first
|
747
787
|
rescue Autobuild::SubcommandFailed
|
748
|
-
raise PackageException.new(package, 'import'),
|
788
|
+
raise PackageException.new(package, 'import'),
|
789
|
+
"failed to resolve #{name}. "\
|
790
|
+
"Are you sure this commit, branch or tag exists ?"
|
749
791
|
end
|
750
792
|
|
751
793
|
# Returns the file's conents at a certain commit
|
@@ -757,7 +799,8 @@ def rev_parse(package, name, object_type = "commit")
|
|
757
799
|
def show(package, commit, path)
|
758
800
|
run_git_bare(package, 'show', "#{commit}:#{path}").join("\n")
|
759
801
|
rescue Autobuild::SubcommandFailed
|
760
|
-
raise PackageException.new(package, 'import'),
|
802
|
+
raise PackageException.new(package, 'import'),
|
803
|
+
"failed to either resolve commit #{commit} or file #{path}"
|
761
804
|
end
|
762
805
|
|
763
806
|
# Tests whether a commit is already present in a given history
|
@@ -773,9 +816,10 @@ def commit_present_in?(package, rev, reference)
|
|
773
816
|
begin
|
774
817
|
merge_base = run_git_bare(package, 'merge-base', commit, reference).first
|
775
818
|
merge_base == commit
|
776
|
-
|
777
819
|
rescue Exception
|
778
|
-
raise PackageException.new(package, 'import'), "failed to find
|
820
|
+
raise PackageException.new(package, 'import'), "failed to find "\
|
821
|
+
"the merge-base between #{rev} and #{reference}. "\
|
822
|
+
"Are you sure these commits exist ?"
|
779
823
|
end
|
780
824
|
end
|
781
825
|
|
@@ -808,15 +852,13 @@ def describe_commit_on_remote(package, rev = 'HEAD', options = Hash.new)
|
|
808
852
|
end
|
809
853
|
end
|
810
854
|
|
811
|
-
|
812
|
-
remote_refs.delete_if { |r| r =~ /^refs\/tags\// }
|
813
|
-
end
|
855
|
+
remote_refs.delete_if { |r| r =~ %r{^refs/tags/} } unless options[:tags]
|
814
856
|
|
815
857
|
# Prefer tags, then heads, then the rest (e.g. github pull requests)
|
816
|
-
remote_refs = remote_refs.sort_by do |rev_name,
|
858
|
+
remote_refs = remote_refs.sort_by do |rev_name, _rev_id|
|
817
859
|
case rev_name
|
818
|
-
when
|
819
|
-
when
|
860
|
+
when %r{^refs/tags/} then 0
|
861
|
+
when %r{^refs/heads/} then 1
|
820
862
|
else 2
|
821
863
|
end
|
822
864
|
end
|
@@ -825,23 +867,23 @@ def describe_commit_on_remote(package, rev = 'HEAD', options = Hash.new)
|
|
825
867
|
begin
|
826
868
|
if commit_present_in?(package, commit_id, rev_id)
|
827
869
|
return rev_name
|
870
|
+
else
|
871
|
+
true
|
828
872
|
end
|
829
|
-
true
|
830
873
|
rescue PackageException
|
831
874
|
false
|
832
875
|
end
|
833
876
|
end
|
834
877
|
|
835
|
-
|
878
|
+
unless remote_refs.empty?
|
836
879
|
fetch_remote(package, refspec: remote_refs.map(&:first))
|
837
880
|
remote_refs.each do |rev_name, rev_id|
|
838
|
-
if commit_present_in?(package, commit_id, rev_id)
|
839
|
-
return rev_name
|
840
|
-
end
|
881
|
+
return rev_name if commit_present_in?(package, commit_id, rev_id)
|
841
882
|
end
|
842
883
|
end
|
843
884
|
|
844
|
-
raise PackageException.new(package), "current HEAD (#{commit_id}) does not
|
885
|
+
raise PackageException.new(package), "current HEAD (#{commit_id}) does not "\
|
886
|
+
"seem to be present on the remote"
|
845
887
|
end
|
846
888
|
|
847
889
|
# Computes the update status to update a branch whose tip is at
|
@@ -855,9 +897,12 @@ def describe_commit_on_remote(package, rev = 'HEAD', options = Hash.new)
|
|
855
897
|
#
|
856
898
|
def merge_status(package, fetch_commit, reference_commit = "HEAD")
|
857
899
|
begin
|
858
|
-
common_commit = run_git_bare(package, 'merge-base',
|
900
|
+
common_commit = run_git_bare(package, 'merge-base',
|
901
|
+
reference_commit, fetch_commit).first.strip
|
859
902
|
rescue Exception
|
860
|
-
raise PackageException.new(package, 'import'), "failed to find
|
903
|
+
raise PackageException.new(package, 'import'), "failed to find "\
|
904
|
+
"the merge-base between #{reference_commit} and #{fetch_commit}. "\
|
905
|
+
"Are you sure these commits exist ?"
|
861
906
|
end
|
862
907
|
remote_commit = rev_parse(package, fetch_commit)
|
863
908
|
head_commit = rev_parse(package, reference_commit)
|
@@ -868,12 +913,10 @@ def merge_status(package, fetch_commit, reference_commit = "HEAD")
|
|
868
913
|
else
|
869
914
|
Status::NEEDS_MERGE
|
870
915
|
end
|
916
|
+
elsif common_commit == head_commit
|
917
|
+
Status::UP_TO_DATE
|
871
918
|
else
|
872
|
-
|
873
|
-
Status::UP_TO_DATE
|
874
|
-
else
|
875
|
-
Status::ADVANCED
|
876
|
-
end
|
919
|
+
Status::ADVANCED
|
877
920
|
end
|
878
921
|
|
879
922
|
Status.new(package, status, fetch_commit, head_commit, common_commit)
|
@@ -887,10 +930,13 @@ def merge_status(package, fetch_commit, reference_commit = "HEAD")
|
|
887
930
|
# @param [Package] package the already checked-out package
|
888
931
|
# @return [void]
|
889
932
|
def update_alternates(package)
|
890
|
-
alternates_path = File.join(git_dir(package, false),
|
933
|
+
alternates_path = File.join(git_dir(package, false),
|
934
|
+
'objects', 'info', 'alternates')
|
891
935
|
current_alternates =
|
892
936
|
if File.file?(alternates_path)
|
893
|
-
File.readlines(alternates_path)
|
937
|
+
File.readlines(alternates_path)
|
938
|
+
.map(&:strip)
|
939
|
+
.find_all { |l| !l.empty? }
|
894
940
|
else Array.new
|
895
941
|
end
|
896
942
|
|
@@ -898,12 +944,14 @@ def update_alternates(package)
|
|
898
944
|
File.join(path, 'objects')
|
899
945
|
end
|
900
946
|
|
901
|
-
|
947
|
+
unless (current_alternates.sort - alternates.sort).empty?
|
902
948
|
# Warn that something is fishy, but assume that the user knows
|
903
949
|
# what he is doing
|
904
|
-
package.warn "%s: the list of git alternates listed in the repository
|
950
|
+
package.warn "%s: the list of git alternates listed in the repository "\
|
951
|
+
"differs from the one set up in autobuild."
|
905
952
|
package.warn "%s: I will update, but that is dangerous"
|
906
|
-
package.warn "%s: using git alternates is for advanced users only,
|
953
|
+
package.warn "%s: using git alternates is for advanced users only, "\
|
954
|
+
"who know git very well."
|
907
955
|
package.warn "%s: Don't complain if something breaks"
|
908
956
|
end
|
909
957
|
if alternates.empty?
|
@@ -946,7 +994,7 @@ def reset_head_to_commit(package, target_commit, fetch_commit, options = Hash.ne
|
|
946
994
|
# Check whether the current HEAD is present on the remote
|
947
995
|
# repository. We'll refuse resetting if there are uncommitted
|
948
996
|
# changes
|
949
|
-
|
997
|
+
unless commit_present_in?(package, current_head, fetch_commit)
|
950
998
|
raise ImporterCannotReset.new(package, 'import'),
|
951
999
|
"branch #{local_branch} of #{package.name} contains"\
|
952
1000
|
" commits that do not seem to be present on the branch"\
|
@@ -958,7 +1006,8 @@ def reset_head_to_commit(package, target_commit, fetch_commit, options = Hash.ne
|
|
958
1006
|
end
|
959
1007
|
end
|
960
1008
|
|
961
|
-
package.message " %%s: resetting branch
|
1009
|
+
package.message format(" %%s: resetting branch %<branch>s to %<commit>s",
|
1010
|
+
branch: local_branch, commit: target_commit)
|
962
1011
|
# I don't use a reset --hard here as it would add even more
|
963
1012
|
# restrictions on when we can do the operation (as we would refuse
|
964
1013
|
# doing it if there are local changes). The checkout creates a
|
@@ -968,7 +1017,8 @@ def reset_head_to_commit(package, target_commit, fetch_commit, options = Hash.ne
|
|
968
1017
|
resolved_target_commit = rev_parse(package, "#{target_commit}^{commit}")
|
969
1018
|
begin
|
970
1019
|
run_git(package, 'checkout', target_commit)
|
971
|
-
run_git(package, 'update-ref', "refs/heads/#{local_branch}",
|
1020
|
+
run_git(package, 'update-ref', "refs/heads/#{local_branch}",
|
1021
|
+
resolved_target_commit)
|
972
1022
|
run_git(package, 'symbolic-ref', "HEAD", "refs/heads/#{local_branch}")
|
973
1023
|
rescue ::Exception
|
974
1024
|
run_git(package, 'symbolic-ref', "HEAD", target_commit)
|
@@ -986,7 +1036,7 @@ def determine_target_state(package, only_local: false)
|
|
986
1036
|
end
|
987
1037
|
|
988
1038
|
if pinned_state
|
989
|
-
|
1039
|
+
unless has_commit?(package, pinned_state)
|
990
1040
|
fetch_commit = current_remote_commit(
|
991
1041
|
package,
|
992
1042
|
only_local: only_local,
|
@@ -994,14 +1044,13 @@ def determine_target_state(package, only_local: false)
|
|
994
1044
|
end
|
995
1045
|
target_commit = pinned_state = rev_parse(package, pinned_state)
|
996
1046
|
else
|
997
|
-
target_commit = fetch_commit
|
1047
|
+
target_commit = fetch_commit =
|
998
1048
|
current_remote_commit(package, only_local: only_local)
|
999
1049
|
end
|
1000
1050
|
|
1001
|
-
|
1051
|
+
[pinned_state, target_commit, fetch_commit]
|
1002
1052
|
end
|
1003
1053
|
|
1004
|
-
|
1005
1054
|
# @option (see Package#update)
|
1006
1055
|
def update(package, options = Hash.new)
|
1007
1056
|
validate_importdir(package)
|
@@ -1010,9 +1059,7 @@ def update(package, options = Hash.new)
|
|
1010
1059
|
|
1011
1060
|
# This is really really a hack to workaround how broken the
|
1012
1061
|
# importdir thing is
|
1013
|
-
if package.importdir == package.srcdir
|
1014
|
-
update_alternates(package)
|
1015
|
-
end
|
1062
|
+
update_alternates(package) if package.importdir == package.srcdir
|
1016
1063
|
|
1017
1064
|
pinned_state, target_commit, fetch_commit =
|
1018
1065
|
determine_target_state(package, only_local: only_local)
|
@@ -1020,14 +1067,14 @@ def update(package, options = Hash.new)
|
|
1020
1067
|
did_change_branch = ensure_on_local_branch(package, target_commit)
|
1021
1068
|
|
1022
1069
|
# Check whether we are already at the requested state
|
1023
|
-
|
1024
|
-
|
1070
|
+
if pinned_state
|
1071
|
+
pin_is_uptodate, pin_did_merge =
|
1025
1072
|
handle_pinned_state(package, pinned_state, reset: reset)
|
1026
|
-
|
1073
|
+
end
|
1027
1074
|
|
1028
1075
|
unless pin_is_uptodate
|
1029
|
-
fetch_commit ||= current_remote_commit(
|
1030
|
-
|
1076
|
+
fetch_commit ||= current_remote_commit(package,
|
1077
|
+
only_local: only_local,
|
1031
1078
|
refspec: [remote_branch_to_ref(remote_branch), tag])
|
1032
1079
|
did_update =
|
1033
1080
|
if reset
|
@@ -1048,11 +1095,13 @@ def update(package, options = Hash.new)
|
|
1048
1095
|
|
1049
1096
|
private def ensure_on_local_branch(package, target_commit)
|
1050
1097
|
if !has_local_branch?(package)
|
1051
|
-
package.message "%%s: checking out branch
|
1098
|
+
package.message format("%%s: checking out branch %<branch>s",
|
1099
|
+
branch: local_branch)
|
1052
1100
|
run_git(package, 'checkout', '-b', local_branch, target_commit)
|
1053
1101
|
true
|
1054
1102
|
elsif !on_local_branch?(package)
|
1055
|
-
package.message "%%s: switching to branch
|
1103
|
+
package.message format("%%s: switching to branch %<branch>s",
|
1104
|
+
branch: local_branch)
|
1056
1105
|
run_git(package, 'checkout', local_branch)
|
1057
1106
|
true
|
1058
1107
|
else
|
@@ -1065,7 +1114,11 @@ def merge_if_simple(package, target_commit)
|
|
1065
1114
|
status = merge_status(package, target_commit)
|
1066
1115
|
if status.needs_update?
|
1067
1116
|
if !merge? && status.status == Status::NEEDS_MERGE
|
1068
|
-
raise PackageException.new(package, 'import'), "the local branch
|
1117
|
+
raise PackageException.new(package, 'import'), "the local branch "\
|
1118
|
+
"'#{local_branch}' and the remote branch #{branch} of "\
|
1119
|
+
"#{package.name} have diverged, and I therefore refuse "\
|
1120
|
+
"to update automatically. Go into #{package.importdir} "\
|
1121
|
+
"and either reset the local branch or merge the remote changes"
|
1069
1122
|
end
|
1070
1123
|
run_git(package, 'merge', target_commit)
|
1071
1124
|
return true
|
@@ -1085,13 +1138,11 @@ def merge_if_simple(package, target_commit)
|
|
1085
1138
|
end
|
1086
1139
|
|
1087
1140
|
def each_alternate_path(package)
|
1088
|
-
return enum_for(__method__, package)
|
1141
|
+
return enum_for(__method__, package) unless block_given?
|
1089
1142
|
|
1090
1143
|
alternates.each do |path|
|
1091
|
-
path = path
|
1092
|
-
if File.directory?(path)
|
1093
|
-
yield(path)
|
1094
|
-
end
|
1144
|
+
path = format(path, package.name)
|
1145
|
+
yield(path) if File.directory?(path)
|
1095
1146
|
end
|
1096
1147
|
nil
|
1097
1148
|
end
|
@@ -1108,20 +1159,17 @@ def uses_lfs?(package)
|
|
1108
1159
|
|
1109
1160
|
def self.lfs_installed?
|
1110
1161
|
return @lfs_installed unless @lfs_installed.nil?
|
1162
|
+
|
1111
1163
|
_, _, status = Open3.capture3('git lfs env')
|
1112
1164
|
@lfs_installed = status.success?
|
1113
1165
|
end
|
1114
1166
|
|
1115
|
-
def checkout(package,
|
1167
|
+
def checkout(package, _options = Hash.new)
|
1116
1168
|
base_dir = File.expand_path('..', package.importdir)
|
1117
|
-
|
1118
|
-
FileUtils.mkdir_p base_dir
|
1119
|
-
end
|
1169
|
+
FileUtils.mkdir_p(base_dir) unless File.directory?(base_dir)
|
1120
1170
|
|
1121
1171
|
clone_options = Array.new
|
1122
|
-
if with_submodules?
|
1123
|
-
clone_options << '--recurse-submodules'
|
1124
|
-
end
|
1172
|
+
clone_options << '--recurse-submodules' if with_submodules?
|
1125
1173
|
if single_branch?
|
1126
1174
|
if remote_branch.start_with?("refs/")
|
1127
1175
|
raise ArgumentError, "you cannot provide a full ref for"\
|
@@ -1136,21 +1184,24 @@ def checkout(package, options = Hash.new)
|
|
1136
1184
|
clone_options << "--config=#{key}=#{value}"
|
1137
1185
|
end
|
1138
1186
|
package.run(:import,
|
1139
|
-
Autobuild.tool('git'), 'clone', '-o', remote_name, *clone_options,
|
1187
|
+
Autobuild.tool('git'), 'clone', '-o', remote_name, *clone_options,
|
1188
|
+
repository, package.importdir, retry: true)
|
1140
1189
|
|
1141
1190
|
update_remotes_configuration(package)
|
1142
1191
|
update(package, only_local: !remote_branch.start_with?("refs/"), reset: true)
|
1143
|
-
if with_submodules?
|
1144
|
-
run_git(package, "submodule", "update", '--init')
|
1145
|
-
end
|
1192
|
+
run_git(package, "submodule", "update", '--init') if with_submodules?
|
1146
1193
|
end
|
1147
1194
|
|
1148
1195
|
# Changes the repository this importer is pointing to
|
1149
1196
|
def relocate(repository, options = Hash.new)
|
1150
1197
|
options = Hash[options.map { |k, v| [k.to_sym, v] }]
|
1151
1198
|
|
1152
|
-
local_branch =
|
1153
|
-
|
1199
|
+
local_branch =
|
1200
|
+
options[:local_branch] || options[:branch] ||
|
1201
|
+
self.local_branch || 'master'
|
1202
|
+
remote_branch =
|
1203
|
+
options[:remote_branch] || options[:branch] ||
|
1204
|
+
self.remote_branch || 'master'
|
1154
1205
|
if local_branch.start_with?("refs/")
|
1155
1206
|
raise ArgumentError, "you cannot provide a full ref for"\
|
1156
1207
|
" the local branch, only for the remote branch"
|
@@ -1168,10 +1219,12 @@ def relocate(repository, options = Hash.new)
|
|
1168
1219
|
@commit = options.fetch(:commit, @commit)
|
1169
1220
|
|
1170
1221
|
@repository = repository.to_str
|
1171
|
-
@repository_id =
|
1222
|
+
@repository_id =
|
1223
|
+
options[:repository_id] ||
|
1172
1224
|
"git:#{@repository}"
|
1173
|
-
@source_id =
|
1174
|
-
|
1225
|
+
@source_id =
|
1226
|
+
options[:source_id] ||
|
1227
|
+
"#{@repository_id} branch=#{remote_branch} tag=#{tag} commit=#{commit}"
|
1175
1228
|
end
|
1176
1229
|
|
1177
1230
|
# Tests whether the given directory is a git repository
|
@@ -1185,31 +1238,31 @@ def self.can_handle?(path)
|
|
1185
1238
|
#
|
1186
1239
|
# @raise [ArgumentError] if the path does not point to a git repository
|
1187
1240
|
def self.vcs_definition_for(path, remote_name = 'autobuild')
|
1188
|
-
|
1189
|
-
raise ArgumentError, "#{path} is
|
1241
|
+
unless can_handle?(path)
|
1242
|
+
raise ArgumentError, "#{path} is neither a git repository, "\
|
1243
|
+
"nor a bare git repository"
|
1190
1244
|
end
|
1191
1245
|
|
1192
1246
|
Dir.chdir(path) do
|
1193
1247
|
vars = `#{Autobuild.tool(:git)} config -l`.
|
1194
1248
|
split("\n").
|
1195
|
-
|
1249
|
+
each_with_object(Hash.new) do |line, h|
|
1196
1250
|
k, v = line.strip.split('=', 2)
|
1197
1251
|
h[k] = v
|
1198
|
-
h
|
1199
1252
|
end
|
1200
|
-
url = vars["remote.#{remote_name}.url"] ||
|
1201
|
-
vars['remote.origin.url']
|
1253
|
+
url = vars["remote.#{remote_name}.url"] || vars['remote.origin.url']
|
1202
1254
|
if url
|
1203
|
-
return Hash[:
|
1255
|
+
return Hash[type: :git, url: url]
|
1204
1256
|
else
|
1205
|
-
return Hash[:
|
1257
|
+
return Hash[type: :git]
|
1206
1258
|
end
|
1207
1259
|
end
|
1208
1260
|
end
|
1209
1261
|
|
1210
1262
|
def declare_alternate_repository(name, repository, options = Hash.new)
|
1211
|
-
|
1212
|
-
raise ArgumentError, "cannot declare alternate repository
|
1263
|
+
unless name
|
1264
|
+
raise ArgumentError, "cannot declare alternate repository "\
|
1265
|
+
"#{repository} without a name"
|
1213
1266
|
end
|
1214
1267
|
additional_remotes << [name, repository, options[:push_to] || repository]
|
1215
1268
|
end
|
@@ -1221,4 +1274,3 @@ def self.git(repository, branch = nil, options = {})
|
|
1221
1274
|
Git.new(repository, branch, options)
|
1222
1275
|
end
|
1223
1276
|
end
|
1224
|
-
|