git-object-browser 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. data/.gitignore +17 -0
  2. data/.rspec +2 -0
  3. data/Gemfile +13 -0
  4. data/Guardfile +11 -0
  5. data/LICENSE +22 -0
  6. data/README.md +18 -0
  7. data/Rakefile +2 -0
  8. data/bin/git-object-browser +5 -0
  9. data/git-object-browser.gemspec +18 -0
  10. data/htdocs/css/angular-ui.min.css +1 -0
  11. data/htdocs/css/bootstrap-responsive.css +1058 -0
  12. data/htdocs/css/bootstrap-responsive.min.css +9 -0
  13. data/htdocs/css/bootstrap.css +5389 -0
  14. data/htdocs/css/bootstrap.min.css +699 -0
  15. data/htdocs/css/font-awesome-ie7.css +645 -0
  16. data/htdocs/css/font-awesome.css +303 -0
  17. data/htdocs/css/main.css +22 -0
  18. data/htdocs/font/fontawesome-webfont.eot +0 -0
  19. data/htdocs/font/fontawesome-webfont.svg +255 -0
  20. data/htdocs/font/fontawesome-webfont.ttf +0 -0
  21. data/htdocs/font/fontawesome-webfont.woff +0 -0
  22. data/htdocs/img/glyphicons-halflings-white.png +0 -0
  23. data/htdocs/img/glyphicons-halflings.png +0 -0
  24. data/htdocs/index.html +114 -0
  25. data/htdocs/js/main.js +286 -0
  26. data/htdocs/js/vendor/angular-bootstrap-prettify.min.js +41 -0
  27. data/htdocs/js/vendor/angular-bootstrap.min.js +9 -0
  28. data/htdocs/js/vendor/angular-cookies.min.js +7 -0
  29. data/htdocs/js/vendor/angular-loader.min.js +7 -0
  30. data/htdocs/js/vendor/angular-resource.min.js +10 -0
  31. data/htdocs/js/vendor/angular-sanitize.min.js +13 -0
  32. data/htdocs/js/vendor/angular-ui-ieshiv.min.js +7 -0
  33. data/htdocs/js/vendor/angular-ui.min.js +7 -0
  34. data/htdocs/js/vendor/angular.js +14401 -0
  35. data/htdocs/js/vendor/angular.min.js +158 -0
  36. data/htdocs/js/vendor/bootstrap.js +2027 -0
  37. data/htdocs/js/vendor/bootstrap.min.js +6 -0
  38. data/htdocs/js/vendor/html5shiv.js +5 -0
  39. data/htdocs/js/vendor/jquery-1.8.2.min.js +2 -0
  40. data/htdocs/templates/directory.html +25 -0
  41. data/htdocs/templates/file.html +6 -0
  42. data/htdocs/templates/git.html +1 -0
  43. data/htdocs/templates/index.html +44 -0
  44. data/htdocs/templates/index_entry.html +54 -0
  45. data/htdocs/templates/info_refs.html +27 -0
  46. data/htdocs/templates/loading.html +1 -0
  47. data/htdocs/templates/notfound.html +7 -0
  48. data/htdocs/templates/object.html +54 -0
  49. data/htdocs/templates/objects.html +16 -0
  50. data/htdocs/templates/pack_file.html +15 -0
  51. data/htdocs/templates/pack_index.html +38 -0
  52. data/htdocs/templates/packed_object.html +111 -0
  53. data/htdocs/templates/packed_refs.html +27 -0
  54. data/htdocs/templates/ref.html +12 -0
  55. data/lib/git-object-browser.rb +37 -0
  56. data/lib/git-object-browser/dumper.rb +62 -0
  57. data/lib/git-object-browser/index_dumper.rb +77 -0
  58. data/lib/git-object-browser/main.rb +63 -0
  59. data/lib/git-object-browser/models/bindata.rb +68 -0
  60. data/lib/git-object-browser/models/directory.rb +61 -0
  61. data/lib/git-object-browser/models/git_object.rb +127 -0
  62. data/lib/git-object-browser/models/index.rb +77 -0
  63. data/lib/git-object-browser/models/index_entry.rb +95 -0
  64. data/lib/git-object-browser/models/index_reuc_extension.rb +31 -0
  65. data/lib/git-object-browser/models/index_tree_extension.rb +52 -0
  66. data/lib/git-object-browser/models/info_refs.rb +32 -0
  67. data/lib/git-object-browser/models/pack_file.rb +40 -0
  68. data/lib/git-object-browser/models/pack_index.rb +146 -0
  69. data/lib/git-object-browser/models/packed_object.rb +239 -0
  70. data/lib/git-object-browser/models/packed_refs.rb +39 -0
  71. data/lib/git-object-browser/models/plain_file.rb +24 -0
  72. data/lib/git-object-browser/models/ref.rb +32 -0
  73. data/lib/git-object-browser/object_dumper.rb +31 -0
  74. data/lib/git-object-browser/server/git_servlet.rb +209 -0
  75. data/lib/git-object-browser/server/main.rb +31 -0
  76. data/lib/git-object-browser/version.rb +3 -0
  77. data/spec/fixtures/generate_worktree.sh +103 -0
  78. data/spec/fixtures/git/indexes/001 +0 -0
  79. data/spec/fixtures/git/indexes/002-empty-tree-extension +0 -0
  80. data/spec/fixtures/git/plain_file +1 -0
  81. data/spec/fixtures/json/blob.json +9 -0
  82. data/spec/fixtures/json/merge-a.json +48 -0
  83. data/spec/fixtures/json/test3-tag.json +36 -0
  84. data/spec/fixtures/json/tree.json +20 -0
  85. data/spec/fixtures/worktree/_git/COMMIT_EDITMSG +1 -0
  86. data/spec/fixtures/worktree/_git/HEAD +1 -0
  87. data/spec/fixtures/worktree/_git/ORIG_HEAD +1 -0
  88. data/spec/fixtures/worktree/_git/config +11 -0
  89. data/spec/fixtures/worktree/_git/description +1 -0
  90. data/spec/fixtures/worktree/_git/hooks/applypatch-msg.sample +15 -0
  91. data/spec/fixtures/worktree/_git/hooks/commit-msg.sample +24 -0
  92. data/spec/fixtures/worktree/_git/hooks/post-update.sample +8 -0
  93. data/spec/fixtures/worktree/_git/hooks/pre-applypatch.sample +14 -0
  94. data/spec/fixtures/worktree/_git/hooks/pre-commit.sample +50 -0
  95. data/spec/fixtures/worktree/_git/hooks/pre-rebase.sample +169 -0
  96. data/spec/fixtures/worktree/_git/hooks/prepare-commit-msg.sample +36 -0
  97. data/spec/fixtures/worktree/_git/hooks/update.sample +128 -0
  98. data/spec/fixtures/worktree/_git/ignore +3 -0
  99. data/spec/fixtures/worktree/_git/index +0 -0
  100. data/spec/fixtures/worktree/_git/info/exclude +6 -0
  101. data/spec/fixtures/worktree/_git/info/refs +1 -0
  102. data/spec/fixtures/worktree/_git/logs/HEAD +10 -0
  103. data/spec/fixtures/worktree/_git/logs/refs/heads/branch-a +3 -0
  104. data/spec/fixtures/worktree/_git/logs/refs/heads/branch-b +2 -0
  105. data/spec/fixtures/worktree/_git/logs/refs/heads/master +4 -0
  106. data/spec/fixtures/worktree/_git/objects/00/cb8bfeb5b8ce906d39698e4e33b38341f5448f +1 -0
  107. data/spec/fixtures/worktree/_git/objects/07/31f9d4b6fa0475872be6a8ca263096f1d201cf +2 -0
  108. data/spec/fixtures/worktree/_git/objects/1d/3dc60b5a117054e43741d51e599ff31bb15f9f +0 -0
  109. data/spec/fixtures/worktree/_git/objects/26/4e42b1fef5bcb55acec162fdd5a068d79ae551 +0 -0
  110. data/spec/fixtures/worktree/_git/objects/28/3c06ddf1b31c14bb221d41173299e133b7753d +0 -0
  111. data/spec/fixtures/worktree/_git/objects/37/d1632d3f1159dad9cfb58e6c34312ab4355c49 +0 -0
  112. data/spec/fixtures/worktree/_git/objects/3a/2bf444f105c19b13ba5e75e884e10715e95a91 +0 -0
  113. data/spec/fixtures/worktree/_git/objects/40/a061aaf0cd0555449671a11993e4fed11f91a4 +2 -0
  114. data/spec/fixtures/worktree/_git/objects/53/2a1874c26cd19bd4d66e03218ab73e63de4357 +3 -0
  115. data/spec/fixtures/worktree/_git/objects/5b/719b165fde1964fb5a08adaf3b6e4f57ca1ff5 +0 -0
  116. data/spec/fixtures/worktree/_git/objects/61/cae34206bb889bae43ffdd22c17217485178bf +0 -0
  117. data/spec/fixtures/worktree/_git/objects/6c/444ac15f1e3c2a6869bd36ca7e58c39512106f +2 -0
  118. data/spec/fixtures/worktree/_git/objects/93/b714995d24c52180195876058a49c7d7fea0ad +0 -0
  119. data/spec/fixtures/worktree/_git/objects/96/25401ac3e19ef10868c140a76b719ac3f08fcf +0 -0
  120. data/spec/fixtures/worktree/_git/objects/b9/29ed2ab14f7489d5238a06d10d2f2c229a4ab4 +0 -0
  121. data/spec/fixtures/worktree/_git/objects/be/e0d26d33c284ee065e38bd7e81ae4bdc870f89 +4 -0
  122. data/spec/fixtures/worktree/_git/objects/c3/6491256978d26c08cd7aa97eee0f5631f96659 +0 -0
  123. data/spec/fixtures/worktree/_git/objects/d2/34c5e057fe32c676ea67e8cb38f4625ddaeb54 +0 -0
  124. data/spec/fixtures/worktree/_git/objects/df/6b0d2bcc76e6ec0fca20c227104a4f28bac41b +0 -0
  125. data/spec/fixtures/worktree/_git/objects/e5/b6d4317cefa946d77fc91539f1f1e48b60836f +0 -0
  126. data/spec/fixtures/worktree/_git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 +0 -0
  127. data/spec/fixtures/worktree/_git/objects/info/packs +2 -0
  128. data/spec/fixtures/worktree/_git/objects/pack/pack-f1c1717e9264c12310c7bd3e7dcdd28924000ff6.idx +0 -0
  129. data/spec/fixtures/worktree/_git/objects/pack/pack-f1c1717e9264c12310c7bd3e7dcdd28924000ff6.pack +0 -0
  130. data/spec/fixtures/worktree/_git/packed-refs +2 -0
  131. data/spec/fixtures/worktree/_git/refs/heads/branch-a +1 -0
  132. data/spec/fixtures/worktree/_git/refs/heads/branch-b +1 -0
  133. data/spec/fixtures/worktree/_git/refs/heads/master +1 -0
  134. data/spec/fixtures/worktree/_git/refs/tags/simple-tag +1 -0
  135. data/spec/fixtures/worktree/_git/refs/tags/test3-tag +1 -0
  136. data/spec/fixtures/worktree/sample-a.txt +1 -0
  137. data/spec/fixtures/worktree/sample.txt +1 -0
  138. data/spec/fixtures/worktree/subdir/sample-sub.txt +0 -0
  139. data/spec/git-object-browser/main_spec.rb +31 -0
  140. data/spec/git-object-browser/models/bindata_spec.rb +144 -0
  141. data/spec/git-object-browser/models/git_object_spec.rb +49 -0
  142. data/spec/git-object-browser/models/index_spec.rb +42 -0
  143. data/spec/git-object-browser/models/index_tree_extension_spec.rb +58 -0
  144. data/spec/git-object-browser/models/plain_file_spec.rb +11 -0
  145. data/spec/spec_helper.rb +19 -0
  146. metadata +260 -0
