gitoe 0.1.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 +7 -0
- data/.gitignore +18 -0
- data/.gitmodules +3 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +91 -0
- data/Guardfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +35 -0
- data/Rules +47 -0
- data/bin/gitoe +36 -0
- data/content/gitoe-draw.coffee +342 -0
- data/content/gitoe-repo.coffee +546 -0
- data/content/gitoe.coffee +182 -0
- data/content/index.haml +71 -0
- data/content/jquery/jquery-1.9.1.min.js +5 -0
- data/content/jquery/jquery.scrollTo.min.js +7 -0
- data/content/raphael-min.js +10 -0
- data/content/reset.sass +46 -0
- data/content/style.sass +109 -0
- data/gitoe.gemspec +34 -0
- data/lib/gitoe.rb +16 -0
- data/lib/gitoe/httpserver/public/gitoe-draw.js +399 -0
- data/lib/gitoe/httpserver/public/gitoe-repo.js +618 -0
- data/lib/gitoe/httpserver/public/gitoe.js +249 -0
- data/lib/gitoe/httpserver/public/index.html +49 -0
- data/lib/gitoe/httpserver/public/jquery/jquery-1.9.1.min.js +5 -0
- data/lib/gitoe/httpserver/public/jquery/jquery.scrollTo.min.js +7 -0
- data/lib/gitoe/httpserver/public/raphael-min.js +10 -0
- data/lib/gitoe/httpserver/public/reset.css +45 -0
- data/lib/gitoe/httpserver/public/style.css +106 -0
- data/lib/gitoe/httpserver/repos.rb +71 -0
- data/lib/gitoe/httpserver/static.rb +17 -0
- data/lib/gitoe/repo/repo.rb +174 -0
- data/lib/gitoe/repo/rugged.rb +121 -0
- data/lib/gitoe/version.rb +3 -0
- data/nanoc.yaml +77 -0
- data/test/test.rb +9 -0
- data/todo.markdown +16 -0
- data/vendor/jquery-1.9.1.min.js +5 -0
- data/vendor/raphael-min.js +10 -0
- metadata +239 -0
@@ -0,0 +1,546 @@
|
|
1
|
+
$ = jQuery or throw "demand jQuery"
|
2
|
+
|
3
|
+
url_root = "/repo"
|
4
|
+
|
5
|
+
exec_callback = (context,fun,args)->
|
6
|
+
fun.apply(context, args)
|
7
|
+
|
8
|
+
clone = (obj)->
|
9
|
+
$.extend {}, obj
|
10
|
+
|
11
|
+
local = '##??!'
|
12
|
+
|
13
|
+
uniq = ( old_array, ignore_list=['0000000000000000000000000000000000000000'] )->
|
14
|
+
# leave only first occurances
|
15
|
+
|
16
|
+
ignore = {}
|
17
|
+
for i in ignore_list
|
18
|
+
ignore[ i ] = true
|
19
|
+
|
20
|
+
new_array = []
|
21
|
+
for elem in old_array
|
22
|
+
if not ignore[elem]
|
23
|
+
ignore[elem] = true
|
24
|
+
new_array.push elem
|
25
|
+
new_array
|
26
|
+
|
27
|
+
strcmp = (str1, str2, pos = 0)->
|
28
|
+
c1 = str1.charAt( pos )
|
29
|
+
c2 = str2.charAt( pos )
|
30
|
+
if c1 < c2
|
31
|
+
return 1
|
32
|
+
else if c1 > c2
|
33
|
+
return -1
|
34
|
+
else if c1 == '' # which means c2 == ''
|
35
|
+
return 0
|
36
|
+
else
|
37
|
+
return strcmp(str1, str2, pos+1)
|
38
|
+
|
39
|
+
class OrderedSet
|
40
|
+
# a FIFO queue while guarantees uniqueness
|
41
|
+
constructor: ()->
|
42
|
+
@elems = []
|
43
|
+
@hash = {}
|
44
|
+
push: (new_elem)->
|
45
|
+
if not @hash[new_elem]
|
46
|
+
@hash[new_elem] = true
|
47
|
+
@elems.push new_elem
|
48
|
+
true
|
49
|
+
else
|
50
|
+
false
|
51
|
+
length: ()->
|
52
|
+
@elems.length
|
53
|
+
shift: ()->
|
54
|
+
throw "empty" unless @elems.length > 0
|
55
|
+
ret = @elems.shift()
|
56
|
+
delete @hash[ret]
|
57
|
+
ret
|
58
|
+
|
59
|
+
class DAGtopo
|
60
|
+
# TODO
|
61
|
+
# modify to a persistent object, for reverse-order toposort
|
62
|
+
# respond to
|
63
|
+
# #depth()
|
64
|
+
# #add_edge(u,v)
|
65
|
+
# callback on
|
66
|
+
# yield: (commit,layer)
|
67
|
+
constructor: ()->
|
68
|
+
@edges = {} # { u: [v] } for edges < u → v >
|
69
|
+
|
70
|
+
add_edge: (from,to)-> # nil
|
71
|
+
@edges[from] ?= []
|
72
|
+
@edges[to] ?= []
|
73
|
+
@edges[from].push to
|
74
|
+
|
75
|
+
sort: ()-> # [nodes] , in topological order
|
76
|
+
in_degree = {}
|
77
|
+
for from, to_s of @edges
|
78
|
+
in_degree[from] ?= 0
|
79
|
+
for to in to_s
|
80
|
+
in_degree[to] ?= 0
|
81
|
+
in_degree[to]++
|
82
|
+
sorted = []
|
83
|
+
nodes_whose_in_degree_is_0 =
|
84
|
+
Object.keys(in_degree).filter (node)->
|
85
|
+
in_degree[node] is 0
|
86
|
+
while nodes_whose_in_degree_is_0.length > 0
|
87
|
+
node = nodes_whose_in_degree_is_0.shift()
|
88
|
+
delete in_degree[node] # not really necessary, keep it clean
|
89
|
+
sorted.push node
|
90
|
+
for to in @edges[node]
|
91
|
+
if --in_degree[to] == 0
|
92
|
+
nodes_whose_in_degree_is_0.push to
|
93
|
+
return sorted
|
94
|
+
|
95
|
+
class GitoeChange
|
96
|
+
# changes in ONE repo
|
97
|
+
@parse: ( repos )-># [ changes ]
|
98
|
+
# repo :: { ref: logs }
|
99
|
+
|
100
|
+
# collect changes
|
101
|
+
changes = []
|
102
|
+
for repo_name, repo_content of repos
|
103
|
+
for ref_name, ref_content of repo_content
|
104
|
+
for change in ref_content.log
|
105
|
+
change['repo_name'] = repo_name
|
106
|
+
change["ref_name"] = ref_name
|
107
|
+
changes.push change
|
108
|
+
|
109
|
+
# sort by time and ref_name
|
110
|
+
changes.sort (a,b)->
|
111
|
+
( a.committer.time - b.committer.time ) \
|
112
|
+
or strcmp(a.repo_name, b.repo_name) \
|
113
|
+
or -((a.ref_name == "HEAD") - (b.ref_name == "HEAD")) \
|
114
|
+
or strcmp(a.ref_name, b.ref_name)
|
115
|
+
|
116
|
+
grouped_changes = @group changes
|
117
|
+
console.log changes, grouped_changes
|
118
|
+
|
119
|
+
grouped_changes.map (group)->
|
120
|
+
new GitoeChange(group)
|
121
|
+
|
122
|
+
@group : (changes)-> # [ [group_of_changes] ]
|
123
|
+
# TODO group changes with some maintainable grammer rules
|
124
|
+
groups = []
|
125
|
+
begin = 0
|
126
|
+
for change, end in changes
|
127
|
+
next = changes[ end + 1 ]
|
128
|
+
if (change.ref_name isnt "HEAD") \ # change in named branch
|
129
|
+
or ( /^rebase: aborting/.test change.message) \ # rebase --abort
|
130
|
+
or (end == changes.length - 1 ) \ # last change in all changes
|
131
|
+
or (next.repo_name != change.repo_name)\ # last change in consecutive changes of the same repo
|
132
|
+
or ( /^checkout:/.test(change.message) and not /^(rebase|cherry-pick)/.test(next.message) ) # last checkout before rebase
|
133
|
+
groups.push changes[ begin .. end ]
|
134
|
+
begin = end+1
|
135
|
+
groups
|
136
|
+
|
137
|
+
constructor: ( changes )->
|
138
|
+
@main = changes[ changes.length - 1 ]
|
139
|
+
if changes.length > 1
|
140
|
+
@rest = changes[ 0 .. (changes.length - 2) ]
|
141
|
+
else
|
142
|
+
@rest = []
|
143
|
+
if @main.repo_name is local
|
144
|
+
@is_local = true
|
145
|
+
else
|
146
|
+
@is_local = false
|
147
|
+
|
148
|
+
to_html: ()-># [ changes_as_li ]
|
149
|
+
rules = GitoeChange.message_rules
|
150
|
+
html = GitoeChange.html
|
151
|
+
for pattern, regex of rules.patterns
|
152
|
+
if matched = @main.message.match(regex)
|
153
|
+
return rules.actions[pattern].apply(html,[matched, @main, @rest]).addClass("reflog")
|
154
|
+
console.log "not recognized change : ", @main, @rest
|
155
|
+
$('<li>').text("???").addClass("unknown")
|
156
|
+
|
157
|
+
on_click: ->
|
158
|
+
# closure
|
159
|
+
refs = {}
|
160
|
+
ref_fullname = GitoeChange.html.ref_fullname
|
161
|
+
for change in @rest
|
162
|
+
fullname = ref_fullname change
|
163
|
+
refs[ fullname ] ?= []
|
164
|
+
refs[ fullname ].push change.oid_old
|
165
|
+
refs[ fullname ].push change.oid_new
|
166
|
+
fullname = ref_fullname @main
|
167
|
+
refs[ fullname ] ?= []
|
168
|
+
refs[ fullname ].push @main.oid_old
|
169
|
+
refs[ fullname ].push @main.oid_new
|
170
|
+
|
171
|
+
for fullname, sha1_s of refs
|
172
|
+
refs[fullname] = uniq(sha1_s)
|
173
|
+
|
174
|
+
-># in GitoeCanvas context
|
175
|
+
@set_refs refs
|
176
|
+
|
177
|
+
@html = {
|
178
|
+
# a singleton obj to eval html DSL with
|
179
|
+
span: (text,classes)->
|
180
|
+
$("<span>").text(text).addClass(classes)
|
181
|
+
li: (content, classes)->
|
182
|
+
$("<li>").append(content).addClass(classes)
|
183
|
+
ref: (text)->
|
184
|
+
@span text, 'ref_name'
|
185
|
+
ref_fullname: ( change )-> # span "repo/ref"
|
186
|
+
if change.repo_name is local
|
187
|
+
change.ref_name
|
188
|
+
else
|
189
|
+
"#{change.repo_name}/#{change.ref_name}"
|
190
|
+
git_command: (text)->
|
191
|
+
@span text, "git_command"
|
192
|
+
ref_realname: (ref_name)-> # "repo/ref"
|
193
|
+
splited = ref_name.split "/"
|
194
|
+
if splited[0] == "HEAD"
|
195
|
+
"HEAD"
|
196
|
+
else if splited[0] == "refs"
|
197
|
+
switch splited[1]
|
198
|
+
when "heads" # refs/heads/<branch>
|
199
|
+
splited[2]
|
200
|
+
when "remotes" # refs/remotes/<repo>/<branch>
|
201
|
+
"#{ splited[2] }/#{ splited[3] }"
|
202
|
+
when "tags" # refs/tags/<tag>
|
203
|
+
splited[2]
|
204
|
+
else
|
205
|
+
console.log "not recognized", ref_name
|
206
|
+
"???"
|
207
|
+
else
|
208
|
+
console.log "not recognized", ref_name
|
209
|
+
"???"
|
210
|
+
sha1_commit: (sha1)->
|
211
|
+
@span sha1, "sha1_commit"
|
212
|
+
br: ->
|
213
|
+
$('<br>')
|
214
|
+
}
|
215
|
+
|
216
|
+
@message_rules = {
|
217
|
+
patterns: {
|
218
|
+
clone: /^clone: from (.*)/
|
219
|
+
branch: /^branch: Created from (.*)/
|
220
|
+
commit: /^commit: /
|
221
|
+
commit_amend: /^commit \(amend\): /
|
222
|
+
merge_commit: /^commit \(merge\): Merge branch '?([^ ]+)'? into '?([^ ]+)'?$/
|
223
|
+
merge_ff: /^merge ([^:]*):/
|
224
|
+
reset: /^reset: moving to (.*)/
|
225
|
+
push : /^update by push/
|
226
|
+
pull : /^pull: /
|
227
|
+
fetch: /^fetch/
|
228
|
+
checkout: /^checkout: moving from ([^ ]+) to ([^ ]+)/
|
229
|
+
rename_remote: /^remote: renamed ([^ ]+) to ([^ ]+)/
|
230
|
+
rebase_finish: /^rebase (-[^ ]+)? \(finish\): returning to (.*)/
|
231
|
+
rebase_finish2:/^rebase (-[^ ]+)? \(finish\): ([^ ]+) onto/
|
232
|
+
rebase_finish3:/^rebase (-[^ ]+ )?finished: ([^ ]+) onto/
|
233
|
+
rebase_abort: /^rebase: aborting/
|
234
|
+
}
|
235
|
+
actions : {
|
236
|
+
clone: (matched,change)->
|
237
|
+
@li [
|
238
|
+
@git_command "git clone"
|
239
|
+
@span ": create "
|
240
|
+
@ref (@ref_fullname change)
|
241
|
+
@span " at "
|
242
|
+
@sha1_commit change.oid_new
|
243
|
+
]
|
244
|
+
branch: (matched, change)->
|
245
|
+
# TODO show position better
|
246
|
+
@li [
|
247
|
+
@git_command "git branch"
|
248
|
+
@span ": branch out "
|
249
|
+
@ref (@ref_fullname change)
|
250
|
+
@span " at "
|
251
|
+
@sha1_commit change.oid_new
|
252
|
+
if /^refs/.test matched[1]
|
253
|
+
@span " (was "
|
254
|
+
if /^refs/.test matched[1]
|
255
|
+
@ref @ref_realname(matched[1])
|
256
|
+
if /^refs/.test matched[1]
|
257
|
+
@span " )"
|
258
|
+
]
|
259
|
+
commit: (matched, change)->
|
260
|
+
@li [
|
261
|
+
@git_command "git commit"
|
262
|
+
@span ": move "
|
263
|
+
@ref (@ref_fullname change)
|
264
|
+
@span " from "
|
265
|
+
@sha1_commit change.oid_old
|
266
|
+
@span " to "
|
267
|
+
@sha1_commit change.oid_new
|
268
|
+
]
|
269
|
+
merge_commit: (matched, change)->
|
270
|
+
@li [
|
271
|
+
@git_command "git merge"
|
272
|
+
@span ": move "
|
273
|
+
@span matched[2], "ref_name"
|
274
|
+
@span ' to '
|
275
|
+
@sha1_commit change.oid_new
|
276
|
+
@span ' by merging '
|
277
|
+
@span matched[1], "ref_name"
|
278
|
+
]
|
279
|
+
commit_amend: (matched, change)->
|
280
|
+
@li [
|
281
|
+
@git_command "git commit --amend"
|
282
|
+
@span ": move "
|
283
|
+
@ref (@ref_fullname change)
|
284
|
+
@span " from "
|
285
|
+
@sha1_commit change.oid_old
|
286
|
+
@span " to "
|
287
|
+
@sha1_commit change.oid_new
|
288
|
+
]
|
289
|
+
merge_ff: (matched, change)->
|
290
|
+
@li [
|
291
|
+
@git_command "git merge"
|
292
|
+
@span ": move "
|
293
|
+
@ref (@ref_fullname change)
|
294
|
+
@span ' to '
|
295
|
+
@sha1_commit change.oid_new
|
296
|
+
@span ' by merging '
|
297
|
+
@span matched[1], "ref_name"
|
298
|
+
]
|
299
|
+
reset: (matched, change)->
|
300
|
+
@li [
|
301
|
+
@git_command "git reset"
|
302
|
+
@span ": point "
|
303
|
+
@ref (@ref_fullname change)
|
304
|
+
@span " to "
|
305
|
+
@sha1_commit change.oid_new
|
306
|
+
@span " ( was "
|
307
|
+
@sha1_commit change.oid_old
|
308
|
+
@span " )"
|
309
|
+
]
|
310
|
+
push: (matched, change)->
|
311
|
+
@li [
|
312
|
+
@git_command "git push"
|
313
|
+
@span ": update "
|
314
|
+
@ref (@ref_fullname change)
|
315
|
+
@span " to "
|
316
|
+
@sha1_commit change.oid_new
|
317
|
+
if change.oid_old isnt "0000000000000000000000000000000000000000"
|
318
|
+
@span " ( was "
|
319
|
+
if change.oid_old isnt "0000000000000000000000000000000000000000"
|
320
|
+
@sha1_commit change.oid_old
|
321
|
+
if change.oid_old isnt "0000000000000000000000000000000000000000"
|
322
|
+
@span " )"
|
323
|
+
]
|
324
|
+
fetch: (matched, change)->
|
325
|
+
@li [
|
326
|
+
@git_command "git fetch"
|
327
|
+
@span ": update "
|
328
|
+
@ref (@ref_fullname change)
|
329
|
+
@span " to "
|
330
|
+
@sha1_commit change.oid_new
|
331
|
+
if change.oid_old isnt "0000000000000000000000000000000000000000"
|
332
|
+
@span " ( was "
|
333
|
+
if change.oid_old isnt "0000000000000000000000000000000000000000"
|
334
|
+
@sha1_commit change.oid_old
|
335
|
+
if change.oid_old isnt "0000000000000000000000000000000000000000"
|
336
|
+
@span " )"
|
337
|
+
]
|
338
|
+
pull: (matched, change)->
|
339
|
+
@li [
|
340
|
+
@git_command "git pull"
|
341
|
+
@span ": update "
|
342
|
+
@ref (@ref_fullname change)
|
343
|
+
@span " from "
|
344
|
+
@sha1_commit change.oid_old
|
345
|
+
@span " to "
|
346
|
+
@sha1_commit change.oid_new
|
347
|
+
]
|
348
|
+
checkout: (matched, change, rest)->
|
349
|
+
# TODO handle remaining "checkout SHA1" message of removed branch
|
350
|
+
@li [
|
351
|
+
@git_command "git checkout"
|
352
|
+
@span ": checkout "
|
353
|
+
@ref matched[2]
|
354
|
+
@span " at "
|
355
|
+
@sha1_commit change.oid_new
|
356
|
+
]
|
357
|
+
rename_remote: (matched, change)->
|
358
|
+
@li [
|
359
|
+
@git_command "git remote rename"
|
360
|
+
@span ": rename "
|
361
|
+
@ref @ref_realname(matched[1])
|
362
|
+
@span " to "
|
363
|
+
@ref @ref_realname(matched[2])
|
364
|
+
]
|
365
|
+
rebase_finish: (matched, change)->
|
366
|
+
@li [
|
367
|
+
if matched[1]
|
368
|
+
@git_command "git rebase #{matched[1]}"
|
369
|
+
else
|
370
|
+
@git_command "git rebase"
|
371
|
+
@span ": rebase "
|
372
|
+
@ref @ref_realname(matched[2])
|
373
|
+
@span " to "
|
374
|
+
@sha1_commit change.oid_new
|
375
|
+
]
|
376
|
+
rebase_finish2: (matched, change)->
|
377
|
+
@li [
|
378
|
+
if matched[1]
|
379
|
+
@git_command "git rebase #{matched[1]}"
|
380
|
+
else
|
381
|
+
@git_command "git rebase"
|
382
|
+
@span ": rebase "
|
383
|
+
@ref (@ref_fullname change)
|
384
|
+
@span " to "
|
385
|
+
@sha1_commit change.oid_new
|
386
|
+
]
|
387
|
+
rebase_finish3: (matched, change)->
|
388
|
+
@li [
|
389
|
+
if matched[1]
|
390
|
+
@git_command "git rebase #{matched[1]}"
|
391
|
+
else
|
392
|
+
@git_command "git rebase"
|
393
|
+
@span ": rebase "
|
394
|
+
@ref (@ref_fullname change)
|
395
|
+
@span " to "
|
396
|
+
@sha1_commit change.oid_new
|
397
|
+
]
|
398
|
+
rebase_abort: (matched, change, rest)->
|
399
|
+
if rest.length > 0
|
400
|
+
if matched_head = rest[0].message.match /^checkout: moving from ([^ ]+)/
|
401
|
+
real_ref = matched_head[1]
|
402
|
+
@li [
|
403
|
+
@git_command "git rebase --abort"
|
404
|
+
@span ": didn't rebase "
|
405
|
+
if real_ref
|
406
|
+
@ref real_ref
|
407
|
+
]
|
408
|
+
}
|
409
|
+
}
|
410
|
+
|
411
|
+
class GitoeHistorian
|
412
|
+
constructor: ()->
|
413
|
+
@cb = {} # { name: fun }
|
414
|
+
|
415
|
+
set_cb: (new_cb)->
|
416
|
+
# cb:
|
417
|
+
# update_reflog : ( changes )
|
418
|
+
# update_num_tags : ( num_tags )
|
419
|
+
for name, fun of new_cb
|
420
|
+
@cb[name] = fun
|
421
|
+
|
422
|
+
parse: ( refs )-> # [ changes of all repos ]
|
423
|
+
classified = @classify( clone refs )
|
424
|
+
console.log classified
|
425
|
+
@cb.update_num_tags? Object.keys( classified.tags ).length
|
426
|
+
|
427
|
+
changes = GitoeChange.parse( classified.repos )
|
428
|
+
@cb.update_reflog?( changes )
|
429
|
+
|
430
|
+
classify: (refs)-> # { repos: {}, tags: {} }
|
431
|
+
repos = {}
|
432
|
+
tags = {}
|
433
|
+
for ref_name, ref_content of refs
|
434
|
+
splited = ref_name.split "/"
|
435
|
+
if splited[0] == "HEAD" and splited.length == 1
|
436
|
+
repos[ local ] ?= {}
|
437
|
+
repos[ local ]["HEAD"] = ref_content
|
438
|
+
else if splited[0] == "refs"
|
439
|
+
switch splited[1]
|
440
|
+
when "heads" # refs/heads/<branch>
|
441
|
+
repos[ local ] ?= {}
|
442
|
+
repos[ local ][ splited[2] ] = ref_content
|
443
|
+
when "remotes" # refs/remotes/<repo>/<branch>
|
444
|
+
repos[ splited[2] ] ?= {}
|
445
|
+
repos[ splited[2] ][ splited[3] ] = ref_content
|
446
|
+
when "tags" # refs/tags/<tag>
|
447
|
+
tags[ splited[2] ] = ref_content
|
448
|
+
# do nothing
|
449
|
+
else
|
450
|
+
console.log "not recognized", ref_name
|
451
|
+
else
|
452
|
+
console.log "not recognized", ref_name
|
453
|
+
{
|
454
|
+
repos: repos
|
455
|
+
tags: tags
|
456
|
+
}
|
457
|
+
|
458
|
+
class GitoeRepo
|
459
|
+
# TODO
|
460
|
+
# queue commits with OrderedSet
|
461
|
+
# reverse-toposort with DAGtopo
|
462
|
+
constructor: ()->
|
463
|
+
@commits_to_fetch = {} # { sha1: true }
|
464
|
+
@commits_fetched = {} # { sha1: commit }
|
465
|
+
@cb = {} # { name: fun }
|
466
|
+
@commits_ignored = { "0000000000000000000000000000000000000000" : true }
|
467
|
+
|
468
|
+
set_cb: (new_cb)->
|
469
|
+
# cb: triggered unconditionally
|
470
|
+
# ajax_error : ( jqXHR )->
|
471
|
+
# fetched_commit: ( to_fetch, fetched )->
|
472
|
+
# yield_reflogs : ( refs )->
|
473
|
+
# yield_commit : ( content )->
|
474
|
+
for name, fun of new_cb
|
475
|
+
@cb[name] = fun
|
476
|
+
|
477
|
+
open: (path,cb = {})=>
|
478
|
+
# cb:
|
479
|
+
# success: ()->
|
480
|
+
# fail : ()->
|
481
|
+
$.post("#{url_root}/new",{path: path})
|
482
|
+
.fail(@ajax_error, cb.fail)
|
483
|
+
.done(@ajax_open_success, cb.success)
|
484
|
+
|
485
|
+
fetch_commits: (cb = {})=>
|
486
|
+
# cb:
|
487
|
+
# success: ()->
|
488
|
+
# fail : ()->
|
489
|
+
throw "not opened" unless @path
|
490
|
+
to_query = Object.keys(@commits_to_fetch)[0..9]
|
491
|
+
# TODO find a more efficient formula
|
492
|
+
param = { limit: 1000 }
|
493
|
+
$.get("#{@path}/commits/#{to_query.join()}", param )
|
494
|
+
.fail(@ajax_error, cb.fail)
|
495
|
+
.done(@ajax_fetch_commits_success, cb.success)
|
496
|
+
|
497
|
+
fetch_status: (cb = {})->
|
498
|
+
# cb:
|
499
|
+
# success: ()->
|
500
|
+
# fail : ()->
|
501
|
+
$.get("#{@path}/")
|
502
|
+
.fail(@ajax_error, cb.fail)
|
503
|
+
.done(@ajax_fetch_status_success, cb.success)
|
504
|
+
|
505
|
+
fetch_alldone: ()->
|
506
|
+
sorter = new DAGtopo
|
507
|
+
for child,content of @commits_fetched
|
508
|
+
for parent in content.parents
|
509
|
+
sorter.add_edge( parent, child )
|
510
|
+
sorted_commits = sorter.sort()
|
511
|
+
for sha1 in sorted_commits
|
512
|
+
@cb.yield_commit? @commits_fetched[sha1]
|
513
|
+
|
514
|
+
ajax_open_success: (json)=>
|
515
|
+
throw "already opened" if @path
|
516
|
+
@path = "#{url_root}/#{json.id}"
|
517
|
+
|
518
|
+
ajax_fetch_commits_success: (json)=>
|
519
|
+
for sha1, content of json
|
520
|
+
delete @commits_to_fetch[ sha1 ]
|
521
|
+
@commits_fetched[ sha1 ] ||= content
|
522
|
+
for sha1_parent in content.parents
|
523
|
+
if not (@commits_fetched[ sha1 ] or @commits_ignored[ sha1 ])
|
524
|
+
@commits_to_fetch[ sha1_parent ] = true
|
525
|
+
to_fetch = Object.keys(@commits_to_fetch).length
|
526
|
+
fetched = Object.keys(@commits_fetched ).length
|
527
|
+
@cb.fetched_commit?(to_fetch, fetched)
|
528
|
+
|
529
|
+
ajax_fetch_status_success: (response)=>
|
530
|
+
for ref_name, ref of response.refs
|
531
|
+
# dig commits with log
|
532
|
+
# TODO also dig from annotated tags
|
533
|
+
for change in ref.log
|
534
|
+
for field in ['oid_new', 'oid_old']
|
535
|
+
sha1 = change[ field ]
|
536
|
+
if not (@commits_fetched[ sha1 ] or @commits_ignored[ sha1 ])
|
537
|
+
@commits_to_fetch[ sha1 ] = true
|
538
|
+
@cb.fetch_status? response
|
539
|
+
|
540
|
+
ajax_error: (jqXHR)=>
|
541
|
+
@cb.ajax_error? jqXHR
|
542
|
+
|
543
|
+
@exports ?= { gitoe: {} }
|
544
|
+
exports.gitoe.strcmp = strcmp
|
545
|
+
exports.gitoe.GitoeRepo = GitoeRepo
|
546
|
+
exports.gitoe.GitoeHistorian = GitoeHistorian
|