git-object-browser 0.0.2

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.
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
+