autobuild 1.17.0 → 1.21.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/.travis.yml +3 -2
- data/Gemfile +2 -1
- data/Rakefile +1 -4
- data/autobuild.gemspec +18 -13
- data/bin/autobuild +4 -3
- data/lib/autobuild.rb +4 -5
- data/lib/autobuild/build_logfile.rb +6 -4
- data/lib/autobuild/config.rb +104 -41
- data/lib/autobuild/configurable.rb +32 -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 +246 -182
- data/lib/autobuild/import/hg.rb +23 -18
- data/lib/autobuild/import/svn.rb +48 -29
- data/lib/autobuild/importer.rb +534 -499
- data/lib/autobuild/mail_reporter.rb +77 -77
- data/lib/autobuild/package.rb +200 -122
- data/lib/autobuild/packages/autotools.rb +47 -42
- data/lib/autobuild/packages/cmake.rb +77 -65
- data/lib/autobuild/packages/dummy.rb +9 -8
- data/lib/autobuild/packages/genom.rb +1 -1
- data/lib/autobuild/packages/gnumake.rb +74 -31
- 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 +12 -8
- data/lib/autobuild/packages/ruby.rb +22 -17
- data/lib/autobuild/parallel.rb +50 -46
- data/lib/autobuild/pkgconfig.rb +25 -13
- data/lib/autobuild/progress_display.rb +149 -64
- data/lib/autobuild/rake_task_extension.rb +12 -7
- data/lib/autobuild/reporting.rb +51 -26
- data/lib/autobuild/subcommand.rb +72 -65
- data/lib/autobuild/test.rb +9 -7
- data/lib/autobuild/test_utility.rb +12 -10
- data/lib/autobuild/timestamps.rb +28 -23
- data/lib/autobuild/tools.rb +17 -16
- data/lib/autobuild/utility.rb +67 -23
- data/lib/autobuild/version.rb +1 -1
- metadata +53 -37
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.importdir, '.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
|
@@ -23,12 +24,19 @@ class << self
|
|
23
24
|
# AUTOBUILD_GIT_CACHE_DIR and AUTOBUILD_CACHE_DIR environment
|
24
25
|
# variables
|
25
26
|
#
|
27
|
+
# Because of its role within the caching system in autobuild/autoproj,
|
28
|
+
# these defaults are not applied to git repositories that are using
|
29
|
+
# submodules. The autoproj cache builder does not generate repositories
|
30
|
+
# compatible with having submodules
|
31
|
+
#
|
26
32
|
# @return [Array]
|
27
33
|
# @see default_alternates=, Git#alternates
|
28
34
|
def default_alternates
|
29
35
|
if @default_alternates then @default_alternates
|
30
|
-
elsif cache_dirs = Importer.cache_dirs('git')
|
31
|
-
@default_alternates = cache_dirs.map
|
36
|
+
elsif (cache_dirs = Importer.cache_dirs('git'))
|
37
|
+
@default_alternates = cache_dirs.map do |path|
|
38
|
+
File.join(File.expand_path(path), '%s')
|
39
|
+
end
|
32
40
|
else Array.new
|
33
41
|
end
|
34
42
|
end
|
@@ -44,11 +52,13 @@ def self.default_config
|
|
44
52
|
#
|
45
53
|
# @return [String]
|
46
54
|
def self.version
|
47
|
-
version = Subprocess.run('git', 'setup', Autobuild.tool(:git), '--version').
|
55
|
+
version = Subprocess.run('git', 'setup', Autobuild.tool(:git), '--version').
|
56
|
+
first
|
48
57
|
if version =~ /^git version (\d[\d\.]+)/
|
49
58
|
$1.split(".").map { |i| Integer(i) }
|
50
59
|
else
|
51
|
-
raise ArgumentError, "cannot parse git version string #{version},
|
60
|
+
raise ArgumentError, "cannot parse git version string #{version}, "\
|
61
|
+
"was expecting something looking like 'git version 2.1.0'"
|
52
62
|
end
|
53
63
|
end
|
54
64
|
|
@@ -58,9 +68,7 @@ def self.version
|
|
58
68
|
# @return [Integer] -1 if actual is greater than required,
|
59
69
|
# 0 if equal, and 1 if actual is smaller than required
|
60
70
|
def self.compare_versions(actual, required)
|
61
|
-
if actual.size > required.size
|
62
|
-
return -compare_versions(required, actual)
|
63
|
-
end
|
71
|
+
return -compare_versions(required, actual) if actual.size > required.size
|
64
72
|
|
65
73
|
actual += [0] * (required.size - actual.size)
|
66
74
|
actual.zip(required).each do |v_act, v_req|
|
@@ -90,24 +98,24 @@ def self.at_least_version(*version)
|
|
90
98
|
# @param [String] branch deprecated, use the 'branch' named option
|
91
99
|
# instead
|
92
100
|
#
|
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
|
-
#
|
101
|
+
# @option options [String] push_to (repository) the URL to set up as
|
102
|
+
# push_to URL in the remote(s). Note that it is not used internally by
|
103
|
+
# this class
|
104
|
+
# @option options [String] branch (master) the branch we should track.
|
105
|
+
# It is used both as {#local_branch} and {#remote_branch}
|
97
106
|
# @option options [String] tag (nil) a tag at which we should pin the
|
98
107
|
# checkout. Cannot be given at the same time than :commit
|
99
108
|
# @option options [String] commit (nil) a commit ID at which we should pin the
|
100
109
|
# 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.
|
110
|
+
# @option options [String] repository_id (git:#{repository}) a string
|
111
|
+
# that allows to uniquely identify a repository. The meaning is
|
112
|
+
# caller-specific. For instance, autoproj uses repository_id to check
|
113
|
+
# whether two Git importers fetches from the same repository.
|
105
114
|
# @option options [Boolean] with_submodules (false) whether the importer should
|
106
115
|
# checkout and update submodules. Note that in an autobuild-based
|
107
116
|
# workflow, it is recommended to not use submodules but checkout all
|
108
117
|
# repositories separately instead.
|
109
118
|
def initialize(repository, branch = nil, options = {})
|
110
|
-
@alternates = Git.default_alternates.dup
|
111
119
|
@git_dir_cache = Array.new
|
112
120
|
@local_branch = @remote_branch = nil
|
113
121
|
@tag = @commit = nil
|
@@ -115,15 +123,19 @@ def initialize(repository, branch = nil, options = {})
|
|
115
123
|
@merge = false
|
116
124
|
|
117
125
|
if branch.respond_to?(:to_hash)
|
118
|
-
|
126
|
+
options = branch.to_hash
|
127
|
+
branch = nil
|
119
128
|
end
|
120
129
|
|
121
130
|
if branch
|
122
|
-
Autobuild.warn "the git importer now expects you to provide the branch
|
131
|
+
Autobuild.warn "the git importer now expects you to provide the branch "\
|
132
|
+
"as a named option"
|
123
133
|
Autobuild.warn "this form is deprecated:"
|
124
|
-
Autobuild.warn "
|
134
|
+
Autobuild.warn "Autobuild.git 'git://gitorious.org/rock/buildconf.git',"
|
135
|
+
Autobuild.warn " 'master'"
|
125
136
|
Autobuild.warn "and should be replaced by"
|
126
|
-
Autobuild.warn "
|
137
|
+
Autobuild.warn "Autobuild.git 'git://gitorious.org/rock/buildconf.git',"
|
138
|
+
Autobuild.warn " branch: 'master'"
|
127
139
|
end
|
128
140
|
|
129
141
|
gitopts, common = Kernel.filter_options options,
|
@@ -138,7 +150,8 @@ def initialize(repository, branch = nil, options = {})
|
|
138
150
|
with_submodules: false,
|
139
151
|
single_branch: false
|
140
152
|
if gitopts[:branch] && branch
|
141
|
-
raise ConfigException, "git branch specified with both the option hash
|
153
|
+
raise ConfigException, "git branch specified with both the option hash "\
|
154
|
+
"and the explicit parameter"
|
142
155
|
end
|
143
156
|
gitopts[:branch] ||= branch
|
144
157
|
|
@@ -146,12 +159,23 @@ def initialize(repository, branch = nil, options = {})
|
|
146
159
|
|
147
160
|
@single_branch = gitopts[:single_branch]
|
148
161
|
@with_submodules = gitopts.delete(:with_submodules)
|
162
|
+
@alternates =
|
163
|
+
if @with_submodules
|
164
|
+
[]
|
165
|
+
else
|
166
|
+
Git.default_alternates.dup
|
167
|
+
end
|
168
|
+
|
149
169
|
@remote_name = 'autobuild'
|
150
170
|
@push_to = nil
|
151
171
|
relocate(repository, gitopts)
|
152
172
|
@additional_remotes = Array.new
|
153
173
|
end
|
154
174
|
|
175
|
+
def vcs_fingerprint(package)
|
176
|
+
rev_parse(package, 'HEAD')
|
177
|
+
end
|
178
|
+
|
155
179
|
# The name of the remote that should be set up by the importer
|
156
180
|
#
|
157
181
|
# Defaults to 'autobuild'
|
@@ -240,13 +264,17 @@ def remote_branch
|
|
240
264
|
# True if it is allowed to merge remote updates automatically. If false
|
241
265
|
# (the default), the import will fail if the updates do not resolve as
|
242
266
|
# a fast-forward
|
243
|
-
def merge
|
267
|
+
def merge?
|
268
|
+
@merge
|
269
|
+
end
|
244
270
|
|
245
271
|
# Set the merge flag. See #merge?
|
246
|
-
|
272
|
+
attr_writer :merge
|
247
273
|
|
248
274
|
# Whether the git checkout should be done with submodules
|
249
|
-
def with_submodules
|
275
|
+
def with_submodules?
|
276
|
+
@with_submodules
|
277
|
+
end
|
250
278
|
|
251
279
|
# Whether 'clone' should fetch only the remote branch, or all the
|
252
280
|
# branches
|
@@ -255,16 +283,14 @@ def single_branch?
|
|
255
283
|
end
|
256
284
|
|
257
285
|
# Set the {#single_branch?} predicate
|
258
|
-
|
259
|
-
@single_branch = !!flag
|
260
|
-
end
|
286
|
+
attr_writer :single_branch
|
261
287
|
|
262
288
|
# @api private
|
263
289
|
#
|
264
290
|
# Verifies that the package's {Package#importdir} points to a git
|
265
291
|
# repository
|
266
292
|
def validate_importdir(package)
|
267
|
-
|
293
|
+
git_dir(package, true)
|
268
294
|
end
|
269
295
|
|
270
296
|
# @api private
|
@@ -276,16 +302,16 @@ def validate_importdir(package)
|
|
276
302
|
# @return [(String,Symbol),nil] either the path to the git folder and
|
277
303
|
# :bare or :normal, or nil if path is not a git repository.
|
278
304
|
def self.resolve_git_dir(path)
|
279
|
-
|
280
|
-
if
|
281
|
-
dir = path
|
282
|
-
end
|
305
|
+
gitdir = File.join(path, '.git')
|
306
|
+
path = gitdir if File.exist?(gitdir)
|
283
307
|
|
284
|
-
result = `#{Autobuild.tool(:git)} --git-dir="#{
|
285
|
-
|
308
|
+
result = `#{Autobuild.tool(:git)} --git-dir="#{path}" rev-parse \
|
309
|
+
--is-bare-repository 2>&1`
|
310
|
+
if $CHILD_STATUS.success?
|
286
311
|
if result.strip == "true"
|
287
|
-
|
288
|
-
else
|
312
|
+
[path, :bare]
|
313
|
+
else
|
314
|
+
[path, :normal]
|
289
315
|
end
|
290
316
|
end
|
291
317
|
end
|
@@ -337,13 +363,15 @@ def self.git_dir(package, require_working_copy)
|
|
337
363
|
# @return [void]
|
338
364
|
# @raise ConfigException if dir/style are nil, or if
|
339
365
|
# require_working_copy is true and style is :bare
|
340
|
-
def self.validate_git_dir(package, require_working_copy,
|
366
|
+
def self.validate_git_dir(package, require_working_copy, _dir, style)
|
341
367
|
if !style
|
342
368
|
raise ConfigException.new(package, 'import', retry: false),
|
343
|
-
"while importing #{package.name}, #{package.importdir}
|
369
|
+
"while importing #{package.name}, #{package.importdir} "\
|
370
|
+
"does not point to a git repository"
|
344
371
|
elsif require_working_copy && (style == :bare)
|
345
372
|
raise ConfigException.new(package, 'import', retry: false),
|
346
|
-
"while importing #{package.name}, #{package.importdir}
|
373
|
+
"while importing #{package.name}, #{package.importdir} "\
|
374
|
+
"points to a bare git repository but a working copy was required"
|
347
375
|
end
|
348
376
|
end
|
349
377
|
|
@@ -355,11 +383,13 @@ def self.validate_git_dir(package, require_working_copy, dir, style)
|
|
355
383
|
# @raise [ArgumentError] if one of the tags is unknown
|
356
384
|
def delta_between_tags(package, from_tag, to_tag)
|
357
385
|
pkg_tags = tags(package)
|
358
|
-
|
359
|
-
raise ArgumentError, "tag '#{from_tag}' is unknown to #{package.name}
|
386
|
+
unless pkg_tags.key?(from_tag)
|
387
|
+
raise ArgumentError, "tag '#{from_tag}' is unknown to #{package.name} "\
|
388
|
+
"-- known tags are: #{pkg_tags.keys}"
|
360
389
|
end
|
361
|
-
|
362
|
-
raise ArgumentError, "tag '#{to_tag}' is unknown to #{package.name}
|
390
|
+
unless pkg_tags.key?(to_tag)
|
391
|
+
raise ArgumentError, "tag '#{to_tag}' is unknown to #{package.name} "\
|
392
|
+
"-- known tags are: #{pkg_tags.keys}"
|
363
393
|
end
|
364
394
|
|
365
395
|
from_commit = pkg_tags[from_tag]
|
@@ -377,14 +407,14 @@ def delta_between_tags(package, from_tag, to_tag)
|
|
377
407
|
# @return [Hash<String,String>] a mapping from a tag name to its commit
|
378
408
|
# ID
|
379
409
|
def tags(package, options = Hash.new)
|
380
|
-
|
410
|
+
unless options.fetch(:only_local, false)
|
381
411
|
run_git_bare(package, 'fetch', '--tags')
|
382
412
|
end
|
383
413
|
tag_list = run_git_bare(package, 'show-ref', '--tags').map(&:strip)
|
384
414
|
tags = Hash.new
|
385
415
|
tag_list.each do |entry|
|
386
416
|
commit_to_tag = entry.split(" ")
|
387
|
-
tags[commit_to_tag[1].sub("refs/tags/","")] = commit_to_tag[0]
|
417
|
+
tags[commit_to_tag[1].sub("refs/tags/", "")] = commit_to_tag[0]
|
388
418
|
end
|
389
419
|
tags
|
390
420
|
end
|
@@ -405,14 +435,17 @@ def run_git(package, *args)
|
|
405
435
|
#
|
406
436
|
# (see Git#run_git)
|
407
437
|
def self.run_git(package, *args)
|
408
|
-
options =
|
409
|
-
|
410
|
-
|
411
|
-
|
438
|
+
options =
|
439
|
+
if args.last.kind_of?(Hash)
|
440
|
+
args.pop
|
441
|
+
else
|
442
|
+
Hash.new
|
443
|
+
end
|
412
444
|
|
413
445
|
working_directory = File.dirname(git_dir(package, true))
|
414
446
|
package.run(:import, Autobuild.tool(:git), *args,
|
415
|
-
Hash[resolved_env: Hash.new,
|
447
|
+
Hash[resolved_env: Hash.new,
|
448
|
+
working_directory: working_directory].merge(options))
|
416
449
|
end
|
417
450
|
|
418
451
|
# @api private
|
@@ -428,10 +461,13 @@ def run_git_bare(package, *args)
|
|
428
461
|
#
|
429
462
|
# (see Git#run_git_bare)
|
430
463
|
def self.run_git_bare(package, *args)
|
431
|
-
options =
|
432
|
-
|
433
|
-
|
434
|
-
|
464
|
+
options =
|
465
|
+
if args.last.kind_of?(Hash)
|
466
|
+
args.pop
|
467
|
+
else
|
468
|
+
Hash.new
|
469
|
+
end
|
470
|
+
|
435
471
|
package.run(:import, Autobuild.tool(:git),
|
436
472
|
'--git-dir', git_dir(package, false),
|
437
473
|
*args, Hash[resolved_env: Hash.new].merge(options))
|
@@ -441,14 +477,21 @@ def self.run_git_bare(package, *args)
|
|
441
477
|
#
|
442
478
|
# Set a remote up in the repositorie's configuration
|
443
479
|
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',
|
480
|
+
run_git_bare(package, 'config', '--replace-all',
|
481
|
+
"remote.#{remote_name}.url", repository)
|
482
|
+
run_git_bare(package, 'config', '--replace-all',
|
483
|
+
"remote.#{remote_name}.pushurl", push_to || repository)
|
484
|
+
run_git_bare(package, 'config', '--replace-all',
|
485
|
+
"remote.#{remote_name}.fetch",
|
486
|
+
"+refs/heads/*:refs/remotes/#{remote_name}/*")
|
447
487
|
|
448
488
|
if remote_branch && local_branch
|
449
|
-
run_git_bare(package, 'config', '--replace-all',
|
489
|
+
run_git_bare(package, 'config', '--replace-all',
|
490
|
+
"remote.#{remote_name}.push",
|
491
|
+
"refs/heads/#{local_branch}:#{remote_branch_to_ref(remote_branch)}")
|
450
492
|
else
|
451
|
-
run_git_bare(package, 'config', '--replace-all',
|
493
|
+
run_git_bare(package, 'config', '--replace-all',
|
494
|
+
"remote.#{remote_name}.push", "refs/heads/*:refs/heads/*")
|
452
495
|
end
|
453
496
|
end
|
454
497
|
|
@@ -473,18 +516,21 @@ def update_remotes_configuration(package)
|
|
473
516
|
end
|
474
517
|
|
475
518
|
if local_branch
|
476
|
-
run_git_bare(package, 'config', '--replace-all',
|
477
|
-
|
519
|
+
run_git_bare(package, 'config', '--replace-all',
|
520
|
+
"branch.#{local_branch}.remote", remote_name)
|
521
|
+
run_git_bare(package, 'config', '--replace-all',
|
522
|
+
"branch.#{local_branch}.merge", remote_branch_to_ref(local_branch))
|
478
523
|
end
|
479
524
|
end
|
480
525
|
|
481
526
|
# Resolve a commit ref to a tag or commit ID
|
482
527
|
def describe_rev(package, rev)
|
483
|
-
tag = run_git_bare(package, 'describe',
|
484
|
-
|
528
|
+
tag = run_git_bare(package, 'describe',
|
529
|
+
'--tags', '--exact-match', rev).first.strip
|
530
|
+
[true, tag.encode('UTF-8')]
|
485
531
|
rescue Autobuild::SubcommandFailed
|
486
532
|
commit = rev_parse(package, rev)
|
487
|
-
|
533
|
+
[false, commit.encode('UTF-8')]
|
488
534
|
end
|
489
535
|
|
490
536
|
# Enumerates the ref that are present on the remote
|
@@ -492,12 +538,11 @@ def describe_rev(package, rev)
|
|
492
538
|
# @yieldparam [String] ref_name the ref name
|
493
539
|
# @yieldparam [String] commit_id the ref's commit ID
|
494
540
|
def each_remote_ref(package)
|
495
|
-
return enum_for(__method__, package)
|
541
|
+
return enum_for(__method__, package) unless block_given?
|
542
|
+
|
496
543
|
run_git_bare(package, 'ls-remote', repository).each do |line|
|
497
544
|
commit_id, ref_name = line.split(/\s+/)
|
498
|
-
if ref_name !~ /\^/
|
499
|
-
yield(ref_name, commit_id)
|
500
|
-
end
|
545
|
+
yield(ref_name, commit_id) if ref_name !~ /\^/
|
501
546
|
end
|
502
547
|
end
|
503
548
|
|
@@ -508,7 +553,7 @@ def each_remote_ref(package)
|
|
508
553
|
# package's source directory.
|
509
554
|
def fetch_remote(package, options = Hash.new)
|
510
555
|
validate_importdir(package)
|
511
|
-
|
556
|
+
unless options[:refspec]
|
512
557
|
raise ArgumentError, "required argument 'refspec' not given"
|
513
558
|
end
|
514
559
|
|
@@ -532,13 +577,14 @@ def fetch_remote(package, options = Hash.new)
|
|
532
577
|
|
533
578
|
# Now get the actual commit ID from the FETCH_HEAD file, and
|
534
579
|
# return it
|
535
|
-
if File.readable?(
|
536
|
-
fetched_commits = File.readlines(
|
580
|
+
if File.readable?(File.join(git_dir, 'FETCH_HEAD'))
|
581
|
+
fetched_commits = File.readlines(File.join(git_dir, 'FETCH_HEAD')).
|
537
582
|
find_all { |l| l !~ /not-for-merge/ }.
|
538
583
|
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",
|
584
|
+
refspec.zip(fetched_commits).each do |spec, commit_id|
|
585
|
+
if spec =~ %r{^refs/heads/(.*)$}
|
586
|
+
run_git_bare(package, 'update-ref', "-m", "updated by autobuild",
|
587
|
+
"refs/remotes/#{remote_name}/#{$1}", commit_id)
|
542
588
|
end
|
543
589
|
end
|
544
590
|
|
@@ -576,16 +622,16 @@ def self.has_uncommitted_changes?(package, with_untracked_files = false)
|
|
576
622
|
# one is returned by this method
|
577
623
|
# @return [String] the commit ID as a string
|
578
624
|
def current_remote_commit(package, options = Hash.new)
|
579
|
-
|
580
|
-
options = Hash[only_local: options]
|
581
|
-
end
|
625
|
+
options = Hash[only_local: options] unless options.kind_of?(Hash)
|
582
626
|
only_local = options.delete(:only_local)
|
583
627
|
|
584
628
|
if only_local
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
629
|
+
unless remote_branch.start_with?("refs/")
|
630
|
+
refspec =
|
631
|
+
options[:refspec] ||
|
632
|
+
("refs/tags/#{tag}" if tag) ||
|
633
|
+
"refs/remotes/#{remote_name}/#{remote_branch}"
|
634
|
+
end
|
589
635
|
unless (refspec = Array(refspec).first)
|
590
636
|
raise ArgumentError, "cannot use only_local with no tag,"\
|
591
637
|
" and an absolute remote ref"
|
@@ -594,10 +640,12 @@ def current_remote_commit(package, options = Hash.new)
|
|
594
640
|
begin
|
595
641
|
run_git_bare(package, 'show-ref', '-s', refspec).first.strip
|
596
642
|
rescue SubcommandFailed
|
597
|
-
raise PackageException.new(package, "import"),
|
643
|
+
raise PackageException.new(package, "import"),
|
644
|
+
"cannot resolve #{refspec}"
|
598
645
|
end
|
599
646
|
else
|
600
|
-
refspec =
|
647
|
+
refspec =
|
648
|
+
options[:refspec] ||
|
601
649
|
("refs/tags/#{tag}" if tag) ||
|
602
650
|
remote_branch_to_ref(remote_branch)
|
603
651
|
begin fetch_remote(package, refspec: refspec)
|
@@ -610,23 +658,28 @@ def current_remote_commit(package, options = Hash.new)
|
|
610
658
|
# Returns a {Status} object that represents the status of this package
|
611
659
|
# w.r.t. the expected remote repository and branch
|
612
660
|
def status(package, options = Hash.new)
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
661
|
+
only_local =
|
662
|
+
if options.kind_of?(Hash)
|
663
|
+
options.fetch(:only_local, false)
|
664
|
+
else
|
665
|
+
options
|
666
|
+
end
|
618
667
|
|
619
668
|
validate_importdir(package)
|
620
|
-
|
669
|
+
_pinned_state, target_commit, = determine_target_state(
|
670
|
+
package, only_local: only_local)
|
621
671
|
|
622
672
|
status = merge_status(package, target_commit)
|
623
673
|
status.uncommitted_code = self.class.has_uncommitted_changes?(package)
|
624
|
-
if current_branch = self.current_branch(package)
|
674
|
+
if (current_branch = self.current_branch(package))
|
625
675
|
if current_branch != "refs/heads/#{local_branch}"
|
626
|
-
status.unexpected_working_copy_state <<
|
676
|
+
status.unexpected_working_copy_state <<
|
677
|
+
"working copy is on branch #{current_branch}, "\
|
678
|
+
"the autoproj configuration expected it to be on #{local_branch}"
|
627
679
|
end
|
628
680
|
else
|
629
|
-
status.unexpected_working_copy_state <<
|
681
|
+
status.unexpected_working_copy_state <<
|
682
|
+
"working copy is on a detached HEAD"
|
630
683
|
end
|
631
684
|
status
|
632
685
|
end
|
@@ -642,7 +695,8 @@ def has_commit?(package, commit_id)
|
|
642
695
|
end
|
643
696
|
|
644
697
|
def has_branch?(package, branch_name)
|
645
|
-
run_git_bare(package, 'show-ref', '-q', '--verify',
|
698
|
+
run_git_bare(package, 'show-ref', '-q', '--verify',
|
699
|
+
remote_branch_to_ref(branch_name))
|
646
700
|
true
|
647
701
|
rescue SubcommandFailed => e
|
648
702
|
if e.status == 1
|
@@ -675,16 +729,13 @@ def detached_head?(package)
|
|
675
729
|
def current_branch(package)
|
676
730
|
run_git_bare(package, 'symbolic-ref', 'HEAD', '-q').first.strip
|
677
731
|
rescue SubcommandFailed => e
|
678
|
-
if e.status
|
679
|
-
return
|
680
|
-
else raise
|
681
|
-
end
|
732
|
+
raise if e.status != 1
|
682
733
|
end
|
683
734
|
|
684
735
|
# Checks if the current branch is the target branch. Expects that the
|
685
736
|
# current directory is the package's directory
|
686
737
|
def on_local_branch?(package)
|
687
|
-
if current_branch = self.current_branch(package)
|
738
|
+
if (current_branch = self.current_branch(package))
|
688
739
|
current_branch == "refs/heads/#{local_branch}"
|
689
740
|
end
|
690
741
|
end
|
@@ -723,7 +774,9 @@ def needs_update?
|
|
723
774
|
end
|
724
775
|
|
725
776
|
def log(package, from, to)
|
726
|
-
log = package.importer.run_git_bare(
|
777
|
+
log = package.importer.run_git_bare(
|
778
|
+
package, 'log', '--encoding=UTF-8',
|
779
|
+
"--pretty=format:%h %cr %cn %s", "#{from}..#{to}")
|
727
780
|
log.map do |line|
|
728
781
|
line.strip.encode
|
729
782
|
end
|
@@ -740,12 +793,12 @@ def log(package, from, to)
|
|
740
793
|
# @return [String] the commit ID
|
741
794
|
# @raise [PackageException] if name cannot be found
|
742
795
|
def rev_parse(package, name, object_type = "commit")
|
743
|
-
if object_type
|
744
|
-
name = "#{name}^{#{object_type}}"
|
745
|
-
end
|
796
|
+
name = "#{name}^{#{object_type}}" if object_type
|
746
797
|
run_git_bare(package, 'rev-parse', '-q', '--verify', name).first
|
747
798
|
rescue Autobuild::SubcommandFailed
|
748
|
-
raise PackageException.new(package, 'import'),
|
799
|
+
raise PackageException.new(package, 'import'),
|
800
|
+
"failed to resolve #{name}. "\
|
801
|
+
"Are you sure this commit, branch or tag exists ?"
|
749
802
|
end
|
750
803
|
|
751
804
|
# Returns the file's conents at a certain commit
|
@@ -757,7 +810,8 @@ def rev_parse(package, name, object_type = "commit")
|
|
757
810
|
def show(package, commit, path)
|
758
811
|
run_git_bare(package, 'show', "#{commit}:#{path}").join("\n")
|
759
812
|
rescue Autobuild::SubcommandFailed
|
760
|
-
raise PackageException.new(package, 'import'),
|
813
|
+
raise PackageException.new(package, 'import'),
|
814
|
+
"failed to either resolve commit #{commit} or file #{path}"
|
761
815
|
end
|
762
816
|
|
763
817
|
# Tests whether a commit is already present in a given history
|
@@ -773,9 +827,10 @@ def commit_present_in?(package, rev, reference)
|
|
773
827
|
begin
|
774
828
|
merge_base = run_git_bare(package, 'merge-base', commit, reference).first
|
775
829
|
merge_base == commit
|
776
|
-
|
777
830
|
rescue Exception
|
778
|
-
raise PackageException.new(package, 'import'), "failed to find
|
831
|
+
raise PackageException.new(package, 'import'), "failed to find "\
|
832
|
+
"the merge-base between #{rev} and #{reference}. "\
|
833
|
+
"Are you sure these commits exist ?"
|
779
834
|
end
|
780
835
|
end
|
781
836
|
|
@@ -808,15 +863,13 @@ def describe_commit_on_remote(package, rev = 'HEAD', options = Hash.new)
|
|
808
863
|
end
|
809
864
|
end
|
810
865
|
|
811
|
-
|
812
|
-
remote_refs.delete_if { |r| r =~ /^refs\/tags\// }
|
813
|
-
end
|
866
|
+
remote_refs.delete_if { |r| r =~ %r{^refs/tags/} } unless options[:tags]
|
814
867
|
|
815
868
|
# Prefer tags, then heads, then the rest (e.g. github pull requests)
|
816
|
-
remote_refs = remote_refs.sort_by do |rev_name,
|
869
|
+
remote_refs = remote_refs.sort_by do |rev_name, _rev_id|
|
817
870
|
case rev_name
|
818
|
-
when
|
819
|
-
when
|
871
|
+
when %r{^refs/tags/} then 0
|
872
|
+
when %r{^refs/heads/} then 1
|
820
873
|
else 2
|
821
874
|
end
|
822
875
|
end
|
@@ -825,23 +878,23 @@ def describe_commit_on_remote(package, rev = 'HEAD', options = Hash.new)
|
|
825
878
|
begin
|
826
879
|
if commit_present_in?(package, commit_id, rev_id)
|
827
880
|
return rev_name
|
881
|
+
else
|
882
|
+
true
|
828
883
|
end
|
829
|
-
true
|
830
884
|
rescue PackageException
|
831
885
|
false
|
832
886
|
end
|
833
887
|
end
|
834
888
|
|
835
|
-
|
889
|
+
unless remote_refs.empty?
|
836
890
|
fetch_remote(package, refspec: remote_refs.map(&:first))
|
837
891
|
remote_refs.each do |rev_name, rev_id|
|
838
|
-
if commit_present_in?(package, commit_id, rev_id)
|
839
|
-
return rev_name
|
840
|
-
end
|
892
|
+
return rev_name if commit_present_in?(package, commit_id, rev_id)
|
841
893
|
end
|
842
894
|
end
|
843
895
|
|
844
|
-
raise PackageException.new(package), "current HEAD (#{commit_id}) does not
|
896
|
+
raise PackageException.new(package), "current HEAD (#{commit_id}) does not "\
|
897
|
+
"seem to be present on the remote"
|
845
898
|
end
|
846
899
|
|
847
900
|
# Computes the update status to update a branch whose tip is at
|
@@ -855,9 +908,12 @@ def describe_commit_on_remote(package, rev = 'HEAD', options = Hash.new)
|
|
855
908
|
#
|
856
909
|
def merge_status(package, fetch_commit, reference_commit = "HEAD")
|
857
910
|
begin
|
858
|
-
common_commit = run_git_bare(package, 'merge-base',
|
911
|
+
common_commit = run_git_bare(package, 'merge-base',
|
912
|
+
reference_commit, fetch_commit).first.strip
|
859
913
|
rescue Exception
|
860
|
-
raise PackageException.new(package, 'import'), "failed to find
|
914
|
+
raise PackageException.new(package, 'import'), "failed to find "\
|
915
|
+
"the merge-base between #{reference_commit} and #{fetch_commit}. "\
|
916
|
+
"Are you sure these commits exist ?"
|
861
917
|
end
|
862
918
|
remote_commit = rev_parse(package, fetch_commit)
|
863
919
|
head_commit = rev_parse(package, reference_commit)
|
@@ -868,12 +924,10 @@ def merge_status(package, fetch_commit, reference_commit = "HEAD")
|
|
868
924
|
else
|
869
925
|
Status::NEEDS_MERGE
|
870
926
|
end
|
927
|
+
elsif common_commit == head_commit
|
928
|
+
Status::UP_TO_DATE
|
871
929
|
else
|
872
|
-
|
873
|
-
Status::UP_TO_DATE
|
874
|
-
else
|
875
|
-
Status::ADVANCED
|
876
|
-
end
|
930
|
+
Status::ADVANCED
|
877
931
|
end
|
878
932
|
|
879
933
|
Status.new(package, status, fetch_commit, head_commit, common_commit)
|
@@ -887,10 +941,13 @@ def merge_status(package, fetch_commit, reference_commit = "HEAD")
|
|
887
941
|
# @param [Package] package the already checked-out package
|
888
942
|
# @return [void]
|
889
943
|
def update_alternates(package)
|
890
|
-
alternates_path = File.join(git_dir(package, false),
|
944
|
+
alternates_path = File.join(git_dir(package, false),
|
945
|
+
'objects', 'info', 'alternates')
|
891
946
|
current_alternates =
|
892
947
|
if File.file?(alternates_path)
|
893
|
-
File.readlines(alternates_path)
|
948
|
+
File.readlines(alternates_path)
|
949
|
+
.map(&:strip)
|
950
|
+
.find_all { |l| !l.empty? }
|
894
951
|
else Array.new
|
895
952
|
end
|
896
953
|
|
@@ -898,12 +955,14 @@ def update_alternates(package)
|
|
898
955
|
File.join(path, 'objects')
|
899
956
|
end
|
900
957
|
|
901
|
-
|
958
|
+
unless (current_alternates.sort - alternates.sort).empty?
|
902
959
|
# Warn that something is fishy, but assume that the user knows
|
903
960
|
# what he is doing
|
904
|
-
package.warn "%s: the list of git alternates listed in the repository
|
961
|
+
package.warn "%s: the list of git alternates listed in the repository "\
|
962
|
+
"differs from the one set up in autobuild."
|
905
963
|
package.warn "%s: I will update, but that is dangerous"
|
906
|
-
package.warn "%s: using git alternates is for advanced users only,
|
964
|
+
package.warn "%s: using git alternates is for advanced users only, "\
|
965
|
+
"who know git very well."
|
907
966
|
package.warn "%s: Don't complain if something breaks"
|
908
967
|
end
|
909
968
|
if alternates.empty?
|
@@ -946,7 +1005,7 @@ def reset_head_to_commit(package, target_commit, fetch_commit, options = Hash.ne
|
|
946
1005
|
# Check whether the current HEAD is present on the remote
|
947
1006
|
# repository. We'll refuse resetting if there are uncommitted
|
948
1007
|
# changes
|
949
|
-
|
1008
|
+
unless commit_present_in?(package, current_head, fetch_commit)
|
950
1009
|
raise ImporterCannotReset.new(package, 'import'),
|
951
1010
|
"branch #{local_branch} of #{package.name} contains"\
|
952
1011
|
" commits that do not seem to be present on the branch"\
|
@@ -958,7 +1017,8 @@ def reset_head_to_commit(package, target_commit, fetch_commit, options = Hash.ne
|
|
958
1017
|
end
|
959
1018
|
end
|
960
1019
|
|
961
|
-
package.message " %%s: resetting branch
|
1020
|
+
package.message format(" %%s: resetting branch %<branch>s to %<commit>s",
|
1021
|
+
branch: local_branch, commit: target_commit)
|
962
1022
|
# I don't use a reset --hard here as it would add even more
|
963
1023
|
# restrictions on when we can do the operation (as we would refuse
|
964
1024
|
# doing it if there are local changes). The checkout creates a
|
@@ -968,7 +1028,8 @@ def reset_head_to_commit(package, target_commit, fetch_commit, options = Hash.ne
|
|
968
1028
|
resolved_target_commit = rev_parse(package, "#{target_commit}^{commit}")
|
969
1029
|
begin
|
970
1030
|
run_git(package, 'checkout', target_commit)
|
971
|
-
run_git(package, 'update-ref', "refs/heads/#{local_branch}",
|
1031
|
+
run_git(package, 'update-ref', "refs/heads/#{local_branch}",
|
1032
|
+
resolved_target_commit)
|
972
1033
|
run_git(package, 'symbolic-ref', "HEAD", "refs/heads/#{local_branch}")
|
973
1034
|
rescue ::Exception
|
974
1035
|
run_git(package, 'symbolic-ref', "HEAD", target_commit)
|
@@ -986,7 +1047,7 @@ def determine_target_state(package, only_local: false)
|
|
986
1047
|
end
|
987
1048
|
|
988
1049
|
if pinned_state
|
989
|
-
|
1050
|
+
unless has_commit?(package, pinned_state)
|
990
1051
|
fetch_commit = current_remote_commit(
|
991
1052
|
package,
|
992
1053
|
only_local: only_local,
|
@@ -994,14 +1055,13 @@ def determine_target_state(package, only_local: false)
|
|
994
1055
|
end
|
995
1056
|
target_commit = pinned_state = rev_parse(package, pinned_state)
|
996
1057
|
else
|
997
|
-
target_commit = fetch_commit
|
1058
|
+
target_commit = fetch_commit =
|
998
1059
|
current_remote_commit(package, only_local: only_local)
|
999
1060
|
end
|
1000
1061
|
|
1001
|
-
|
1062
|
+
[pinned_state, target_commit, fetch_commit]
|
1002
1063
|
end
|
1003
1064
|
|
1004
|
-
|
1005
1065
|
# @option (see Package#update)
|
1006
1066
|
def update(package, options = Hash.new)
|
1007
1067
|
validate_importdir(package)
|
@@ -1010,9 +1070,7 @@ def update(package, options = Hash.new)
|
|
1010
1070
|
|
1011
1071
|
# This is really really a hack to workaround how broken the
|
1012
1072
|
# importdir thing is
|
1013
|
-
if package.importdir == package.srcdir
|
1014
|
-
update_alternates(package)
|
1015
|
-
end
|
1073
|
+
update_alternates(package) if package.importdir == package.srcdir
|
1016
1074
|
|
1017
1075
|
pinned_state, target_commit, fetch_commit =
|
1018
1076
|
determine_target_state(package, only_local: only_local)
|
@@ -1020,14 +1078,14 @@ def update(package, options = Hash.new)
|
|
1020
1078
|
did_change_branch = ensure_on_local_branch(package, target_commit)
|
1021
1079
|
|
1022
1080
|
# Check whether we are already at the requested state
|
1023
|
-
|
1024
|
-
|
1081
|
+
if pinned_state
|
1082
|
+
pin_is_uptodate, pin_did_merge =
|
1025
1083
|
handle_pinned_state(package, pinned_state, reset: reset)
|
1026
|
-
|
1084
|
+
end
|
1027
1085
|
|
1028
1086
|
unless pin_is_uptodate
|
1029
|
-
fetch_commit ||= current_remote_commit(
|
1030
|
-
|
1087
|
+
fetch_commit ||= current_remote_commit(package,
|
1088
|
+
only_local: only_local,
|
1031
1089
|
refspec: [remote_branch_to_ref(remote_branch), tag])
|
1032
1090
|
did_update =
|
1033
1091
|
if reset
|
@@ -1048,11 +1106,13 @@ def update(package, options = Hash.new)
|
|
1048
1106
|
|
1049
1107
|
private def ensure_on_local_branch(package, target_commit)
|
1050
1108
|
if !has_local_branch?(package)
|
1051
|
-
package.message "%%s: checking out branch
|
1109
|
+
package.message format("%%s: checking out branch %<branch>s",
|
1110
|
+
branch: local_branch)
|
1052
1111
|
run_git(package, 'checkout', '-b', local_branch, target_commit)
|
1053
1112
|
true
|
1054
1113
|
elsif !on_local_branch?(package)
|
1055
|
-
package.message "%%s: switching to branch
|
1114
|
+
package.message format("%%s: switching to branch %<branch>s",
|
1115
|
+
branch: local_branch)
|
1056
1116
|
run_git(package, 'checkout', local_branch)
|
1057
1117
|
true
|
1058
1118
|
else
|
@@ -1065,7 +1125,11 @@ def merge_if_simple(package, target_commit)
|
|
1065
1125
|
status = merge_status(package, target_commit)
|
1066
1126
|
if status.needs_update?
|
1067
1127
|
if !merge? && status.status == Status::NEEDS_MERGE
|
1068
|
-
raise PackageException.new(package, 'import'), "the local branch
|
1128
|
+
raise PackageException.new(package, 'import'), "the local branch "\
|
1129
|
+
"'#{local_branch}' and the remote branch #{branch} of "\
|
1130
|
+
"#{package.name} have diverged, and I therefore refuse "\
|
1131
|
+
"to update automatically. Go into #{package.importdir} "\
|
1132
|
+
"and either reset the local branch or merge the remote changes"
|
1069
1133
|
end
|
1070
1134
|
run_git(package, 'merge', target_commit)
|
1071
1135
|
return true
|
@@ -1085,13 +1149,11 @@ def merge_if_simple(package, target_commit)
|
|
1085
1149
|
end
|
1086
1150
|
|
1087
1151
|
def each_alternate_path(package)
|
1088
|
-
return enum_for(__method__, package)
|
1152
|
+
return enum_for(__method__, package) unless block_given?
|
1089
1153
|
|
1090
1154
|
alternates.each do |path|
|
1091
|
-
path = path
|
1092
|
-
if File.directory?(path)
|
1093
|
-
yield(path)
|
1094
|
-
end
|
1155
|
+
path = format(path, package.name)
|
1156
|
+
yield(path) if File.directory?(path)
|
1095
1157
|
end
|
1096
1158
|
nil
|
1097
1159
|
end
|
@@ -1108,20 +1170,17 @@ def uses_lfs?(package)
|
|
1108
1170
|
|
1109
1171
|
def self.lfs_installed?
|
1110
1172
|
return @lfs_installed unless @lfs_installed.nil?
|
1111
|
-
|
1173
|
+
|
1174
|
+
_, _, status = Open3.capture3('git lfs')
|
1112
1175
|
@lfs_installed = status.success?
|
1113
1176
|
end
|
1114
1177
|
|
1115
|
-
def checkout(package,
|
1178
|
+
def checkout(package, _options = Hash.new)
|
1116
1179
|
base_dir = File.expand_path('..', package.importdir)
|
1117
|
-
|
1118
|
-
FileUtils.mkdir_p base_dir
|
1119
|
-
end
|
1180
|
+
FileUtils.mkdir_p(base_dir) unless File.directory?(base_dir)
|
1120
1181
|
|
1121
1182
|
clone_options = Array.new
|
1122
|
-
if with_submodules?
|
1123
|
-
clone_options << '--recurse-submodules'
|
1124
|
-
end
|
1183
|
+
clone_options << '--recurse-submodules' if with_submodules?
|
1125
1184
|
if single_branch?
|
1126
1185
|
if remote_branch.start_with?("refs/")
|
1127
1186
|
raise ArgumentError, "you cannot provide a full ref for"\
|
@@ -1136,21 +1195,25 @@ def checkout(package, options = Hash.new)
|
|
1136
1195
|
clone_options << "--config=#{key}=#{value}"
|
1137
1196
|
end
|
1138
1197
|
package.run(:import,
|
1139
|
-
Autobuild.tool('git'), 'clone', '-o', remote_name, *clone_options,
|
1198
|
+
Autobuild.tool('git'), 'clone', '-o', remote_name, *clone_options,
|
1199
|
+
repository, package.importdir, retry: true)
|
1140
1200
|
|
1141
1201
|
update_remotes_configuration(package)
|
1142
|
-
update(package, only_local: !remote_branch.start_with?("refs/"),
|
1143
|
-
|
1144
|
-
|
1145
|
-
end
|
1202
|
+
update(package, only_local: !remote_branch.start_with?("refs/"),
|
1203
|
+
reset: :force)
|
1204
|
+
run_git(package, "submodule", "update", '--init') if with_submodules?
|
1146
1205
|
end
|
1147
1206
|
|
1148
1207
|
# Changes the repository this importer is pointing to
|
1149
1208
|
def relocate(repository, options = Hash.new)
|
1150
1209
|
options = Hash[options.map { |k, v| [k.to_sym, v] }]
|
1151
1210
|
|
1152
|
-
local_branch =
|
1153
|
-
|
1211
|
+
local_branch =
|
1212
|
+
options[:local_branch] || options[:branch] ||
|
1213
|
+
self.local_branch || 'master'
|
1214
|
+
remote_branch =
|
1215
|
+
options[:remote_branch] || options[:branch] ||
|
1216
|
+
self.remote_branch || 'master'
|
1154
1217
|
if local_branch.start_with?("refs/")
|
1155
1218
|
raise ArgumentError, "you cannot provide a full ref for"\
|
1156
1219
|
" the local branch, only for the remote branch"
|
@@ -1168,10 +1231,12 @@ def relocate(repository, options = Hash.new)
|
|
1168
1231
|
@commit = options.fetch(:commit, @commit)
|
1169
1232
|
|
1170
1233
|
@repository = repository.to_str
|
1171
|
-
@repository_id =
|
1234
|
+
@repository_id =
|
1235
|
+
options[:repository_id] ||
|
1172
1236
|
"git:#{@repository}"
|
1173
|
-
@source_id =
|
1174
|
-
|
1237
|
+
@source_id =
|
1238
|
+
options[:source_id] ||
|
1239
|
+
"#{@repository_id} branch=#{remote_branch} tag=#{tag} commit=#{commit}"
|
1175
1240
|
end
|
1176
1241
|
|
1177
1242
|
# Tests whether the given directory is a git repository
|
@@ -1185,31 +1250,31 @@ def self.can_handle?(path)
|
|
1185
1250
|
#
|
1186
1251
|
# @raise [ArgumentError] if the path does not point to a git repository
|
1187
1252
|
def self.vcs_definition_for(path, remote_name = 'autobuild')
|
1188
|
-
|
1189
|
-
raise ArgumentError, "#{path} is
|
1253
|
+
unless can_handle?(path)
|
1254
|
+
raise ArgumentError, "#{path} is neither a git repository, "\
|
1255
|
+
"nor a bare git repository"
|
1190
1256
|
end
|
1191
1257
|
|
1192
1258
|
Dir.chdir(path) do
|
1193
1259
|
vars = `#{Autobuild.tool(:git)} config -l`.
|
1194
1260
|
split("\n").
|
1195
|
-
|
1261
|
+
each_with_object(Hash.new) do |line, h|
|
1196
1262
|
k, v = line.strip.split('=', 2)
|
1197
1263
|
h[k] = v
|
1198
|
-
h
|
1199
1264
|
end
|
1200
|
-
url = vars["remote.#{remote_name}.url"] ||
|
1201
|
-
vars['remote.origin.url']
|
1265
|
+
url = vars["remote.#{remote_name}.url"] || vars['remote.origin.url']
|
1202
1266
|
if url
|
1203
|
-
return Hash[:
|
1267
|
+
return Hash[type: :git, url: url]
|
1204
1268
|
else
|
1205
|
-
return Hash[:
|
1269
|
+
return Hash[type: :git]
|
1206
1270
|
end
|
1207
1271
|
end
|
1208
1272
|
end
|
1209
1273
|
|
1210
1274
|
def declare_alternate_repository(name, repository, options = Hash.new)
|
1211
|
-
|
1212
|
-
raise ArgumentError, "cannot declare alternate repository
|
1275
|
+
unless name
|
1276
|
+
raise ArgumentError, "cannot declare alternate repository "\
|
1277
|
+
"#{repository} without a name"
|
1213
1278
|
end
|
1214
1279
|
additional_remotes << [name, repository, options[:push_to] || repository]
|
1215
1280
|
end
|
@@ -1221,4 +1286,3 @@ def self.git(repository, branch = nil, options = {})
|
|
1221
1286
|
Git.new(repository, branch, options)
|
1222
1287
|
end
|
1223
1288
|
end
|
1224
|
-
|