git-forks 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/git-forks.rb +189 -55
- metadata +1 -1
data/lib/git-forks.rb
CHANGED
@@ -11,7 +11,8 @@ require 'time'
|
|
11
11
|
|
12
12
|
class GitForks
|
13
13
|
|
14
|
-
CACHE_FILE
|
14
|
+
CACHE_FILE = '.git/forks_cache.json'
|
15
|
+
NO_UPDATE_ACTIONS = ['help', 'usage', 'update', 'config']
|
15
16
|
|
16
17
|
def initialize(args)
|
17
18
|
@command = args.shift
|
@@ -30,7 +31,7 @@ class GitForks
|
|
30
31
|
# If the cache file doesn't exist, make sure we run update
|
31
32
|
# before any other command. git-forks will otherwise crash
|
32
33
|
# with an exception.
|
33
|
-
update unless File.exists?(CACHE_FILE) || @command
|
34
|
+
update unless File.exists?(CACHE_FILE) || NO_UPDATE_ACTIONS.include?(@command)
|
34
35
|
|
35
36
|
self.send @command
|
36
37
|
elsif %w(-h --help).include?(@command)
|
@@ -62,6 +63,58 @@ class GitForks
|
|
62
63
|
# Commands
|
63
64
|
#-----------------------------------------------------------------------------
|
64
65
|
|
66
|
+
# list
|
67
|
+
# get
|
68
|
+
# add
|
69
|
+
# remove
|
70
|
+
#
|
71
|
+
def config
|
72
|
+
action = @args.shift
|
73
|
+
owner = @args.shift
|
74
|
+
|
75
|
+
if action
|
76
|
+
if owner || action == "list"
|
77
|
+
case action
|
78
|
+
when "list"
|
79
|
+
if (f = config_get_forks).size > 0
|
80
|
+
puts f
|
81
|
+
end
|
82
|
+
when "get"
|
83
|
+
if (v = config_get_fork(owner)).size > 0
|
84
|
+
puts v
|
85
|
+
end
|
86
|
+
when "add"
|
87
|
+
if config_get_fork(owner).size > 0
|
88
|
+
puts "#{owner} already exists."
|
89
|
+
else
|
90
|
+
config_add_fork(owner)
|
91
|
+
puts "Added #{owner}."
|
92
|
+
end
|
93
|
+
when "remove"
|
94
|
+
if config_get_fork(owner).empty?
|
95
|
+
puts "#{owner} not found."
|
96
|
+
else
|
97
|
+
# (Forces cache update.)
|
98
|
+
config_remove_fork(owner)
|
99
|
+
puts "Removed #{owner}."
|
100
|
+
end
|
101
|
+
else
|
102
|
+
puts "<action> '#{action}' unknown"
|
103
|
+
puts
|
104
|
+
usage
|
105
|
+
end
|
106
|
+
else
|
107
|
+
puts "<owner> argument missing"
|
108
|
+
puts
|
109
|
+
usage
|
110
|
+
end
|
111
|
+
else
|
112
|
+
puts "<action> argument missing"
|
113
|
+
puts
|
114
|
+
usage
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
65
118
|
# Get the latest GitHub data.
|
66
119
|
def update
|
67
120
|
puts 'Retrieving the latest GitHub data...'
|
@@ -92,66 +145,82 @@ class GitForks
|
|
92
145
|
def fetch
|
93
146
|
target_owners = @args
|
94
147
|
|
95
|
-
update if not @updated
|
148
|
+
update if not @updated # force cache update
|
149
|
+
|
150
|
+
cached_owners = []
|
96
151
|
get_cached_data('forks').each do |fork|
|
97
|
-
|
98
|
-
|
152
|
+
cached_owners << fork['owner']['login']
|
153
|
+
end
|
154
|
+
|
155
|
+
# fetch all configured forks by default
|
156
|
+
target_owners = cached_owners if target_owners.empty?
|
157
|
+
|
158
|
+
target_owners.each do |owner|
|
159
|
+
if cached_owners.include?(owner)
|
99
160
|
puts '-' * 80
|
100
161
|
puts "Fething Git data from fork '#{owner}/#{@repo}'"
|
101
|
-
|
102
|
-
|
162
|
+
git_fetch_fork(owner)
|
163
|
+
else
|
164
|
+
# TODO: add --force => add owner to config automatically
|
165
|
+
puts '-' * 80
|
166
|
+
puts "'#{owner}/#{@repo}' is not in your forks whitelist."
|
167
|
+
puts
|
168
|
+
puts "Run: $ git forks config add #{owner}"
|
169
|
+
puts "and then try again, if you really want to pull from this fork."
|
170
|
+
puts
|
171
|
+
print "This is your current forks whitelist: "
|
172
|
+
if (f = config_get_forks).size > 0
|
173
|
+
puts f.gsub("\n", ', ')
|
174
|
+
else
|
175
|
+
puts "<empty>"
|
176
|
+
end
|
177
|
+
exit 1
|
103
178
|
end
|
104
179
|
end
|
105
180
|
end
|
106
181
|
|
107
182
|
# List all forks.
|
108
183
|
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
# --------------------------------------------------------------------------------
|
112
|
-
# Forks of 'doubleotoo/foo/master'
|
113
|
-
#
|
114
|
-
# Owner Branches Updated
|
115
|
-
# ------ -------- -------
|
116
|
-
# justintoo 2 01-May-12
|
117
|
-
# rose-compiler 3 27-Apr-12
|
184
|
+
# TODO: add sorting by column
|
118
185
|
#
|
119
186
|
def list
|
120
187
|
forks = get_cached_data('forks')
|
121
188
|
forks.reverse! if @args.shift == '--reverse'
|
122
189
|
|
190
|
+
whitelist = config_get_forks.split("\n")
|
191
|
+
|
123
192
|
output = forks.collect do |f|
|
193
|
+
owner = f['owner']['login']
|
194
|
+
whitelist.delete(owner)
|
195
|
+
|
124
196
|
line = ""
|
125
|
-
line << l(
|
197
|
+
line << l(owner, 25)
|
126
198
|
line << l(f['branches'].size, 12)
|
127
199
|
line << strftime(clean(f['updated_at']))
|
128
200
|
end
|
129
201
|
|
130
202
|
if output.compact.empty?
|
131
|
-
puts "No forks of '#{@user}/#{@repo}'"
|
203
|
+
puts "No forks of '#{@user}/#{@repo}'."
|
132
204
|
else
|
133
205
|
puts '-' * 80
|
134
|
-
puts "Forks of '#{@user}/#{@repo}'"
|
206
|
+
puts "Forks of '#{@user}/#{@repo}':"
|
135
207
|
puts
|
136
208
|
puts l('Owner', 25) + l('Branches', 12) + 'Updated'
|
137
209
|
puts l('------', 25) + l('--------', 12) + '-------'
|
138
210
|
puts output.compact
|
211
|
+
if whitelist.size > 0
|
212
|
+
whitelist.each do |f|
|
213
|
+
puts l(f, 25) + l('*', 12) + '*'
|
214
|
+
end
|
215
|
+
|
216
|
+
puts
|
217
|
+
puts '* no cache data available; may require `update`'
|
218
|
+
end
|
139
219
|
puts '-' * 80
|
140
220
|
end
|
141
221
|
end
|
142
222
|
|
143
223
|
# Show details of one fork.
|
144
|
-
#
|
145
|
-
# Example::
|
146
|
-
#
|
147
|
-
# -------------------------------------------------------------------------------
|
148
|
-
# Owner : justintoo
|
149
|
-
# Created : 01-May-12
|
150
|
-
# Updated : 01-May-12
|
151
|
-
# Branches : 2
|
152
|
-
# 444a867d338cafc0c82d058b458b4fe268fa14d6 master
|
153
|
-
# 14178fe5b204c38650de8ddaf5d9fb80aa834e74 foo
|
154
|
-
#
|
155
224
|
def show
|
156
225
|
owner = @args.shift
|
157
226
|
option = @args.shift
|
@@ -210,25 +279,43 @@ class GitForks
|
|
210
279
|
end
|
211
280
|
|
212
281
|
def help
|
213
|
-
puts "No command: #{@command}"
|
214
|
-
puts "Try: browse, fetch, list, show, update"
|
215
|
-
puts "or call with '-h' for usage information"
|
282
|
+
puts "No command: #{@command}" if not @command == 'help'
|
283
|
+
puts "Try: browse, config, fetch, list, show, update;"
|
284
|
+
puts " or call with '-h' for usage information"
|
216
285
|
end
|
217
286
|
|
218
287
|
# Show a quick reference of available commands.
|
219
288
|
def usage
|
220
|
-
puts 'Usage: git forks <command>'
|
221
|
-
puts
|
289
|
+
puts 'Usage: git forks [-h] <command>'
|
290
|
+
puts
|
291
|
+
puts 'Manage your GitHub project\'s forks.'
|
222
292
|
puts
|
223
293
|
puts 'Available commands:'
|
224
294
|
puts ' browse <owner>[:<ref>] Show fork in web browser.'
|
225
295
|
puts ' <ref> denotes a Git Tree or a Git Commit.'
|
226
|
-
puts '
|
296
|
+
puts ' config <action> [owner] Configure which forks you are interested in (all by default).'
|
297
|
+
puts
|
298
|
+
puts ' Available actions: '
|
299
|
+
puts ' list List all forks.'
|
300
|
+
puts ' get <owner> Check for <owner>.'
|
301
|
+
puts ' add <owner> Add <owner>.'
|
302
|
+
puts ' remove <owner> Remove <owner>. (Forces cache update.)'
|
303
|
+
puts
|
304
|
+
puts ' The associated git-ref data is also removed.'
|
305
|
+
puts
|
306
|
+
puts ' You may want to run `git gc --prune=now` to'
|
307
|
+
puts ' remove stale objects that you fetched from'
|
308
|
+
puts ' your forks. (Also, see git-reflog.)'
|
309
|
+
puts
|
310
|
+
puts ' You can run `git fsck` to list dangling objects.'
|
311
|
+
puts
|
312
|
+
puts ' (git-gc does have various default expiry times.)'
|
313
|
+
puts ' fetch [<owners>] git-fetch fork data from GitHub. (Forces cache update.)'
|
227
314
|
puts ' <owners> is a space separate list.'
|
228
|
-
puts ' (Forces cache update.)'
|
229
315
|
puts ' list [--reverse] List all forks.'
|
230
316
|
puts ' show <owner> Show details for a single fork.'
|
231
317
|
puts ' update Retrieve fork info from GitHub API v3.'
|
318
|
+
puts ' usage Show this usage information.'
|
232
319
|
end
|
233
320
|
|
234
321
|
#-----------------------------------------------------------------------------
|
@@ -266,30 +353,16 @@ class GitForks
|
|
266
353
|
#-----------------------------------------------------------------------------
|
267
354
|
|
268
355
|
def fetch_fork_info
|
269
|
-
|
356
|
+
targets = config_get_forks # optional fork targets
|
357
|
+
forks = Octokit.forks("#{@user}/#{@repo}").select {|f|
|
358
|
+
targets.empty? or targets.include?(f.owner.login)
|
359
|
+
}
|
270
360
|
end
|
271
361
|
|
272
362
|
def fetch_fork_branches(fork_user)
|
273
363
|
branches = Octokit.branches("#{fork_user}/#{@repo}")
|
274
364
|
end
|
275
365
|
|
276
|
-
#-----------------------------------------------------------------------------
|
277
|
-
# Git
|
278
|
-
#-----------------------------------------------------------------------------
|
279
|
-
|
280
|
-
def git(command)
|
281
|
-
`git #{command}`.chomp
|
282
|
-
end
|
283
|
-
|
284
|
-
def github_endpoint
|
285
|
-
host = git("config --get-all github.host")
|
286
|
-
if host.size > 0
|
287
|
-
host
|
288
|
-
else
|
289
|
-
'https://github.com'
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
366
|
#-----------------------------------------------------------------------------
|
294
367
|
# Display Helper Functions
|
295
368
|
#-----------------------------------------------------------------------------
|
@@ -320,6 +393,10 @@ class GitForks
|
|
320
393
|
end
|
321
394
|
end
|
322
395
|
|
396
|
+
#-----------------------------------------------------------------------------
|
397
|
+
# Git
|
398
|
+
#-----------------------------------------------------------------------------
|
399
|
+
|
323
400
|
#def github_login
|
324
401
|
# git("config --get-all github.user")
|
325
402
|
#end
|
@@ -362,4 +439,61 @@ class GitForks
|
|
362
439
|
return nil, nil
|
363
440
|
end
|
364
441
|
|
442
|
+
def git(command)
|
443
|
+
`git #{command}`.chomp
|
444
|
+
end
|
445
|
+
|
446
|
+
def github_endpoint
|
447
|
+
host = git("config --get-all github.host")
|
448
|
+
if host.size > 0
|
449
|
+
host
|
450
|
+
else
|
451
|
+
'https://github.com'
|
452
|
+
end
|
453
|
+
end
|
454
|
+
|
455
|
+
def config_get_forks
|
456
|
+
git("config --get-all github.forks.owner")
|
457
|
+
end
|
458
|
+
|
459
|
+
def config_get_fork(owner)
|
460
|
+
git("config --get-all github.forks.owner \"^#{owner}$\"")
|
461
|
+
end
|
462
|
+
|
463
|
+
def config_add_fork(owner)
|
464
|
+
git("config --add github.forks.owner #{owner}")
|
465
|
+
end
|
466
|
+
|
467
|
+
# (Forces cache update.)
|
468
|
+
def config_remove_fork(owner)
|
469
|
+
git("config --unset github.forks.owner \"^#{owner}$\"")
|
470
|
+
git_remove_fork(owner)
|
471
|
+
update # TODO: optimize by only updating if fork existed
|
472
|
+
end
|
473
|
+
|
474
|
+
# Remove a fork's git-refs.
|
475
|
+
#
|
476
|
+
# Directory: refs/forks/rose-compiler/ <-- notice the trailing slash
|
477
|
+
# Single: refs/forks/rose-compiler/master
|
478
|
+
def git_remove_fork(owner)
|
479
|
+
refdir = "refs/forks/#{owner}"
|
480
|
+
gitdir = ".git/#{refdir}"
|
481
|
+
|
482
|
+
if Dir.exists?(gitdir)
|
483
|
+
Dir.foreach(gitdir) do |ref|
|
484
|
+
next if ref == '.' or ref == '..'
|
485
|
+
# delete each individual ref
|
486
|
+
git("update-ref -d #{refdir}/#{ref}")
|
487
|
+
end
|
488
|
+
|
489
|
+
# delete the ref directory
|
490
|
+
git("update-ref -d #{refdir}")
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
def git_fetch_fork(owner)
|
495
|
+
git("fetch --prune " +
|
496
|
+
"#{github_endpoint}/#{owner}/#{@repo}.git " +
|
497
|
+
"+refs/heads/*:refs/forks/#{owner}/*")
|
498
|
+
end
|
365
499
|
end # GitForks
|