@@ -0,0 +1,239 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ # https://github.com/git/git/blob/master/sha1_file.c
4
+ # https://github.com/git/git/blob/master/patch-delta.c
5
+ # https://github.com/git/git/blob/master/builtin/unpack-objects.c
6
+ # https://github.com/mojombo/grit/blob/master/lib/grit/git-ruby/internal/pack.rb
7
+ module GitObjectBrowser
8
+
9
+ module Models
10
+
11
+ class PackedObject < Bindata
12
+
13
+ attr_reader :header, :raw_data
14
+ attr_reader :object
15
+
16
+ TYPES = %w{
17
+ undefined
18
+ commit
19
+ tree
20
+ blob
21
+ tag
22
+ undefined
23
+ ofs_delta
24
+ ref_delta
25
+ }
26
+
27
+ def initialize(index, input)
28
+ super(input)
29
+ @index = index
30
+ end
31
+
32
+ def parse(offset)
33
+ parse_raw(offset)
34
+ input = "#{ @object_type } #{ @object_size }\0" + @raw_data
35
+ @object = GitObject.new(nil).parse_inflated(input)
36
+ self
37
+ end
38
+
39
+ def parse_raw(offset)
40
+ @offset = offset
41
+ @header = parse_header(offset)
42
+
43
+ if @header[:type] == 'ofs_delta'
44
+ obj_ofs_delta
45
+ elsif @header[:type] == 'ref_delta'
46
+ obj_ref_delta
47
+ else
48
+ @object_type = @header[:type]
49
+ @object_size = @header[:size]
50
+ @raw_data = zlib_inflate
51
+ end
52
+
53
+ [@object_type, @object_size]
54
+ end
55
+
56
+ def parse_header(offset)
57
+ seek(offset)
58
+ (type, size, header_size) = parse_type_and_size
59
+ type = TYPES[type]
60
+ { :type => type, :size => size, :header_size => header_size }
61
+ end
62
+
63
+ def parse_ofs_delta_header(offset, header)
64
+ (delta_offset, delta_header_size) = parse_delta_offset
65
+ header[:base_offset] = offset - delta_offset
66
+ header[:header_size] += delta_header_size
67
+ header
68
+ end
69
+
70
+ def parse_ref_delta_header(header)
71
+ header[:base_sha1] = hex(20)
72
+ header[:header_size] += 20
73
+ header
74
+ end
75
+
76
+ def to_hash
77
+ return {
78
+ :offset => @offset,
79
+ :type => @header[:type], # commit, tree, blob, tag, ofs_delta, ref_delta
80
+ :size => @header[:size],
81
+ :header_size => @header[:header_size],
82
+ :base_offset => @header[:base_offset],
83
+ :delta_commands => @delta_commands,
84
+ :base_size => @base_size,
85
+ :object => @object.to_hash,
86
+ }
87
+ end
88
+
89
+ def self.path?(relpath)
90
+ return relpath =~ %r{\Aobjects/pack/pack-[0-9a-f]{40}.pack\z}
91
+ end
92
+
93
+ private
94
+
95
+ def obj_ofs_delta
96
+ parse_ofs_delta_header(@offset, @header)
97
+ load_base_and_patch_delta
98
+ end
99
+
100
+ def obj_ref_delta
101
+ parse_ref_delta_header(@header)
102
+ index_entry = @index.find(@header[:base_sha1])
103
+ @header[:base_offset] = index_entry[:offset]
104
+ load_base_and_patch_delta
105
+ end
106
+
107
+ def load_base_and_patch_delta
108
+ begin
109
+ pack = PackedObject.new(@index, @in)
110
+ (@object_type, _) = pack.parse_raw(@header[:base_offset])
111
+ @base = pack.raw_data
112
+ ensure
113
+ seek(@offset + @header[:header_size])
114
+ end
115
+
116
+ switch_source(StringIO.new(zlib_inflate)) { patch_delta }
117
+ end
118
+
119
+ def patch_delta
120
+ @base_size = parse_size
121
+ if @base.size != @base_size
122
+ raise 'incollect base size'
123
+ end
124
+
125
+ @object_size = parse_size
126
+ @delta_commands = []
127
+ @raw_data = ''
128
+ while ! @in.eof?
129
+ delta_command
130
+ end
131
+ if @object_size != @raw_data.size
132
+ raise 'incollect delta size'
133
+ end
134
+ end
135
+
136
+ def delta_command
137
+ cmd = byte
138
+ data = nil
139
+ if cmd & 0b10000000 != 0
140
+ (offset, size) = parse_base_offset_and_size(cmd)
141
+ data = @base[offset, size]
142
+ @raw_data << data
143
+ @delta_commands << { :source => :base, :offset => offset, :size => size }
144
+ elsif cmd != 0
145
+ size = cmd
146
+ data = raw(size)
147
+ @raw_data << data
148
+ @delta_commands << { :source => :delta, :size => size }
149
+ else
150
+ raise 'delta command is 0'
151
+ end
152
+ @delta_commands.last[:data] = shorten_utf8(data, 2000)
153
+ end
154
+
155
+ def shorten_utf8(bin, length)
156
+ str = bin.force_encoding('UTF-8')
157
+ str = '(not UTF-8)' unless str.valid_encoding?
158
+ str = str[0, length] + '...' if str.length > length
159
+ str
160
+ end
161
+
162
+ def zlib_inflate
163
+ store = Zlib::Inflate.new
164
+ buffer = ''
165
+ while buffer.size < @header[:size]
166
+ rawdata = raw(4096)
167
+ if rawdata.size == 0
168
+ raise 'inflate error'
169
+ end
170
+ buffer << store.inflate(rawdata)
171
+ end
172
+ store.close
173
+ buffer
174
+ end
175
+
176
+ # sha1_file.c unpack_object_header_buffer
177
+ # unpack-objects.c unpack_one
178
+ def parse_type_and_size
179
+ hdr = byte
180
+ hdr_size = 1
181
+ continue = (hdr & 0b10000000)
182
+ type = (hdr & 0b01110000) >> 4
183
+ size = (hdr & 0b00001111)
184
+ size_len = 4
185
+ while continue != 0
186
+ hdr = byte
187
+ hdr_size += 1
188
+ continue = (hdr & 0b10000000)
189
+ size += (hdr & 0b01111111) << size_len
190
+ size_len += 7
191
+ end
192
+ return [type, size, hdr_size]
193
+ end
194
+
195
+ # delta.h get_delta_hdr_size
196
+ def parse_size
197
+ size = 0
198
+ size_len = 0
199
+ begin
200
+ hdr = byte
201
+ continue = (hdr & 0b10000000)
202
+ size += (hdr & 0b01111111) << size_len
203
+ size_len += 7
204
+ end while continue != 0
205
+ return size
206
+ end
207
+
208
+ # sha1_file.c get_delta_base
209
+ # unpack-objects.c unpack_delta_entry
210
+ def parse_delta_offset
211
+ offset = -1
212
+ hdr_size = 0
213
+ begin
214
+ hdr = byte
215
+ hdr_size += 1
216
+ continue = hdr & 0b10000000
217
+ low_offset = hdr & 0b01111111
218
+ offset = ((offset + 1) << 7) | low_offset
219
+ end while continue != 0
220
+ return [offset, hdr_size]
221
+ end
222
+
223
+ # patch-delta.c
224
+ def parse_base_offset_and_size(cmd)
225
+ offset = size = 0
226
+ offset = byte if cmd & 0b00000001 != 0
227
+ offset |= byte << 8 if cmd & 0b00000010 != 0
228
+ offset |= byte << 16 if cmd & 0b00000100 != 0
229
+ offset |= byte << 24 if cmd & 0b00001000 != 0
230
+ size = byte if cmd & 0b00010000 != 0
231
+ size |= byte << 8 if cmd & 0b00100000 != 0
232
+ size |= byte << 16 if cmd & 0b01000000 != 0
233
+ size = 0x10000 if size == 0
234
+ return [offset, size]
235
+ end
236
+
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,39 @@
1
+
2
+ module GitObjectBrowser
3
+
4
+ module Models
5
+
6
+ class PackedRefs
7
+ def initialize(input)
8
+ @entries = []
9
+ while (line = input.gets) do
10
+ next if line =~ /\A\s*#/
11
+ next unless line =~ /(\^)?([0-9a-f]{40})\s*(.*)/
12
+ sha1 = $2
13
+ ref = $3
14
+ if $1
15
+ entry = @entries.last
16
+ entry[:tag_sha1] = sha1 if entry
17
+ else
18
+ entry = {}
19
+ entry[:sha1] = sha1
20
+ entry[:ref] = ref
21
+ @entries << entry
22
+ end
23
+ end
24
+ end
25
+
26
+ def to_hash
27
+ return {
28
+ :entries => @entries
29
+ }
30
+ end
31
+
32
+ def self.path?(relpath)
33
+ return relpath == "packed-refs"
34
+ end
35
+
36
+ end
37
+
38
+ end
39
+ end
@@ -0,0 +1,24 @@
1
+
2
+ module GitObjectBrowser
3
+
4
+ module Models
5
+
6
+ class PlainFile
7
+ def initialize(input)
8
+ @in = input
9
+ end
10
+
11
+ def parse
12
+ @content = @in.read(nil)
13
+ @content = @content.force_encoding('UTF-8')
14
+ @content = '(not UTF-8)' unless @content.valid_encoding?
15
+ @content = @content[0, 3000] + "\n..." if @content.length > 3000
16
+ self
17
+ end
18
+
19
+ def to_hash
20
+ return { 'content' => @content }
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,32 @@
1
+
2
+ module GitObjectBrowser
3
+
4
+ module Models
5
+
6
+ class Ref
7
+ def initialize(input)
8
+ line = input.gets.to_s
9
+
10
+ if line =~ %r{\Aref:\s*(.+)}
11
+ @ref = $1
12
+ elsif line =~ %r{\A([0-9a-f]{40})}
13
+ @sha1 = $1
14
+ end
15
+ end
16
+
17
+ def to_hash
18
+ return {
19
+ "ref" => @ref,
20
+ "sha1" => @sha1
21
+ }
22
+ end
23
+
24
+ def self.path?(relpath)
25
+ ref_names = %w{HEAD FETCH_HEAD ORIG_HEAD MERGE_HEAD CHERRY_PICK_HEAD}
26
+ return (ref_names.include?(relpath) || relpath =~ %r{\Arefs/})
27
+ end
28
+
29
+ end
30
+
31
+ end
32
+ end
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+
3
+ module GitObjectBrowser
4
+
5
+ class ObjectDumper
6
+
7
+ def initialize(input, output)
8
+ @object = Models::GitObject.new(input)
9
+ @out = output
10
+ end
11
+
12
+ def dump
13
+ @out << "type: #{@object.type}\n"
14
+ @out << "size: #{@object.size}\n"
15
+ @out << "sha1: #{@object.sha1}\n"
16
+ @out << "\n"
17
+ if @object.type == "tree"
18
+ dump_tree_entries
19
+ else
20
+ @out << @object.contents
21
+ end
22
+ end
23
+
24
+ # man git-ls-tree
25
+ def dump_tree_entries
26
+ @object.entries.each do |entry|
27
+ @out << "#{entry[:mode]} #{entry[:sha1]} #{entry[:filename]}\n"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,209 @@
1
+
2
+ module GitObjectBrowser
3
+
4
+ module Server
5
+
6
+ class GitServlet < WEBrick::HTTPServlet::AbstractServlet
7
+ def initialize(server, target)
8
+ @target = File.expand_path(target)
9
+ end
10
+
11
+ def do_GET(request, response)
12
+ # status, content_type, body = do_stuff_with request
13
+ path = request.path
14
+ unless path =~ %r{/.git(?:/(.*))?}
15
+ not_found(response)
16
+ return
17
+ end
18
+
19
+ @relpath = $1.to_s
20
+ path = File.join(@target, @relpath)
21
+ unless File.exist?(path)
22
+ not_found(response) unless redirect_to_packed_object(response)
23
+ return
24
+ end
25
+
26
+ if path =~ /\.\./
27
+ not_found(response)
28
+ return
29
+ end
30
+
31
+ return if response_directory(response)
32
+ return if response_index(response)
33
+ return if response_object(response)
34
+ return if response_ref(response)
35
+ return if response_packed_object(response, request.query["offset"])
36
+ return if response_pack_file(response)
37
+ return if response_pack_index(response)
38
+ return if response_info_refs(response)
39
+ return if response_packed_refs(response)
40
+
41
+ response_file(response)
42
+ end
43
+
44
+ def redirect_to_packed_object(response)
45
+ return false unless GitObjectBrowser::Models::GitObject.path?(@relpath)
46
+ sha1 = @relpath.gsub(%r{\A.*/([0-9a-f]{2})/([0-9a-f]{38})\z}, '\1\2')
47
+
48
+ Dir.chdir(@target) do
49
+ Dir.glob('objects/pack/*.idx') do |path|
50
+ File.open(path) do |input|
51
+ index = GitObjectBrowser::Models::PackIndex.new(input)
52
+ result = index.find(sha1)
53
+ unless result.nil?
54
+ packfile = path.sub(/\.idx\z/, '.pack')
55
+ response.status = 302
56
+ response["Location"] = "/.git/#{ packfile }?offset=#{ result[:offset] }"
57
+ return true
58
+ end
59
+ end
60
+ end
61
+ end
62
+ false
63
+ end
64
+
65
+ def response_wrapped_object(response, type, obj)
66
+ ok(response)
67
+ hash = {}
68
+ hash["type"] = type
69
+ hash["object"] = obj.to_hash
70
+ hash["root"] = @target
71
+ hash["path"] = @relpath
72
+ hash["wroking_dir"] = File.basename(File.dirname(@target))
73
+
74
+ response.body = ::JSON.generate(hash)
75
+ end
76
+
77
+ def response_directory(response)
78
+ return false unless File.directory?(File.join(@target, @relpath))
79
+
80
+ obj = GitObjectBrowser::Models::Directory.new(@target, @relpath)
81
+ response_wrapped_object(response, "directory", obj)
82
+ return true
83
+ end
84
+
85
+ def response_index(response)
86
+ return false unless @relpath == "index"
87
+
88
+ obj = {}
89
+ File.open(File.join(@target, @relpath)) do |input|
90
+ obj = GitObjectBrowser::Models::Index.new(input).parse
91
+ end
92
+ response_wrapped_object(response, "index", obj)
93
+ return true
94
+ end
95
+
96
+ def response_object(response)
97
+ return false unless GitObjectBrowser::Models::GitObject.path?(@relpath)
98
+
99
+ obj = {}
100
+ File.open(File.join(@target, @relpath)) do |input|
101
+ obj = GitObjectBrowser::Models::GitObject.new(input).parse
102
+ end
103
+ response_wrapped_object(response, "object", obj)
104
+ return true
105
+ end
106
+
107
+ def response_ref(response)
108
+ return false unless GitObjectBrowser::Models::Ref.path?(@relpath)
109
+
110
+ obj = {}
111
+ File.open(File.join(@target, @relpath)) do |input|
112
+ obj = GitObjectBrowser::Models::Ref.new(input)
113
+ end
114
+ response_wrapped_object(response, "ref", obj)
115
+ return true
116
+ end
117
+
118
+ def response_pack_index(response)
119
+ return false unless GitObjectBrowser::Models::PackIndex.path?(@relpath)
120
+ obj = {}
121
+ File.open(File.join(@target, @relpath)) do |input|
122
+ obj = GitObjectBrowser::Models::PackIndex.new(input).parse
123
+ end
124
+ File.open(index_to_pack_path) do |input|
125
+ obj.load_object_types(input)
126
+ end
127
+ response_wrapped_object(response, "pack_index", obj)
128
+ return true
129
+ end
130
+
131
+ def response_pack_file(response)
132
+ return false unless GitObjectBrowser::Models::PackFile.path?(@relpath)
133
+ obj = {}
134
+ File.open(File.join(@target, @relpath)) do |input|
135
+ obj = GitObjectBrowser::Models::PackFile.new(input).parse
136
+ end
137
+ response_wrapped_object(response, 'pack_file', obj)
138
+ return true
139
+ end
140
+
141
+ def index_to_pack_path
142
+ File.join(@target, @relpath.sub(/\.idx\z/, '.pack'))
143
+ end
144
+
145
+ def pack_to_index_path
146
+ File.join(@target, @relpath.sub(/\.pack\z/, '.idx'))
147
+ end
148
+
149
+ def response_packed_object(response, offset)
150
+ return false if offset.nil?
151
+ return false unless GitObjectBrowser::Models::PackedObject.path?(@relpath)
152
+ obj = {}
153
+
154
+ File.open(pack_to_index_path) do |index_input|
155
+ index = GitObjectBrowser::Models::PackIndex.new(index_input)
156
+ File.open(File.join(@target, @relpath)) do |input|
157
+ obj = GitObjectBrowser::Models::PackedObject.new(index, input).parse(offset.to_i)
158
+ end
159
+ end
160
+ response_wrapped_object(response, "packed_object", obj)
161
+ return true
162
+ end
163
+
164
+ def response_info_refs(response)
165
+ return false unless GitObjectBrowser::Models::InfoRefs.path?(@relpath)
166
+
167
+ obj = {}
168
+ File.open(File.join(@target, @relpath)) do |input|
169
+ obj = GitObjectBrowser::Models::InfoRefs.new(input)
170
+ end
171
+ response_wrapped_object(response, "info_refs", obj)
172
+ return true
173
+ end
174
+
175
+ def response_packed_refs(response)
176
+ return false unless GitObjectBrowser::Models::PackedRefs.path?(@relpath)
177
+
178
+ obj = {}
179
+ File.open(File.join(@target, @relpath)) do |input|
180
+ obj = GitObjectBrowser::Models::PackedRefs.new(input)
181
+ end
182
+ response_wrapped_object(response, "packed_refs", obj)
183
+ return true
184
+ end
185
+
186
+ def response_file(response)
187
+ path = File.join(@target, @relpath)
188
+ obj = {}
189
+ File.open(path) do |input|
190
+ obj = GitObjectBrowser::Models::PlainFile.new(input).parse
191
+ end
192
+ response_wrapped_object(response, "file", obj)
193
+ return true
194
+ end
195
+
196
+ def ok(response)
197
+ response.status = 200
198
+ response['Content-Type'] = 'application/json'
199
+ end
200
+
201
+ def not_found(response)
202
+ response.status = 404
203
+ response['Content-Type'] = 'application/json'
204
+ response.body = '{}'
205
+ end
206
+ end
207
+ end
208
+ end
209
+