gollum_rails 1.0.6 → 1.4.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -27,9 +27,6 @@ module GollumRails
27
27
  # Gets / Sets the repository
28
28
  attr_accessor :repository
29
29
 
30
- # Gets / Sets the init options
31
- attr_accessor :options
32
-
33
30
  # Startup action for building wiki components
34
31
  #
35
32
  # Returns true or throws an exception if the path is invalid
@@ -42,11 +39,7 @@ module GollumRails
42
39
  initialize_wiki @repository
43
40
  end
44
41
  end
45
- end
46
-
47
- # Wiki startup options
48
- def options=(options)
49
- @options = options
42
+
50
43
  end
51
44
 
52
45
  # defines block builder for Rails initializer.
@@ -75,7 +68,7 @@ module GollumRails
75
68
  def initialize_wiki(path)
76
69
  if path_valid? path
77
70
  repository = Grit::Repo.new path.to_s
78
- GollumRails::Adapters::Gollum::Wiki.new(repository, options || {})
71
+ GollumRails::Adapters::Gollum::Wiki.new repository
79
72
  true
80
73
  else
81
74
  raise GollumInternalError, 'no repository path specified'
@@ -0,0 +1,397 @@
1
+ #
2
+ # converted from the gitrb project
3
+ #
4
+ # authors:
5
+ # Matthias Lederhofer <matled@gmx.net>
6
+ # Simon 'corecode' Schubert <corecode@fs.ei.tum.de>
7
+ # Scott Chacon <schacon@gmail.com>
8
+ #
9
+ # provides native ruby access to git objects and pack files
10
+ #
11
+
12
+ require 'zlib'
13
+ require 'grit/git-ruby/internal/raw_object'
14
+ require 'grit/git-ruby/internal/file_window'
15
+
16
+ PACK_IDX_SIGNATURE = [0xFF, 0x74, 0x4F, 0x63]
17
+
18
+ module Grit
19
+ module GitRuby
20
+ module Internal
21
+ class PackFormatError < StandardError
22
+ end
23
+
24
+ class PackStorage
25
+ OBJ_OFS_DELTA = 6
26
+ OBJ_REF_DELTA = 7
27
+
28
+ FanOutCount = 256
29
+ SHA1Size = 20
30
+ IdxOffsetSize = 4
31
+ OffsetSize = 4
32
+ ExtendedOffsetSize = 8
33
+ CrcSize = 4
34
+ OffsetStart = FanOutCount * IdxOffsetSize
35
+ SHA1Start = OffsetStart + OffsetSize
36
+ EntrySize = OffsetSize + SHA1Size
37
+ EntrySizeV2 = SHA1Size + CrcSize + OffsetSize
38
+
39
+ def initialize(file)
40
+ if file =~ /\.idx$/
41
+ file = file[0...-3] + 'pack'
42
+ end
43
+ @name = file
44
+ @cache = {}
45
+ init_pack
46
+ end
47
+
48
+ def with_idx(index_file = nil)
49
+ index_file ||= @name[0...-4] + 'idx'
50
+
51
+ begin
52
+ idxfile = File.open(index_file, 'rb')
53
+ rescue Errno::ENOENT => boom
54
+ # file went away. bail out without yielding.
55
+ return
56
+ end
57
+
58
+ # read header
59
+ sig = idxfile.read(4).unpack("C*")
60
+ ver = idxfile.read(4).unpack("N")[0]
61
+
62
+ if sig == PACK_IDX_SIGNATURE
63
+ if(ver != 2)
64
+ raise PackFormatError, "pack #@name has unknown pack file version #{ver}"
65
+ end
66
+ @version = 2
67
+ else
68
+ @version = 1
69
+ end
70
+
71
+ idx = FileWindow.new(idxfile, @version)
72
+ yield idx
73
+ idx.unmap
74
+ ensure
75
+ idxfile.close if idxfile
76
+ end
77
+
78
+ def with_packfile
79
+ begin
80
+ packfile = File.open(@name, 'rb')
81
+ rescue Errno::ENOENT
82
+ # file went away. bail out without yielding.
83
+ return
84
+ end
85
+ yield packfile
86
+ ensure
87
+ packfile.close if packfile
88
+ end
89
+
90
+ def cache_objects
91
+ @cache = {}
92
+ with_packfile do |packfile|
93
+ each_entry do |sha, offset|
94
+ data, type = unpack_object(packfile, offset, {:caching => true})
95
+ if data
96
+ @cache[sha] = RawObject.new(OBJ_TYPES[type], data)
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ def name
103
+ @name
104
+ end
105
+
106
+ def close
107
+ # shouldnt be anything open now
108
+ end
109
+
110
+ # given an index file, list out the shas that it's packfile contains
111
+ def get_shas
112
+ shas = []
113
+ each_sha1 { |sha| shas << sha.unpack("H*")[0] }
114
+ shas
115
+ end
116
+
117
+ def [](sha1)
118
+ if obj = @cache[sha1]
119
+ return obj
120
+ end
121
+
122
+ offset = find_object(sha1)
123
+ return nil if !offset
124
+ @cache[sha1] = obj = parse_object(offset)
125
+ return obj
126
+ end
127
+
128
+ def init_pack
129
+ with_idx do |idx|
130
+ @offsets = [0]
131
+ FanOutCount.times do |i|
132
+ pos = idx[i * IdxOffsetSize,IdxOffsetSize].unpack('N')[0]
133
+ if pos < @offsets[i]
134
+ raise PackFormatError, "pack #@name has discontinuous index #{i}"
135
+ end
136
+ @offsets << pos
137
+ end
138
+ @size = @offsets[-1]
139
+ end
140
+ end
141
+
142
+ def each_entry
143
+ with_idx do |idx|
144
+ if @version == 2
145
+ data = read_data_v2(idx)
146
+ data.each do |sha1, crc, offset|
147
+ yield sha1, offset
148
+ end
149
+ else
150
+ pos = OffsetStart
151
+ @size.times do
152
+ offset = idx[pos,OffsetSize].unpack('N')[0]
153
+ sha1 = idx[pos+OffsetSize,SHA1Size]
154
+ pos += EntrySize
155
+ yield sha1, offset
156
+ end
157
+ end
158
+ end
159
+ end
160
+
161
+ def read_data_v2(idx)
162
+ data = []
163
+ pos = OffsetStart
164
+ @size.times do |i|
165
+ data[i] = [idx[pos,SHA1Size], 0, 0]
166
+ pos += SHA1Size
167
+ end
168
+ @size.times do |i|
169
+ crc = idx[pos,CrcSize]
170
+ data[i][1] = crc
171
+ pos += CrcSize
172
+ end
173
+ @size.times do |i|
174
+ offset = idx[pos,OffsetSize].unpack('N')[0]
175
+ data[i][2] = offset
176
+ pos += OffsetSize
177
+ end
178
+ data
179
+ end
180
+ private :read_data_v2
181
+
182
+ def each_sha1
183
+ with_idx do |idx|
184
+ if @version == 2
185
+ data = read_data_v2(idx)
186
+ data.each do |sha1, crc, offset|
187
+ yield sha1
188
+ end
189
+ else
190
+ pos = SHA1Start
191
+ @size.times do
192
+ sha1 = idx[pos,SHA1Size]
193
+ pos += EntrySize
194
+ yield sha1
195
+ end
196
+ end
197
+ end
198
+ end
199
+
200
+ def find_object_in_index(idx, sha1)
201
+ slot = sha1.getord(0)
202
+ return nil if !slot
203
+ first, last = @offsets[slot,2]
204
+ while first < last
205
+ mid = (first + last) / 2
206
+ if @version == 2
207
+ midsha1 = idx[OffsetStart + (mid * SHA1Size), SHA1Size]
208
+ cmp = midsha1 <=> sha1
209
+
210
+ if cmp < 0
211
+ first = mid + 1
212
+ elsif cmp > 0
213
+ last = mid
214
+ else
215
+ pos = OffsetStart + (@size * (SHA1Size + CrcSize)) + (mid * OffsetSize)
216
+ offset = idx[pos, OffsetSize].unpack('N')[0]
217
+ if offset & 0x80000000 > 0
218
+ offset &= 0x7fffffff
219
+ pos = OffsetStart + (@size * (SHA1Size + CrcSize + OffsetSize)) + (offset * ExtendedOffsetSize)
220
+ words = idx[pos, ExtendedOffsetSize].unpack('NN')
221
+ offset = (words[0] << 32) | words[1]
222
+ end
223
+ return offset
224
+ end
225
+ else
226
+ midsha1 = idx[SHA1Start + mid * EntrySize,SHA1Size]
227
+ cmp = midsha1 <=> sha1
228
+
229
+ if cmp < 0
230
+ first = mid + 1
231
+ elsif cmp > 0
232
+ last = mid
233
+ else
234
+ pos = OffsetStart + mid * EntrySize
235
+ offset = idx[pos,OffsetSize].unpack('N')[0]
236
+ return offset
237
+ end
238
+ end
239
+ end
240
+ nil
241
+ end
242
+
243
+ def find_object(sha1)
244
+ obj = nil
245
+ with_idx do |idx|
246
+ obj = find_object_in_index(idx, sha1)
247
+ end
248
+ obj
249
+ end
250
+ private :find_object
251
+
252
+ def parse_object(offset)
253
+ obj = nil
254
+ with_packfile do |packfile|
255
+ data, type = unpack_object(packfile, offset)
256
+ obj = RawObject.new(OBJ_TYPES[type], data)
257
+ end
258
+ obj
259
+ end
260
+ protected :parse_object
261
+
262
+ def unpack_object(packfile, offset, options = {})
263
+ obj_offset = offset
264
+ packfile.seek(offset)
265
+
266
+ c = packfile.read(1).getord(0)
267
+ size = c & 0xf
268
+ type = (c >> 4) & 7
269
+ shift = 4
270
+ offset += 1
271
+ while c & 0x80 != 0
272
+ c = packfile.read(1).getord(0)
273
+ size |= ((c & 0x7f) << shift)
274
+ shift += 7
275
+ offset += 1
276
+ end
277
+
278
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
279
+
280
+ case type
281
+ when OBJ_OFS_DELTA, OBJ_REF_DELTA
282
+ data, type = unpack_deltified(packfile, type, offset, obj_offset, size, options)
283
+ #puts type
284
+ when OBJ_COMMIT, OBJ_TREE, OBJ_BLOB, OBJ_TAG
285
+ data = unpack_compressed(offset, size)
286
+ else
287
+ raise PackFormatError, "invalid type #{type}"
288
+ end
289
+ [data, type]
290
+ end
291
+ private :unpack_object
292
+
293
+ def unpack_deltified(packfile, type, offset, obj_offset, size, options = {})
294
+ packfile.seek(offset)
295
+ data = packfile.read(SHA1Size)
296
+
297
+ if type == OBJ_OFS_DELTA
298
+ i = 0
299
+ c = data.getord(i)
300
+ base_offset = c & 0x7f
301
+ while c & 0x80 != 0
302
+ c = data.getord(i += 1)
303
+ base_offset += 1
304
+ base_offset <<= 7
305
+ base_offset |= c & 0x7f
306
+ end
307
+ base_offset = obj_offset - base_offset
308
+ offset += i + 1
309
+ else
310
+ base_offset = find_object(data)
311
+ offset += SHA1Size
312
+ end
313
+
314
+ base, type = unpack_object(packfile, base_offset)
315
+
316
+ return [false, false] if !(type == OBJ_COMMIT || type == OBJ_TREE) && options[:caching]
317
+
318
+ delta = unpack_compressed(offset, size)
319
+ [patch_delta(base, delta), type]
320
+ end
321
+ private :unpack_deltified
322
+
323
+ def unpack_compressed(offset, destsize)
324
+ outdata = ""
325
+ with_packfile do |packfile|
326
+ packfile.seek(offset)
327
+ zstr = Zlib::Inflate.new
328
+ while outdata.size < destsize
329
+ indata = packfile.read(4096)
330
+ if indata.size == 0
331
+ raise PackFormatError, 'error reading pack data'
332
+ end
333
+ outdata << zstr.inflate(indata)
334
+ end
335
+ if outdata.size > destsize
336
+ raise PackFormatError, 'error reading pack data'
337
+ end
338
+ zstr.close
339
+ end
340
+ outdata
341
+ end
342
+ private :unpack_compressed
343
+
344
+ def patch_delta(base, delta)
345
+ src_size, pos = patch_delta_header_size(delta, 0)
346
+ if src_size != base.size
347
+ raise PackFormatError, 'invalid delta data'
348
+ end
349
+
350
+ dest_size, pos = patch_delta_header_size(delta, pos)
351
+ dest = ""
352
+ while pos < delta.size
353
+ c = delta.getord(pos)
354
+ pos += 1
355
+ if c & 0x80 != 0
356
+ pos -= 1
357
+ cp_off = cp_size = 0
358
+ cp_off = delta.getord(pos += 1) if c & 0x01 != 0
359
+ cp_off |= delta.getord(pos += 1) << 8 if c & 0x02 != 0
360
+ cp_off |= delta.getord(pos += 1) << 16 if c & 0x04 != 0
361
+ cp_off |= delta.getord(pos += 1) << 24 if c & 0x08 != 0
362
+ cp_size = delta.getord(pos += 1) if c & 0x10 != 0
363
+ cp_size |= delta.getord(pos += 1) << 8 if c & 0x20 != 0
364
+ cp_size |= delta.getord(pos += 1) << 16 if c & 0x40 != 0
365
+ cp_size = 0x10000 if cp_size == 0
366
+ pos += 1
367
+ dest << base[cp_off,cp_size]
368
+ elsif c != 0
369
+ dest << delta[pos,c]
370
+ pos += c
371
+ else
372
+ raise PackFormatError, 'invalid delta data'
373
+ end
374
+ end
375
+ dest
376
+ end
377
+ private :patch_delta
378
+
379
+ def patch_delta_header_size(delta, pos)
380
+ size = 0
381
+ shift = 0
382
+ begin
383
+ c = delta.getord(pos)
384
+ if c == nil
385
+ raise PackFormatError, 'invalid delta header'
386
+ end
387
+ pos += 1
388
+ size |= (c & 0x7f) << shift
389
+ shift += 7
390
+ end while c & 0x80 != 0
391
+ [size, pos]
392
+ end
393
+ private :patch_delta_header_size
394
+ end
395
+ end
396
+ end
397
+ end
@@ -5,15 +5,9 @@ describe GollumRails::Adapters::Gollum::Connector do
5
5
  @class = GollumRails::Adapters::Gollum::Connector
