git-multi 2.0.0 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/exe/git-multi +1 -1
- data/lib/git/multi/commands.rb +38 -32
- data/lib/git/multi/config.rb +31 -0
- data/lib/git/multi/report.rb +132 -0
- data/lib/git/multi/version.rb +1 -1
- data/lib/git/multi.rb +71 -53
- data/man/git-multi.1 +8 -3
- data/man/git-multi.erb +3 -0
- data/man/git-multi.html +10 -2
- metadata +4 -4
- data/lib/git/multi/settings.rb +0 -99
- data/lib/git/multi/utils.rb +0 -57
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c1bda879ee8b1b3320c8d5490201645cf2f686f8e82cb8200fb1b0a2f8538588
|
4
|
+
data.tar.gz: 072b2cfb7ed429f2a8f78b969ce808a4a0365ab37575c86deceb02c2bbe85701
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2565edfd604e66bbcfeda950c83e5da58ac5f4fbda2173e1705dd56ff98ad8c04b2f757edcaa8c4a45e37e7ab184361db8b3ff2645c95f3b3fd1c100ab7f2279
|
7
|
+
data.tar.gz: 3d56e12752052a25dc64fed40684ae88125d6f330930efbd3a553b1874127a6d721e249306c1b8d2090f102b7cd836d565ca182dba2fd94412687232492dd846
|
data/exe/git-multi
CHANGED
@@ -21,7 +21,7 @@ when /\A--/
|
|
21
21
|
when '--version' then Git::Multi::Commands.version
|
22
22
|
when '--help' then Git::Multi::Commands.help
|
23
23
|
when '--html' then Git::Multi::Commands.html
|
24
|
-
when '--report' then Git::Multi::Commands.report
|
24
|
+
when '--report' then Git::Multi::Commands.report(multi_repo)
|
25
25
|
when '--count' then Git::Multi::Commands.count
|
26
26
|
when '--refresh' then Git::Multi::Commands.refresh
|
27
27
|
when '--json' then Git::Multi::Commands.json(multi_repo)
|
data/lib/git/multi/commands.rb
CHANGED
@@ -16,11 +16,17 @@ module Git
|
|
16
16
|
Kernel.exec "open #{Git::Multi::HTML_PAGE}"
|
17
17
|
end
|
18
18
|
|
19
|
-
def report
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
def report(multi_repo = nil)
|
20
|
+
case multi_repo
|
21
|
+
when nil
|
22
|
+
Report.home_status(Git::Multi::HOME)
|
23
|
+
Report.workarea_status(Git::Multi::WORKAREA)
|
24
|
+
Report.for(*MULTI_REPOS)
|
25
|
+
when *MULTI_REPOS
|
26
|
+
Report.for(multi_repo)
|
27
|
+
else
|
28
|
+
raise "Unknown multi repo: #{multi_repo}"
|
29
|
+
end
|
24
30
|
end
|
25
31
|
|
26
32
|
def count
|
@@ -71,14 +77,14 @@ module Git
|
|
71
77
|
end
|
72
78
|
|
73
79
|
def clone(multi_repo = nil)
|
74
|
-
Git::Multi.missing_repositories_for(multi_repo).each do |
|
75
|
-
FileUtils.mkdir_p
|
76
|
-
|
77
|
-
->(
|
78
|
-
Kernel.system "git clone -q #{
|
80
|
+
Git::Multi.missing_repositories_for(multi_repo).each do |repository|
|
81
|
+
FileUtils.mkdir_p repository.parent_dir # create multi-repo workarea
|
82
|
+
repository.just_do_it(
|
83
|
+
->(repo) {
|
84
|
+
Kernel.system "git clone -q #{repo.rels[:ssh].href.shellescape}"
|
79
85
|
},
|
80
|
-
->(
|
81
|
-
Kernel.system "git clone -q #{
|
86
|
+
->(repo) {
|
87
|
+
Kernel.system "git clone -q #{repo.rels[:ssh].href.shellescape}"
|
82
88
|
},
|
83
89
|
in: 'parent_dir'
|
84
90
|
)
|
@@ -98,33 +104,33 @@ module Git
|
|
98
104
|
end
|
99
105
|
|
100
106
|
def query(args = [], multi_repo = nil)
|
101
|
-
Git::Multi.repositories_for(multi_repo).each do |
|
102
|
-
|
103
|
-
->(
|
107
|
+
Git::Multi.repositories_for(multi_repo).each do |repository|
|
108
|
+
repository.just_do_it(
|
109
|
+
->(repo) {
|
104
110
|
args.each do |attribute|
|
105
|
-
puts "#{attribute}: #{
|
111
|
+
puts "#{attribute}: #{repo[attribute]}"
|
106
112
|
end
|
107
113
|
},
|
108
|
-
->(
|
109
|
-
print "#{
|
110
|
-
puts args.map { |attribute|
|
114
|
+
->(repo) {
|
115
|
+
print "#{repo.full_name}: "
|
116
|
+
puts args.map { |attribute| repo[attribute] }.join(' ')
|
111
117
|
},
|
112
118
|
)
|
113
119
|
end
|
114
120
|
end
|
115
121
|
|
116
122
|
def find(commands, multi_repo = nil)
|
117
|
-
Git::Multi.cloned_repositories_for(multi_repo).each do |
|
118
|
-
Dir.chdir(
|
123
|
+
Git::Multi.cloned_repositories_for(multi_repo).each do |repository|
|
124
|
+
Dir.chdir(repository.local_path) do
|
119
125
|
if repo.instance_eval(commands.join(' && '))
|
120
126
|
repo.just_do_it(
|
121
|
-
->(
|
122
|
-
->(
|
127
|
+
->(_repo) { nil },
|
128
|
+
->(repo) { puts repo.full_name },
|
123
129
|
)
|
124
130
|
end
|
125
131
|
rescue Octokit::NotFound
|
126
|
-
#
|
127
|
-
# consider running "git multi --stale"
|
132
|
+
# repository no longer exists on GitHub
|
133
|
+
# consider running "git multi --stale"!
|
128
134
|
end
|
129
135
|
end
|
130
136
|
end
|
@@ -134,8 +140,8 @@ module Git
|
|
134
140
|
Dir.chdir(repo.local_path) do
|
135
141
|
repo.instance_eval(commands.join(' ; '))
|
136
142
|
rescue Octokit::NotFound
|
137
|
-
#
|
138
|
-
# consider running "git multi --stale"
|
143
|
+
# repository no longer exists on GitHub
|
144
|
+
# consider running "git multi --stale"!
|
139
145
|
end
|
140
146
|
end
|
141
147
|
end
|
@@ -152,13 +158,13 @@ module Git
|
|
152
158
|
|
153
159
|
def system(args = [], multi_repo = nil)
|
154
160
|
cmd = args.map!(&:shellescape).join(' ')
|
155
|
-
Git::Multi.cloned_repositories_for(multi_repo).each do |
|
156
|
-
|
157
|
-
->(
|
161
|
+
Git::Multi.cloned_repositories_for(multi_repo).each do |repository|
|
162
|
+
repository.just_do_it(
|
163
|
+
->(_repo) {
|
158
164
|
Kernel.system cmd
|
159
165
|
},
|
160
|
-
->(
|
161
|
-
Kernel.system "#{cmd} 2>&1 | sed -e 's#^##{
|
166
|
+
->(repo) {
|
167
|
+
Kernel.system "#{cmd} 2>&1 | sed -e 's#^##{repo.full_name.shellescape}: #'"
|
162
168
|
},
|
163
169
|
in: 'local_path'
|
164
170
|
)
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Git
|
2
|
+
module Multi
|
3
|
+
|
4
|
+
module_function
|
5
|
+
|
6
|
+
def local_option(path, name, default = nil)
|
7
|
+
value = `git -C #{path} config --local --get #{name}`.chomp.freeze
|
8
|
+
value.empty? && default ? default : value
|
9
|
+
end
|
10
|
+
|
11
|
+
def local_list(filename, name)
|
12
|
+
list = `git config --file #{filename} --get-all #{name}`
|
13
|
+
list.split($RS).map(&:strip).map(&:freeze)
|
14
|
+
end
|
15
|
+
|
16
|
+
def global_option(name, default = nil)
|
17
|
+
value = `git config --global --get #{name}`.chomp.freeze
|
18
|
+
value.empty? && default ? default : value
|
19
|
+
end
|
20
|
+
|
21
|
+
def global_list(name, default = nil)
|
22
|
+
global_option(name, default).split(',').map(&:strip).map(&:freeze)
|
23
|
+
end
|
24
|
+
|
25
|
+
def env_var(name, default = nil)
|
26
|
+
value = ENV[name].dup.freeze
|
27
|
+
(value.nil? || value.empty?) && default ? default : value
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Git
|
2
|
+
module Multi
|
3
|
+
module Report
|
4
|
+
|
5
|
+
TICK = ['2714'.hex].pack('U*').green.freeze
|
6
|
+
CROSS = ['2718'.hex].pack('U*').red.freeze
|
7
|
+
ARROW = ['2794'.hex].pack('U*').blue.freeze
|
8
|
+
|
9
|
+
module_function
|
10
|
+
|
11
|
+
def home_status(home)
|
12
|
+
directory_status(['${HOME}', home], home)
|
13
|
+
end
|
14
|
+
|
15
|
+
def workarea_status(workarea)
|
16
|
+
directory_status(['${WORKAREA}', abbreviate(workarea, :home)], workarea)
|
17
|
+
end
|
18
|
+
|
19
|
+
def owner_status(message, workarea, owner)
|
20
|
+
directory_status(
|
21
|
+
[
|
22
|
+
message,
|
23
|
+
File.join(abbreviate(workarea, :workarea), owner),
|
24
|
+
],
|
25
|
+
File.join(workarea, owner)
|
26
|
+
)
|
27
|
+
|
28
|
+
github_count = Git::Multi.repositories_for(owner).count
|
29
|
+
cloned_count = Git::Multi.cloned_repositories_for(owner).count
|
30
|
+
missing_count = (github_count - cloned_count)
|
31
|
+
subdir_count = Dir.new(workarea).git_repos(owner).count
|
32
|
+
surplus_count = (subdir_count - cloned_count)
|
33
|
+
|
34
|
+
setting_status(["\tGitHub ", "#{github_count} repositories"])
|
35
|
+
setting_status(["\tcloned ", cloned_count, "(#{missing_count} missing)"])
|
36
|
+
Git::Multi.missing_repositories_for(owner).each do |missing|
|
37
|
+
setting_status(["\tmissing", missing.full_name], false, false)
|
38
|
+
end
|
39
|
+
setting_status(["\tsubdirs", subdir_count, "(#{surplus_count} surplus)"])
|
40
|
+
end
|
41
|
+
|
42
|
+
def project_status(message, superproject)
|
43
|
+
github_count = Git::Multi.repositories_for(superproject).count
|
44
|
+
|
45
|
+
if github_count.zero?
|
46
|
+
setting_status([message, 'listed but not configured'], false, false)
|
47
|
+
else
|
48
|
+
setting_status([message], true)
|
49
|
+
Git::Multi.repositories_for(superproject).each do |repo|
|
50
|
+
if File.directory? repo.local_path
|
51
|
+
setting_status(["\tcloned ", repo.full_name], true)
|
52
|
+
else
|
53
|
+
setting_status(["\tmissing", repo.full_name], false, false)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def for(*multi_repos)
|
60
|
+
multi_repos.each do |multi_repo|
|
61
|
+
case (user = org = project = multi_repo)
|
62
|
+
when *USERS
|
63
|
+
owner_status("user \"#{user}\"", Git::Multi::WORKAREA, user)
|
64
|
+
when *ORGANIZATIONS
|
65
|
+
owner_status("org \"#{org}\"", Git::Multi::WORKAREA, org)
|
66
|
+
when *SUPERPROJECTS
|
67
|
+
project_status("superproject \"#{project}\"", project)
|
68
|
+
else
|
69
|
+
raise "Unknown multi repo: #{multi_repo}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
private_class_method def describe(token)
|
75
|
+
if token.nil?
|
76
|
+
'(nil)'
|
77
|
+
elsif token.empty?
|
78
|
+
'(empty)'
|
79
|
+
else
|
80
|
+
"#{'*' * 36}#{token[36..-1]}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
private_class_method def symbolize(token)
|
85
|
+
case token
|
86
|
+
when Git::Multi.env_var('OCTOKIT_ACCESS_TOKEN')
|
87
|
+
then '${OCTOKIT_ACCESS_TOKEN}'
|
88
|
+
when Git::Multi.global_option('github.token')
|
89
|
+
then 'github.token'
|
90
|
+
else '(unset)'
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
private_class_method def abbreviate(directory, root_dir = nil)
|
95
|
+
case root_dir
|
96
|
+
when :home
|
97
|
+
then directory.gsub(Git::Multi::HOME, '${HOME}')
|
98
|
+
when :workarea
|
99
|
+
then directory.gsub(Git::Multi::WORKAREA, '${WORKAREA}')
|
100
|
+
else abbreviate(abbreviate(directory, :workarea), :home)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
private_class_method def setting_status(messages, valid = false, optional = true)
|
105
|
+
fields = messages.compact.join(' - ')
|
106
|
+
icon = valid ? TICK : optional ? ARROW : CROSS
|
107
|
+
puts "#{icon} #{fields}"
|
108
|
+
end
|
109
|
+
|
110
|
+
private_class_method def file_status(file, message = 'File')
|
111
|
+
setting_status(
|
112
|
+
[
|
113
|
+
message,
|
114
|
+
abbreviate(file),
|
115
|
+
File.file?(file) ? "#{File.size(file).commify} bytes" : nil,
|
116
|
+
],
|
117
|
+
file && !file.empty? && File.file?(file),
|
118
|
+
false
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
private_class_method def directory_status(messages, directory)
|
123
|
+
setting_status(
|
124
|
+
messages,
|
125
|
+
directory && !directory.empty? && File.directory?(directory),
|
126
|
+
false
|
127
|
+
)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/git/multi/version.rb
CHANGED
data/lib/git/multi.rb
CHANGED
@@ -15,9 +15,9 @@ require 'ext/sawyer/resource'
|
|
15
15
|
|
16
16
|
require 'git/hub'
|
17
17
|
|
18
|
-
require 'git/multi/
|
18
|
+
require 'git/multi/config'
|
19
|
+
require 'git/multi/report'
|
19
20
|
require 'git/multi/version'
|
20
|
-
require 'git/multi/settings'
|
21
21
|
require 'git/multi/commands'
|
22
22
|
|
23
23
|
module Git
|
@@ -26,16 +26,23 @@ module Git
|
|
26
26
|
HOME = Dir.home
|
27
27
|
|
28
28
|
DEFAULT_WORKAREA = File.join(HOME, 'Workarea')
|
29
|
-
WORKAREA =
|
29
|
+
WORKAREA = global_option('git.multi.workarea', DEFAULT_WORKAREA)
|
30
30
|
|
31
31
|
DEFAULT_TOKEN = env_var('OCTOKIT_ACCESS_TOKEN') # same as Octokit
|
32
|
-
TOKEN =
|
32
|
+
TOKEN = global_option('github.token', DEFAULT_TOKEN)
|
33
33
|
|
34
|
-
|
35
|
-
REPOSITORIES = File.join(CACHE, 'repositories.byte')
|
34
|
+
GIT_MULTI_DIR = File.join(HOME, '.git', 'multi')
|
36
35
|
|
37
|
-
|
38
|
-
|
36
|
+
FileUtils.mkdir_p(GIT_MULTI_DIR) # ensure `~/.git/multi` directory exists
|
37
|
+
|
38
|
+
GITHUB_CACHE = File.join(GIT_MULTI_DIR, 'repositories.byte')
|
39
|
+
SUPERPROJECTS_CONFIG = File.join(GIT_MULTI_DIR, 'superprojects.config')
|
40
|
+
|
41
|
+
USERS = global_list('git.multi.users')
|
42
|
+
ORGANIZATIONS = global_list('git.multi.organizations')
|
43
|
+
SUPERPROJECTS = global_list('git.multi.superprojects')
|
44
|
+
|
45
|
+
MULTI_REPOS = (USERS + ORGANIZATIONS + SUPERPROJECTS)
|
39
46
|
|
40
47
|
MAN_PAGE = File.expand_path('../../man/git-multi.1', __dir__)
|
41
48
|
HTML_PAGE = File.expand_path('../../man/git-multi.html', __dir__)
|
@@ -47,7 +54,11 @@ module Git
|
|
47
54
|
#
|
48
55
|
|
49
56
|
def valid?(multi_repo)
|
50
|
-
|
57
|
+
MULTI_REPOS.include? multi_repo
|
58
|
+
end
|
59
|
+
|
60
|
+
def full_names_for(superproject)
|
61
|
+
local_list(SUPERPROJECTS_CONFIG, "superproject.#{superproject}.repo")
|
51
62
|
end
|
52
63
|
|
53
64
|
#
|
@@ -69,16 +80,16 @@ module Git
|
|
69
80
|
).flatten
|
70
81
|
end
|
71
82
|
|
72
|
-
def local_repositories_for(
|
73
|
-
case
|
83
|
+
def local_repositories_for(owner = nil)
|
84
|
+
case owner
|
74
85
|
when nil
|
75
|
-
local_repositories
|
86
|
+
local_repositories # all of them
|
76
87
|
when *USERS
|
77
88
|
@local_user_repositories[owner]
|
78
89
|
when *ORGANIZATIONS
|
79
90
|
@local_org_repositories[owner]
|
80
91
|
else
|
81
|
-
raise "Unknown
|
92
|
+
raise "Unknown owner: #{owner}"
|
82
93
|
end
|
83
94
|
end
|
84
95
|
|
@@ -101,16 +112,16 @@ module Git
|
|
101
112
|
).flatten
|
102
113
|
end
|
103
114
|
|
104
|
-
def github_repositories_for(
|
105
|
-
case
|
115
|
+
def github_repositories_for(owner = nil)
|
116
|
+
case owner
|
106
117
|
when nil
|
107
|
-
github_repositories
|
118
|
+
github_repositories # all of them
|
108
119
|
when *USERS
|
109
120
|
@github_user_repositories[owner]
|
110
121
|
when *ORGANIZATIONS
|
111
122
|
@github_org_repositories[owner]
|
112
123
|
else
|
113
|
-
raise "Unknown
|
124
|
+
raise "Unknown owner: #{owner}"
|
114
125
|
end
|
115
126
|
end
|
116
127
|
|
@@ -119,9 +130,7 @@ module Git
|
|
119
130
|
#
|
120
131
|
|
121
132
|
def refresh_repositories
|
122
|
-
File.
|
123
|
-
|
124
|
-
File.open(REPOSITORIES, 'wb') do |file|
|
133
|
+
File.open(GITHUB_CACHE, 'wb') do |file|
|
125
134
|
Marshal.dump(github_repositories, file)
|
126
135
|
end
|
127
136
|
end
|
@@ -151,22 +160,22 @@ module Git
|
|
151
160
|
end
|
152
161
|
|
153
162
|
def repositories
|
154
|
-
if File.size?(
|
163
|
+
if File.size?(GITHUB_CACHE)
|
155
164
|
# rubocop:disable Security/MarshalLoad
|
156
|
-
@repositories ||= Marshal.load(File.read(
|
157
|
-
|
158
|
-
# ensure '
|
159
|
-
|
160
|
-
# adorn '
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
# fix '
|
165
|
-
|
165
|
+
@repositories ||= Marshal.load(File.read(GITHUB_CACHE)).tap do |repos|
|
166
|
+
repos.each_with_index do |repo, index|
|
167
|
+
# ensure 'repo' has handle on an Octokit client
|
168
|
+
repo.client = Git::Hub.send(:client)
|
169
|
+
# adorn 'repo', which is a Sawyer::Resource
|
170
|
+
repo.parent_dir = Pathname.new(File.join(WORKAREA, repo.owner.login))
|
171
|
+
repo.local_path = Pathname.new(File.join(WORKAREA, repo.full_name))
|
172
|
+
repo.fractional_index = "#{index + 1}/#{repos.count}"
|
173
|
+
# fix 'repo' => https://github.com/octokit/octokit.rb/issues/727
|
174
|
+
repo.compliant_ssh_url = 'ssh://' + repo.ssh_url.split(':', 2).join('/')
|
166
175
|
# remove optional '.git' suffix from 'git@github.com:pvdb/git-multi.git'
|
167
|
-
|
168
|
-
# extend '
|
169
|
-
|
176
|
+
repo.abbreviated_ssh_url = repo.ssh_url.chomp('.git')
|
177
|
+
# extend 'repo' with 'just do it' capabilities
|
178
|
+
repo.extend Nike
|
170
179
|
end
|
171
180
|
end
|
172
181
|
# rubocop:enable Security/MarshalLoad
|
@@ -181,12 +190,20 @@ module Git
|
|
181
190
|
#
|
182
191
|
|
183
192
|
def repositories_for(multi_repo = nil)
|
184
|
-
|
185
|
-
|
186
|
-
|
193
|
+
case (owner = superproject = multi_repo)
|
194
|
+
when nil
|
195
|
+
repositories # all of them
|
196
|
+
when *USERS, *ORGANIZATIONS
|
197
|
+
repositories.find_all { |repository|
|
198
|
+
repository.owner.login == owner
|
199
|
+
}
|
200
|
+
when *SUPERPROJECTS
|
201
|
+
full_names = full_names_for(superproject)
|
187
202
|
repositories.find_all { |repository|
|
188
|
-
repository.
|
203
|
+
full_names.include?(repository.full_name)
|
189
204
|
}
|
205
|
+
else
|
206
|
+
raise "Unknown multi repo: #{multi_repo}"
|
190
207
|
end
|
191
208
|
end
|
192
209
|
|
@@ -212,40 +229,41 @@ module Git
|
|
212
229
|
|
213
230
|
def excess_repositories_for(multi_repo = nil)
|
214
231
|
repository_full_names = repositories_for(multi_repo).map(&:full_name)
|
215
|
-
local_repositories_for(multi_repo).reject { |
|
216
|
-
repository_full_names.include?
|
232
|
+
local_repositories_for(multi_repo).reject { |repo|
|
233
|
+
repository_full_names.include? repo.full_name
|
217
234
|
}
|
218
235
|
end
|
219
236
|
|
220
237
|
def stale_repositories_for(multi_repo = nil)
|
221
238
|
repository_full_names = github_repositories_for(multi_repo).map(&:full_name)
|
222
|
-
repositories_for(multi_repo).reject { |
|
223
|
-
repository_full_names.include?
|
239
|
+
repositories_for(multi_repo).reject { |repo|
|
240
|
+
repository_full_names.include? repo.full_name
|
224
241
|
}
|
225
242
|
end
|
226
243
|
|
227
244
|
def spurious_repositories_for(multi_repo = nil)
|
228
|
-
cloned_repositories_for(multi_repo).find_all { |
|
229
|
-
origin_url =
|
245
|
+
cloned_repositories_for(multi_repo).find_all { |repo|
|
246
|
+
origin_url = local_option(repo.local_path, 'remote.origin.url')
|
247
|
+
|
230
248
|
![
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
249
|
+
repo.clone_url,
|
250
|
+
repo.ssh_url,
|
251
|
+
repo.compliant_ssh_url,
|
252
|
+
repo.abbreviated_ssh_url,
|
253
|
+
repo.git_url,
|
236
254
|
].include? origin_url
|
237
255
|
}
|
238
256
|
end
|
239
257
|
|
240
258
|
def missing_repositories_for(multi_repo = nil)
|
241
|
-
repositories_for(multi_repo).find_all { |
|
242
|
-
!File.directory?
|
259
|
+
repositories_for(multi_repo).find_all { |repo|
|
260
|
+
!File.directory? repo.local_path
|
243
261
|
}
|
244
262
|
end
|
245
263
|
|
246
264
|
def cloned_repositories_for(multi_repo = nil)
|
247
|
-
repositories_for(multi_repo).find_all { |
|
248
|
-
File.directory?
|
265
|
+
repositories_for(multi_repo).find_all { |repo|
|
266
|
+
File.directory? repo.local_path
|
249
267
|
}
|
250
268
|
end
|
251
269
|
|
data/man/git-multi.1
CHANGED
@@ -2,12 +2,12 @@
|
|
2
2
|
.\" Title: git-multi
|
3
3
|
.\" Author: [FIXME: author] [see http://docbook.sf.net/el/author]
|
4
4
|
.\" Generator: DocBook XSL Stylesheets v1.79.1 <http://docbook.sf.net/>
|
5
|
-
.\" Date: 11/
|
5
|
+
.\" Date: 11/12/2018
|
6
6
|
.\" Manual: Git Manual
|
7
7
|
.\" Source: Git 2.19.1.542.gc4df23f792.dirty
|
8
8
|
.\" Language: English
|
9
9
|
.\"
|
10
|
-
.TH "GIT\-MULTI" "1" "11/
|
10
|
+
.TH "GIT\-MULTI" "1" "11/12/2018" "Git 2\&.19\&.1\&.542\&.gc4df23" "Git Manual"
|
11
11
|
.\" -----------------------------------------------------------------
|
12
12
|
.\" * Define some portability stuff
|
13
13
|
.\" -----------------------------------------------------------------
|
@@ -31,7 +31,7 @@
|
|
31
31
|
git-multi \- execute the same git command in multiple repositories
|
32
32
|
.SH "VERSION"
|
33
33
|
.sp
|
34
|
-
This is \fBv2\&.
|
34
|
+
This is \fBv2\&.1\&.0\fR of \fIgit multi\fR \&... hooray!
|
35
35
|
.SH "SYNOPSIS"
|
36
36
|
.sp
|
37
37
|
There are some options for \fBgit multi\fR itself, in which case it is invoked as follows:
|
@@ -539,6 +539,11 @@ root directory where repos will been cloned
|
|
539
539
|
.RS 4
|
540
540
|
local, binary cache of GitHub repository metadata
|
541
541
|
.RE
|
542
|
+
.PP
|
543
|
+
\fB${HOME}/\&.git/multi/superprojects\&.config\fR
|
544
|
+
.RS 4
|
545
|
+
definitions for so\-called "superproject" multi repos
|
546
|
+
.RE
|
542
547
|
.SH "REFERENCES"
|
543
548
|
.sp
|
544
549
|
.RS 4
|
data/man/git-multi.erb
CHANGED
@@ -248,6 +248,9 @@ FILES
|
|
248
248
|
`${HOME}/.git/multi/repositories.byte`::
|
249
249
|
local, binary cache of GitHub repository metadata
|
250
250
|
|
251
|
+
`${HOME}/.git/multi/superprojects.config`::
|
252
|
+
definitions for so-called "superproject" multi repos
|
253
|
+
|
251
254
|
REFERENCES
|
252
255
|
----------
|
253
256
|
|
data/man/git-multi.html
CHANGED
@@ -748,7 +748,7 @@ git-multi(1) Manual Page
|
|
748
748
|
<div class="sect1">
|
749
749
|
<h2 id="_version">VERSION</h2>
|
750
750
|
<div class="sectionbody">
|
751
|
-
<div class="paragraph"><p>This is <code>v2.
|
751
|
+
<div class="paragraph"><p>This is <code>v2.1.0</code> of <em>git multi</em> … hooray!</p></div>
|
752
752
|
</div>
|
753
753
|
</div>
|
754
754
|
<div class="sect1">
|
@@ -1168,6 +1168,14 @@ git multi --json | jq -r '.[] | select(.fork == true) | .full_name'</code></pre>
|
|
1168
1168
|
local, binary cache of GitHub repository metadata
|
1169
1169
|
</p>
|
1170
1170
|
</dd>
|
1171
|
+
<dt class="hdlist1">
|
1172
|
+
<code>${HOME}/.git/multi/superprojects.config</code>
|
1173
|
+
</dt>
|
1174
|
+
<dd>
|
1175
|
+
<p>
|
1176
|
+
definitions for so-called "superproject" multi repos
|
1177
|
+
</p>
|
1178
|
+
</dd>
|
1171
1179
|
</dl></div>
|
1172
1180
|
</div>
|
1173
1181
|
</div>
|
@@ -1201,7 +1209,7 @@ the <code>jq</code> command-line utility:
|
|
1201
1209
|
<div id="footer">
|
1202
1210
|
<div id="footer-text">
|
1203
1211
|
Last updated
|
1204
|
-
2018-11-
|
1212
|
+
2018-11-12 14:05:11 GMT
|
1205
1213
|
</div>
|
1206
1214
|
</div>
|
1207
1215
|
</body>
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: git-multi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Vandenberk
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-11-
|
11
|
+
date: 2018-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: octokit
|
@@ -97,9 +97,9 @@ files:
|
|
97
97
|
- lib/git/hub.rb
|
98
98
|
- lib/git/multi.rb
|
99
99
|
- lib/git/multi/commands.rb
|
100
|
+
- lib/git/multi/config.rb
|
100
101
|
- lib/git/multi/gemspec.rb
|
101
|
-
- lib/git/multi/
|
102
|
-
- lib/git/multi/utils.rb
|
102
|
+
- lib/git/multi/report.rb
|
103
103
|
- lib/git/multi/version.rb
|
104
104
|
- man/git-multi.1
|
105
105
|
- man/git-multi.erb
|
data/lib/git/multi/settings.rb
DELETED
@@ -1,99 +0,0 @@
|
|
1
|
-
module Git
|
2
|
-
module Multi
|
3
|
-
module Settings
|
4
|
-
|
5
|
-
TICK = ['2714'.hex].pack('U*').green.freeze
|
6
|
-
CROSS = ['2718'.hex].pack('U*').red.freeze
|
7
|
-
ARROW = ['2794'.hex].pack('U*').blue.freeze
|
8
|
-
|
9
|
-
module_function
|
10
|
-
|
11
|
-
def setting_status(messages, valid = false, optional = true)
|
12
|
-
fields = messages.compact.join(' - ')
|
13
|
-
icon = valid ? TICK : optional ? ARROW : CROSS
|
14
|
-
puts "#{icon} #{fields}"
|
15
|
-
end
|
16
|
-
|
17
|
-
def file_status(file, message = 'File')
|
18
|
-
setting_status(
|
19
|
-
[
|
20
|
-
message,
|
21
|
-
abbreviate(file),
|
22
|
-
File.file?(file) ? "#{File.size(file).commify} bytes" : nil,
|
23
|
-
],
|
24
|
-
file && !file.empty? && File.file?(file),
|
25
|
-
false
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
def directory_status(messages, directory)
|
30
|
-
setting_status(
|
31
|
-
messages,
|
32
|
-
directory && !directory.empty? && File.directory?(directory),
|
33
|
-
false
|
34
|
-
)
|
35
|
-
end
|
36
|
-
|
37
|
-
def workarea_status(message, workarea, owner)
|
38
|
-
directory_status(
|
39
|
-
[
|
40
|
-
message,
|
41
|
-
File.join(abbreviate(workarea, :workarea), owner),
|
42
|
-
],
|
43
|
-
File.join(workarea, owner)
|
44
|
-
)
|
45
|
-
|
46
|
-
github_count = Git::Multi.repositories_for(owner).count
|
47
|
-
cloned_count = Git::Multi.cloned_repositories_for(owner).count
|
48
|
-
missing_count = (github_count - cloned_count)
|
49
|
-
subdir_count = Dir.new(workarea).git_repos(owner).count
|
50
|
-
surplus_count = (subdir_count - cloned_count)
|
51
|
-
|
52
|
-
setting_status(["\tGitHub ", github_count])
|
53
|
-
setting_status(["\tcloned ", cloned_count, "(#{missing_count} missing)"])
|
54
|
-
Git::Multi.missing_repositories_for(owner).each do |missing|
|
55
|
-
setting_status(["\tmissing", missing.full_name], false, false)
|
56
|
-
end
|
57
|
-
setting_status(["\tsubdirs", subdir_count, "(#{surplus_count} surplus)"])
|
58
|
-
end
|
59
|
-
|
60
|
-
def user_status(user)
|
61
|
-
setting_status(['User', user], user && !user.empty?)
|
62
|
-
end
|
63
|
-
|
64
|
-
def organization_status(orgs)
|
65
|
-
orgs.each do |org|
|
66
|
-
setting_status(['Organization', org], org && !org.empty?, true)
|
67
|
-
setting_status(['Organization', 'member?'], Git::Hub.orgs.include?(org), !Git::Hub.connected?)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def token_status(token)
|
72
|
-
setting_status(['Token', symbolize(token), describe(token)], !token.nil? && !token.empty?)
|
73
|
-
setting_status(['Token', 'valid?'], !token.nil? && !token.empty? && Git::Hub.login, !Git::Hub.connected?)
|
74
|
-
setting_status(['Token', "owned by #{Git::Multi::USER}?"], Git::Hub.login == Git::Multi::USER, !Git::Hub.connected?)
|
75
|
-
end
|
76
|
-
|
77
|
-
def home_status(home)
|
78
|
-
directory_status(['${HOME}', home], home)
|
79
|
-
end
|
80
|
-
|
81
|
-
def main_workarea_status(workarea)
|
82
|
-
directory_status(['${WORKAREA}', abbreviate(workarea, :home)], workarea)
|
83
|
-
end
|
84
|
-
|
85
|
-
def user_workarea_status(users)
|
86
|
-
users.each do |user|
|
87
|
-
workarea_status("Workarea (user: #{user})", Git::Multi::WORKAREA, user)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def organization_workarea_status(orgs)
|
92
|
-
orgs.each do |org|
|
93
|
-
workarea_status("Workarea (org: #{org})", Git::Multi::WORKAREA, org)
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
data/lib/git/multi/utils.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
module Git
|
2
|
-
module Multi
|
3
|
-
|
4
|
-
module Settings
|
5
|
-
|
6
|
-
module_function
|
7
|
-
|
8
|
-
def describe(token)
|
9
|
-
if token.nil?
|
10
|
-
'(nil)'
|
11
|
-
elsif token.empty?
|
12
|
-
'(empty)'
|
13
|
-
else
|
14
|
-
"#{'*' * 36}#{token[36..-1]}"
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
def symbolize(token)
|
19
|
-
case token
|
20
|
-
when Git::Multi.env_var('OCTOKIT_ACCESS_TOKEN')
|
21
|
-
then '${OCTOKIT_ACCESS_TOKEN}'
|
22
|
-
when Git::Multi.git_option('github.token')
|
23
|
-
then 'github.token'
|
24
|
-
else '(unset)'
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def abbreviate(directory, root_dir = nil)
|
29
|
-
case root_dir
|
30
|
-
when :home
|
31
|
-
then directory.gsub(Git::Multi::HOME, '${HOME}')
|
32
|
-
when :workarea
|
33
|
-
then directory.gsub(Git::Multi::WORKAREA, '${WORKAREA}')
|
34
|
-
else abbreviate(abbreviate(directory, :workarea), :home)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
module_function
|
41
|
-
|
42
|
-
def git_option(name, default = nil)
|
43
|
-
value = `git config #{name}`.chomp.freeze
|
44
|
-
value.empty? && default ? default : value
|
45
|
-
end
|
46
|
-
|
47
|
-
def git_list(name, default = nil)
|
48
|
-
git_option(name, default).split(',').map(&:strip)
|
49
|
-
end
|
50
|
-
|
51
|
-
def env_var(name, default = nil)
|
52
|
-
value = ENV[name].freeze
|
53
|
-
(value.nil? || value.empty?) && default ? default : value
|
54
|
-
end
|
55
|
-
|
56
|
-
end
|
57
|
-
end
|