autobuild 1.17.0 → 1.18.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.
- 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
|
-
|