git-multirepo 1.0.0.beta70 → 1.0.0.beta71
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 +5 -5
- data/.gitattributes +4 -4
- data/.gitbugtraq +3 -3
- data/.gitignore +38 -38
- data/.rspec +2 -2
- data/.rubocop.yml +79 -79
- data/CHANGELOG.md +116 -112
- data/Gemfile +4 -4
- data/Gemfile.lock +47 -47
- data/LICENSE +22 -22
- data/README.md +178 -178
- data/Rakefile +1 -1
- data/bin/multi +11 -11
- data/docs/bug-repros/91565510-repro.sh +20 -20
- data/git-multirepo.gemspec +31 -31
- data/lib/git-multirepo.rb +3 -3
- data/lib/multirepo/commands/add-command.rb +55 -55
- data/lib/multirepo/commands/branch-command.rb +88 -88
- data/lib/multirepo/commands/checkout-command.rb +127 -127
- data/lib/multirepo/commands/clone-command.rb +68 -68
- data/lib/multirepo/commands/command.rb +87 -87
- data/lib/multirepo/commands/commands.rb +14 -14
- data/lib/multirepo/commands/do-command.rb +101 -101
- data/lib/multirepo/commands/init-command.rb +121 -121
- data/lib/multirepo/commands/inspect-command.rb +48 -48
- data/lib/multirepo/commands/install-command.rb +170 -170
- data/lib/multirepo/commands/merge-command.rb +249 -249
- data/lib/multirepo/commands/open-command.rb +55 -55
- data/lib/multirepo/commands/remove-command.rb +48 -48
- data/lib/multirepo/commands/uninit-command.rb +18 -18
- data/lib/multirepo/commands/update-command.rb +112 -112
- data/lib/multirepo/config.rb +19 -19
- data/lib/multirepo/files/config-entry.rb +39 -39
- data/lib/multirepo/files/config-file.rb +52 -52
- data/lib/multirepo/files/lock-entry.rb +29 -29
- data/lib/multirepo/files/lock-file.rb +62 -62
- data/lib/multirepo/files/meta-file.rb +51 -51
- data/lib/multirepo/files/tracking-file.rb +9 -9
- data/lib/multirepo/files/tracking-files.rb +64 -64
- data/lib/multirepo/git/branch.rb +32 -32
- data/lib/multirepo/git/change.rb +11 -11
- data/lib/multirepo/git/commit.rb +7 -7
- data/lib/multirepo/git/git-runner.rb +56 -56
- data/lib/multirepo/git/git.rb +10 -10
- data/lib/multirepo/git/ref.rb +38 -38
- data/lib/multirepo/git/remote.rb +17 -17
- data/lib/multirepo/git/repo.rb +131 -131
- data/lib/multirepo/hooks/post-commit-hook.rb +23 -23
- data/lib/multirepo/hooks/pre-commit-hook.rb +35 -35
- data/lib/multirepo/info.rb +5 -5
- data/lib/multirepo/logic/dependency.rb +6 -6
- data/lib/multirepo/logic/merge-descriptor.rb +95 -95
- data/lib/multirepo/logic/node.rb +75 -75
- data/lib/multirepo/logic/performer.rb +62 -62
- data/lib/multirepo/logic/repo-selection.rb +25 -25
- data/lib/multirepo/logic/revision-selection.rb +15 -15
- data/lib/multirepo/logic/revision-selector.rb +23 -23
- data/lib/multirepo/logic/version-comparer.rb +10 -10
- data/lib/multirepo/multirepo-exception.rb +6 -6
- data/lib/multirepo/output/extra-output.rb +12 -12
- data/lib/multirepo/output/teamcity-extra-output.rb +11 -11
- data/lib/multirepo/utility/console.rb +52 -52
- data/lib/multirepo/utility/popen-runner.rb +27 -27
- data/lib/multirepo/utility/system-runner.rb +14 -14
- data/lib/multirepo/utility/utils.rb +107 -107
- data/lib/multirepo/utility/verbosity.rb +6 -6
- data/resources/.gitconfig +2 -2
- data/resources/post-commit +0 -0
- data/resources/pre-commit +0 -0
- data/spec/integration/init_spec.rb +19 -19
- data/spec/spec_helper.rb +89 -89
- metadata +3 -3
data/lib/multirepo/logic/node.rb
CHANGED
@@ -1,75 +1,75 @@
|
|
1
|
-
require "multirepo/files/config-file"
|
2
|
-
require "multirepo/utility/utils"
|
3
|
-
|
4
|
-
module MultiRepo
|
5
|
-
class Node
|
6
|
-
attr_accessor :path
|
7
|
-
attr_accessor :depth
|
8
|
-
attr_accessor :parent
|
9
|
-
|
10
|
-
def initialize(path, parent = nil, depth = 0)
|
11
|
-
@path = path
|
12
|
-
@depth = depth
|
13
|
-
@parent = parent
|
14
|
-
end
|
15
|
-
|
16
|
-
def name
|
17
|
-
Pathname.new(File.expand_path(@path)).basename.to_s
|
18
|
-
end
|
19
|
-
|
20
|
-
def children
|
21
|
-
return [] unless Utils.multirepo_enabled?(@path)
|
22
|
-
config_entries = ConfigFile.new(@path).load_entries
|
23
|
-
return config_entries.map { |e| Node.new(e.path, self, @depth + 1) }
|
24
|
-
end
|
25
|
-
|
26
|
-
def ordered_descendants_including_self
|
27
|
-
return ordered_descendants.push(self)
|
28
|
-
end
|
29
|
-
|
30
|
-
def ordered_descendants
|
31
|
-
descendants = find_descendants_recursive(self)
|
32
|
-
|
33
|
-
unique_paths = descendants.map(&:path).uniq
|
34
|
-
unique_nodes = unique_paths.collect do |path|
|
35
|
-
nodes_for_path = descendants.select { |d| d.path == path }
|
36
|
-
next nodes_for_path.sort_by(&:depth).first
|
37
|
-
end
|
38
|
-
|
39
|
-
return unique_nodes.sort_by(&:depth).reverse
|
40
|
-
end
|
41
|
-
|
42
|
-
def find_descendants_recursive(node)
|
43
|
-
ensure_no_dependency_cycle(node)
|
44
|
-
|
45
|
-
descendants = node.children
|
46
|
-
descendants.each { |d| descendants.push(*find_descendants_recursive(d)) }
|
47
|
-
return descendants
|
48
|
-
end
|
49
|
-
|
50
|
-
def ensure_no_dependency_cycle(node)
|
51
|
-
parent = node.parent
|
52
|
-
visited = []
|
53
|
-
while parent
|
54
|
-
visited.push(parent)
|
55
|
-
if parent == node
|
56
|
-
Console.log_warning("Dependency cycle detected:")
|
57
|
-
visited.reverse.each_with_index do |n, i|
|
58
|
-
description = "[first]" if i == visited.count - 1
|
59
|
-
description = "itself" if visited.count == 1
|
60
|
-
Console.log_warning("'#{n.path}' depends on #{description}")
|
61
|
-
end
|
62
|
-
fail MultiRepoException, "Dependency cycles are not supported by multirepo."
|
63
|
-
end
|
64
|
-
parent = parent.parent # Will eventually be nil (root node), which will break out of the loop
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def ==(other)
|
69
|
-
other.class == self.class &&
|
70
|
-
otherPath = Utils.standard_path(other.path)
|
71
|
-
thisPath = Utils.standard_path(@path)
|
72
|
-
otherPath.casecmp(thisPath) == 0
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
1
|
+
require "multirepo/files/config-file"
|
2
|
+
require "multirepo/utility/utils"
|
3
|
+
|
4
|
+
module MultiRepo
|
5
|
+
class Node
|
6
|
+
attr_accessor :path
|
7
|
+
attr_accessor :depth
|
8
|
+
attr_accessor :parent
|
9
|
+
|
10
|
+
def initialize(path, parent = nil, depth = 0)
|
11
|
+
@path = path
|
12
|
+
@depth = depth
|
13
|
+
@parent = parent
|
14
|
+
end
|
15
|
+
|
16
|
+
def name
|
17
|
+
Pathname.new(File.expand_path(@path)).basename.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
def children
|
21
|
+
return [] unless Utils.multirepo_enabled?(@path)
|
22
|
+
config_entries = ConfigFile.new(@path).load_entries
|
23
|
+
return config_entries.map { |e| Node.new(e.path, self, @depth + 1) }
|
24
|
+
end
|
25
|
+
|
26
|
+
def ordered_descendants_including_self
|
27
|
+
return ordered_descendants.push(self)
|
28
|
+
end
|
29
|
+
|
30
|
+
def ordered_descendants
|
31
|
+
descendants = find_descendants_recursive(self)
|
32
|
+
|
33
|
+
unique_paths = descendants.map(&:path).uniq
|
34
|
+
unique_nodes = unique_paths.collect do |path|
|
35
|
+
nodes_for_path = descendants.select { |d| d.path == path }
|
36
|
+
next nodes_for_path.sort_by(&:depth).first
|
37
|
+
end
|
38
|
+
|
39
|
+
return unique_nodes.sort_by(&:depth).reverse
|
40
|
+
end
|
41
|
+
|
42
|
+
def find_descendants_recursive(node)
|
43
|
+
ensure_no_dependency_cycle(node)
|
44
|
+
|
45
|
+
descendants = node.children
|
46
|
+
descendants.each { |d| descendants.push(*find_descendants_recursive(d)) }
|
47
|
+
return descendants
|
48
|
+
end
|
49
|
+
|
50
|
+
def ensure_no_dependency_cycle(node)
|
51
|
+
parent = node.parent
|
52
|
+
visited = []
|
53
|
+
while parent
|
54
|
+
visited.push(parent)
|
55
|
+
if parent == node
|
56
|
+
Console.log_warning("Dependency cycle detected:")
|
57
|
+
visited.reverse.each_with_index do |n, i|
|
58
|
+
description = "[first]" if i == visited.count - 1
|
59
|
+
description = "itself" if visited.count == 1
|
60
|
+
Console.log_warning("'#{n.path}' depends on #{description}")
|
61
|
+
end
|
62
|
+
fail MultiRepoException, "Dependency cycles are not supported by multirepo."
|
63
|
+
end
|
64
|
+
parent = parent.parent # Will eventually be nil (root node), which will break out of the loop
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def ==(other)
|
69
|
+
other.class == self.class &&
|
70
|
+
otherPath = Utils.standard_path(other.path)
|
71
|
+
thisPath = Utils.standard_path(@path)
|
72
|
+
otherPath.casecmp(thisPath) == 0
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -1,62 +1,62 @@
|
|
1
|
-
require "multirepo/files/config-file"
|
2
|
-
require "multirepo/files/lock-file"
|
3
|
-
require "multirepo/utility/utils"
|
4
|
-
|
5
|
-
require_relative "dependency"
|
6
|
-
|
7
|
-
module MultiRepo
|
8
|
-
class Performer
|
9
|
-
def self.perform_main_repo_checkout(main_repo, ref_name, force = false, message = nil)
|
10
|
-
# Make sure the main repo is clean before attempting a checkout
|
11
|
-
unless force || main_repo.clean?
|
12
|
-
fail MultiRepoException, "Can't checkout #{ref_name} because the main repo contains uncommitted changes"
|
13
|
-
end
|
14
|
-
|
15
|
-
# Checkout the specified ref
|
16
|
-
unless main_repo.checkout(ref_name)
|
17
|
-
fail MultiRepoException, "Couldn't perform checkout of main repo #{ref_name}!"
|
18
|
-
end
|
19
|
-
|
20
|
-
Console.log_substep(message || "Checked out main repo #{ref_name}")
|
21
|
-
|
22
|
-
# After checkout, make sure we're working with a multirepo-enabled ref
|
23
|
-
unless Utils.multirepo_tracked?(".")
|
24
|
-
fail MultiRepoException, "Revision #{ref_name} is not tracked by multirepo!"
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.depth_ordered_dependencies
|
29
|
-
config_entries = ConfigFile.new(".").load_entries
|
30
|
-
lock_entries = LockFile.new(".").load_entries
|
31
|
-
|
32
|
-
dependencies = build_dependencies(config_entries, lock_entries)
|
33
|
-
dependency_ordered_nodes = Node.new(".").ordered_descendants
|
34
|
-
|
35
|
-
depth_ordered = dependency_ordered_nodes.map do |node|
|
36
|
-
dependencies.find do |d|
|
37
|
-
configPath = Utils.standard_path(d.config_entry.path)
|
38
|
-
nodePath = Utils.standard_path(node.path)
|
39
|
-
next configPath.casecmp(nodePath) == 0
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
return depth_ordered
|
44
|
-
end
|
45
|
-
|
46
|
-
def self.build_dependencies(config_entries, lock_entries)
|
47
|
-
lock_entries.map do |lock_entry|
|
48
|
-
config_entry = config_entry_for_lock_entry(config_entries, lock_entry)
|
49
|
-
|
50
|
-
dependency = Dependency.new
|
51
|
-
dependency.config_entry = config_entry
|
52
|
-
dependency.lock_entry = lock_entry
|
53
|
-
|
54
|
-
next dependency
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.config_entry_for_lock_entry(config_entries, lock_entry)
|
59
|
-
config_entries.find { |config_entry| config_entry.id == lock_entry.id }
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
1
|
+
require "multirepo/files/config-file"
|
2
|
+
require "multirepo/files/lock-file"
|
3
|
+
require "multirepo/utility/utils"
|
4
|
+
|
5
|
+
require_relative "dependency"
|
6
|
+
|
7
|
+
module MultiRepo
|
8
|
+
class Performer
|
9
|
+
def self.perform_main_repo_checkout(main_repo, ref_name, force = false, message = nil)
|
10
|
+
# Make sure the main repo is clean before attempting a checkout
|
11
|
+
unless force || main_repo.clean?
|
12
|
+
fail MultiRepoException, "Can't checkout #{ref_name} because the main repo contains uncommitted changes"
|
13
|
+
end
|
14
|
+
|
15
|
+
# Checkout the specified ref
|
16
|
+
unless main_repo.checkout(ref_name)
|
17
|
+
fail MultiRepoException, "Couldn't perform checkout of main repo #{ref_name}!"
|
18
|
+
end
|
19
|
+
|
20
|
+
Console.log_substep(message || "Checked out main repo #{ref_name}")
|
21
|
+
|
22
|
+
# After checkout, make sure we're working with a multirepo-enabled ref
|
23
|
+
unless Utils.multirepo_tracked?(".")
|
24
|
+
fail MultiRepoException, "Revision #{ref_name} is not tracked by multirepo!"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.depth_ordered_dependencies
|
29
|
+
config_entries = ConfigFile.new(".").load_entries
|
30
|
+
lock_entries = LockFile.new(".").load_entries
|
31
|
+
|
32
|
+
dependencies = build_dependencies(config_entries, lock_entries)
|
33
|
+
dependency_ordered_nodes = Node.new(".").ordered_descendants
|
34
|
+
|
35
|
+
depth_ordered = dependency_ordered_nodes.map do |node|
|
36
|
+
dependencies.find do |d|
|
37
|
+
configPath = Utils.standard_path(d.config_entry.path)
|
38
|
+
nodePath = Utils.standard_path(node.path)
|
39
|
+
next configPath.casecmp(nodePath) == 0
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
return depth_ordered
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.build_dependencies(config_entries, lock_entries)
|
47
|
+
lock_entries.map do |lock_entry|
|
48
|
+
config_entry = config_entry_for_lock_entry(config_entries, lock_entry)
|
49
|
+
|
50
|
+
dependency = Dependency.new
|
51
|
+
dependency.config_entry = config_entry
|
52
|
+
dependency.lock_entry = lock_entry
|
53
|
+
|
54
|
+
next dependency
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.config_entry_for_lock_entry(config_entries, lock_entry)
|
59
|
+
config_entries.find { |config_entry| config_entry.id == lock_entry.id }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -1,25 +1,25 @@
|
|
1
|
-
require "multirepo/utility/utils"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class RepoSelection
|
5
|
-
ALL = 0
|
6
|
-
MAIN = 1
|
7
|
-
DEPS = 2
|
8
|
-
|
9
|
-
def initialize(argv)
|
10
|
-
@main = argv.flag?("main")
|
11
|
-
@deps = argv.flag?("deps")
|
12
|
-
@all = argv.flag?("all")
|
13
|
-
end
|
14
|
-
|
15
|
-
def valid?
|
16
|
-
Utils.only_one_true?(@main, @deps, @all)
|
17
|
-
end
|
18
|
-
|
19
|
-
def value
|
20
|
-
return MAIN if @main
|
21
|
-
return DEPS if @deps
|
22
|
-
return ALL # Default if unspecified
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
1
|
+
require "multirepo/utility/utils"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class RepoSelection
|
5
|
+
ALL = 0
|
6
|
+
MAIN = 1
|
7
|
+
DEPS = 2
|
8
|
+
|
9
|
+
def initialize(argv)
|
10
|
+
@main = argv.flag?("main")
|
11
|
+
@deps = argv.flag?("deps")
|
12
|
+
@all = argv.flag?("all")
|
13
|
+
end
|
14
|
+
|
15
|
+
def valid?
|
16
|
+
Utils.only_one_true?(@main, @deps, @all)
|
17
|
+
end
|
18
|
+
|
19
|
+
def value
|
20
|
+
return MAIN if @main
|
21
|
+
return DEPS if @deps
|
22
|
+
return ALL # Default if unspecified
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
|
-
module MultiRepo
|
2
|
-
class RevisionSelection
|
3
|
-
AS_LOCK = 0
|
4
|
-
LATEST = 1
|
5
|
-
EXACT = 2
|
6
|
-
|
7
|
-
def self.name_for_mode(mode)
|
8
|
-
case mode
|
9
|
-
when AS_LOCK then "as-lock"
|
10
|
-
when LATEST then "latest"
|
11
|
-
when EXACT then "exact"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
1
|
+
module MultiRepo
|
2
|
+
class RevisionSelection
|
3
|
+
AS_LOCK = 0
|
4
|
+
LATEST = 1
|
5
|
+
EXACT = 2
|
6
|
+
|
7
|
+
def self.name_for_mode(mode)
|
8
|
+
case mode
|
9
|
+
when AS_LOCK then "as-lock"
|
10
|
+
when LATEST then "latest"
|
11
|
+
when EXACT then "exact"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -1,23 +1,23 @@
|
|
1
|
-
require_relative "revision-selection"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class RevisionSelector
|
5
|
-
def self.mode_for_args(checkout_latest, checkout_exact)
|
6
|
-
if checkout_latest
|
7
|
-
RevisionSelection::LATEST
|
8
|
-
elsif checkout_exact
|
9
|
-
RevisionSelection::EXACT
|
10
|
-
else
|
11
|
-
RevisionSelection::AS_LOCK
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.revision_for_mode(mode, ref_name, lock_entry)
|
16
|
-
case mode
|
17
|
-
when RevisionSelection::AS_LOCK then lock_entry.head
|
18
|
-
when RevisionSelection::LATEST then lock_entry.branch
|
19
|
-
when RevisionSelection::EXACT then ref_name
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
1
|
+
require_relative "revision-selection"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class RevisionSelector
|
5
|
+
def self.mode_for_args(checkout_latest, checkout_exact)
|
6
|
+
if checkout_latest
|
7
|
+
RevisionSelection::LATEST
|
8
|
+
elsif checkout_exact
|
9
|
+
RevisionSelection::EXACT
|
10
|
+
else
|
11
|
+
RevisionSelection::AS_LOCK
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.revision_for_mode(mode, ref_name, lock_entry)
|
16
|
+
case mode
|
17
|
+
when RevisionSelection::AS_LOCK then lock_entry.head
|
18
|
+
when RevisionSelection::LATEST then lock_entry.branch
|
19
|
+
when RevisionSelection::EXACT then ref_name
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,10 +1,10 @@
|
|
1
|
-
require "naturally"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class VersionComparer
|
5
|
-
def self.is_latest(current:, last:)
|
6
|
-
return true if current == last
|
7
|
-
return Naturally.sort([current, last]).last == current
|
8
|
-
end
|
9
|
-
end
|
10
|
-
end
|
1
|
+
require "naturally"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class VersionComparer
|
5
|
+
def self.is_latest(current:, last:)
|
6
|
+
return true if current == last
|
7
|
+
return Naturally.sort([current, last]).last == current
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -1,6 +1,6 @@
|
|
1
|
-
require "claide/informative_error"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class MultiRepoException < StandardError
|
5
|
-
end
|
6
|
-
end
|
1
|
+
require "claide/informative_error"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class MultiRepoException < StandardError
|
5
|
+
end
|
6
|
+
end
|
@@ -1,12 +1,12 @@
|
|
1
|
-
require_relative "teamcity-extra-output"
|
2
|
-
|
3
|
-
module MultiRepo
|
4
|
-
class ExtraOutput < BasicObject
|
5
|
-
def self.method_missing(sym, *args, &block)
|
6
|
-
output = case Config.instance.extra_output
|
7
|
-
when "teamcity"; TeamCityExtraOutput.new
|
8
|
-
end
|
9
|
-
output.send(sym, *args, &block) if output
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
1
|
+
require_relative "teamcity-extra-output"
|
2
|
+
|
3
|
+
module MultiRepo
|
4
|
+
class ExtraOutput < BasicObject
|
5
|
+
def self.method_missing(sym, *args, &block)
|
6
|
+
output = case Config.instance.extra_output
|
7
|
+
when "teamcity"; TeamCityExtraOutput.new
|
8
|
+
end
|
9
|
+
output.send(sym, *args, &block) if output
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|