6
6
  end
7
7
 
8
- it "should test the Wiki path connector" do
9
- @class.wiki_path.should be_a String
8
+ it "should test the Wiki class connector" do
9
+ @class.wiki_class.should == GollumRails::Adapters::Gollum::Wiki
10
10
  end
11
- it "should test the Wiki options connector" do
12
- @class.wiki_options.should be_a Hash
13
- end
14
- it "should test the Wiki options content" do
15
- @class.wiki_options.should == {}
16
- end
17
11
  it "should test the Page class connector" do
18
12
  @class.page_class.should == GollumRails::Adapters::Gollum::Page
19
13
  end
@@ -6,24 +6,84 @@ describe GollumRails::Adapters::Gollum::Page do
6
6
  :name => 'The Mosny',
7
7
  :email => 'mosny@zyg.li'
8
8
  }
9
+
10
+ @location = "#{File.dirname(__FILE__)}/../../../utils/wiki.git"
11
+ @repo = Grit::Repo.init_bare @location
12
+ @wiki = GollumRails::Adapters::Gollum::Wiki.new @repo
13
+ @page = GollumRails::Adapters::Gollum::Page.new
9
14
  end
10
- describe "Connector stuff" do
11
- it "should have updated the page_class on initialize" do
12
- adapter = GollumRails::Adapters::Gollum::Page.new
13
- GollumRails::Adapters::Gollum::Connector.page_class.should == GollumRails::Adapters::Gollum::Page
14
- end
15
- end
16
- describe "statically methods" do
17
- it "is a hash" do
18
- GollumRails::Adapters::Gollum::Page.parse_path('google/de').should be_a Hash
19
- end
20
- it "should equal" do
21
- path1 = GollumRails::Adapters::Gollum::Page.parse_path('google/de')
22
- path2 = GollumRails::Adapters::Gollum::Page.parse_path('/google/de')
23
- path1.should == path2
24
- end
25
- it "adds a leading slash" do
26
- GollumRails::Adapters::Gollum::Page.parse_path('google/de')[:path][0].should == '/'
27
- end
15
+ it "should initialize the correct wiki" do
16
+ location = "#{File.dirname(__FILE__)}/../../../utils/wiki.git"
17
+ repo = Grit::Repo.init_bare location
18
+ wiki = GollumRails::Adapters::Gollum::Wiki.new repo
19
+ page = GollumRails::Adapters::Gollum::Page.new
20
+ page.wiki.should be_instance_of Gollum::Wiki
21
+ end
22
+ it "should create a new page" do
23
+ location = "#{File.dirname(__FILE__)}/../../../utils/wiki.git"
24
+ repo = Grit::Repo.init_bare location
25
+ wiki = GollumRails::Adapters::Gollum::Wiki.new repo
26
+ page = GollumRails::Adapters::Gollum::Page.new
27
+ page.new_page("testpage", "content",:markdown, @commit ).should be_instance_of Gollum::Page
28
+ page.delete_page(@commit)
29
+ end
30
+
31
+ it "should delete an existing page" do
32
+ page = @page.new_page 'testpage', 'content', :markdown, @commit
33
+ @page.delete_page(@commit,page).should be_instance_of String
34
+
35
+ @page.new_page 'testpage', 'content', :markdown, @commit
36
+ @page.delete_page(@commit).should be_instance_of String
37
+ end
38
+ it "should update an existing page" do
39
+ @page.new_page 'testpage', 'content', :markdown, @commit
40
+ page = {}
41
+ page[:name] = 'test'
42
+ page[:format] = :markdown
43
+ page[:content] = "content"
44
+ @page.update_page(page, @commit)
45
+
46
+ page = []
47
+ expect{@page.update_page(page, @commit)}.to raise_error GollumRails::Adapters::Gollum::Error
48
+
49
+ page = {}
50
+ page[:content] = "test"
51
+ @page.update_page(page, @commit).raw_data.should == page[:content]
52
+
53
+ page = {}
54
+ page[:name] = "test"
55
+ @page.update_page(page, @commit).name.should == page[:name]
56
+
57
+ page = {}
58
+ page[:format] = :wiki
59
+ @page.update_page(page, @commit).format.should == :mediawiki
60
+
61
+
62
+
63
+ @page.delete_page(@commit)
64
+ end
65
+ it "should find a page" do
66
+ @page.new_page 'content_page', 'content', :markdown, @commit
67
+
68
+ @page.find_page("content_page")
69
+ @page.delete_page(@commit)
70
+ end
71
+ it "should test the commit methods" do
72
+ @page.new_page 'content_page', 'content', :markdown, @commit
73
+ @page.page_last_edited_date.should be_instance_of Time
74
+ @page.page_created.should be_instance_of Time
75
+ @page.page_last_commit.should be_instance_of Grit::Commit
76
+ @page.page_commit(@page.page.versions.first.id).should be_instance_of Grit::Commit
77
+ @page.page_commit_date(@page.page.versions.first.id).should be_instance_of Time
78
+ @page.page_first_commit.should be_instance_of Grit::Commit
79
+ @page.delete_page(@commit)
80
+ end
81
+ it "should test the error throwing" do
82
+ expect{@page.page_last_commit}.to raise_error GollumRails::Adapters::Gollum::Error
83
+ expect{@page.page_first_commit}.to raise_error GollumRails::Adapters::Gollum::Error
84
+ expect{@page.page_last_edited_date}.to raise_error GollumRails::Adapters::Gollum::Error
85
+ expect{@page.page_created}.to raise_error GollumRails::Adapters::Gollum::Error
86
+ expect{@page.page_commit(1)}.to raise_error GollumRails::Adapters::Gollum::Error
87
+ expect{@page.page_commit_date(1)}.to raise_error GollumRails::Adapters::Gollum::Error
28
88
  end
29
89
  end