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