gitlab-gollum-rugged_adapter 0.4.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 602fa2fbdbdba48ed81659c65373c3f89f73d245
4
+ data.tar.gz: 84d10ccbcc126577a331e8cf1c598da1f0716c95
5
+ SHA512:
6
+ metadata.gz: 4d75da96e99eba43a6ac0aa4835df66f9716f2df4afe1b89d246f0ab23493c7e08411d20cab75ed5d63f8e5663e968e51f661dec99c7cf92529064079505e5ec
7
+ data.tar.gz: b1686a416eaa3f0a609575042c1e5389d4b9bec438d0410e3cf31dc21accbb2dca0d1aeb3c5b7f99bd28c82c8044257667de04ff960a79ff7af94c9bafcf3832
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+ gem 'rake', '~> 10.4.2'
5
+ gem 'adapter_specs', git: 'https://github.com/gollum/adapter_specs.git'
6
+
7
+ group :test do
8
+ gem "simplecov"
9
+ end
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) Bart Kamphorst, Dawa Ometto
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,44 @@
1
+ [![Gem Version](https://badge.fury.io/rb/gollum-rugged_adapter.svg)](http://badge.fury.io/rb/gollum-rugged_adapter)
2
+ [![Build Status](https://travis-ci.org/gollum/rugged_adapter.svg?branch=master)](https://travis-ci.org/gollum/rugged_adapter)
3
+ [![Dependency Status](https://gemnasium.com/gollum/rugged_adapter.svg)](https://gemnasium.com/gollum/rugged_adapter)
4
+
5
+ ## DESCRIPTION
6
+
7
+ Adapter for [gollum](https://github.com/gollum/gollum) to use [Rugged](https://github.com/libgit2/rugged) (libgit2) at the backend. See the [gollum wiki](https://github.com/gollum/gollum/wiki/Git-adapters) for more information on adapters. Currently gollum uses grit as a backend by default, but since that is abandonware, the plan is to make this adapter the default in the future.
8
+
9
+ **Please note that this adapter is currently in beta. It passes the unit tests for gollum and [gollum-lib](https://github.com/gollum/gollum-lib), but it needs more comprehensive testing. Please [report any issues](https://github.com/gollum/rugged_adapter/issues) that you encounter.**
10
+
11
+ ## USAGE
12
+
13
+ Install the gem:
14
+
15
+ ```bash
16
+ gem install --pre gollum-rugged_adapter # --pre required for beta-releases
17
+ ```
18
+
19
+ Now run gollum as follows:
20
+
21
+ ```bash
22
+ gollum --adapter rugged
23
+ ```
24
+
25
+ ## CONTRIBUTING
26
+
27
+ 1. Start by cloning the repo [on GitHub](http://github.com/gollum/rugged_adapter).
28
+ 2. From inside the repo's directory, install the (development) dependencies with `bundle install`
29
+ 3. Create a thoughtfully named topic branch to contain your changes.
30
+ 4. Hack away.
31
+ 5. Make sure your changes pass the adapter's specs: `bundle exec rake`
32
+ 6. Make sure your changes pass gollum-lib's tests
33
+ * Clone [gollum-lib](https://github.com/gollum/gollum-lib) and add your local version of the rugged adapter to the gollum-lib `Gemfile`:
34
+
35
+ `gem "gollum-rugged_adapter", :path => '/path/to/rugged_adapter'`
36
+ * `bundle install`
37
+ * `bundle exec rake GIT_ADAPTER=rugged`
38
+ 1. If necessary, rebase your commits into logical chunks, without errors.
39
+ 1. Push the branch up to GitHub.
40
+ 1. Send a pull request to the gollum/rugged_adapter project.
41
+
42
+ ## RELEASING
43
+
44
+ This gem uses [Semantic Versioning](http://semver.org/).
data/Rakefile ADDED
@@ -0,0 +1,126 @@
1
+ require 'rubygems'
2
+
3
+ task :default => :rspec
4
+
5
+ require 'rspec/core/rake_task'
6
+
7
+ def name
8
+ "rugged_adapter"
9
+ end
10
+
11
+ def version
12
+ line = File.read("lib/rugged_adapter/version.rb")[/^\s*VERSION\s*=\s*.*/]
13
+ line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
14
+ end
15
+
16
+ # assumes x.y.z all digit version
17
+ def next_version
18
+ # x.y.z
19
+ v = version.split '.'
20
+ # bump z
21
+ v[-1] = v[-1].to_i + 1
22
+ v.join '.'
23
+ end
24
+
25
+ def bump_version
26
+ old_file = File.read("lib/#{name}/version.rb")
27
+ old_version_line = old_file[/^\s*VERSION\s*=\s*.*/]
28
+ new_version = next_version
29
+ # replace first match of old version with new version
30
+ old_file.sub!(old_version_line, " VERSION = '#{new_version}'")
31
+
32
+ File.write("lib/#{name}/version.rb", old_file)
33
+
34
+ new_version
35
+ end
36
+
37
+ def date
38
+ Date.today.to_s
39
+ end
40
+
41
+ def gemspec
42
+ "#{name}.gemspec"
43
+ end
44
+
45
+ def gem_file
46
+ "gollum-#{name}-#{version}.gem"
47
+ end
48
+
49
+ def replace_header(head, header_name)
50
+ head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
51
+ end
52
+
53
+ desc "Run specs."
54
+ RSpec::Core::RakeTask.new(:rspec) do |spec|
55
+ ruby_opts = "-w"
56
+ spec.pattern = 'spec/**/*_spec.rb'
57
+ spec.rspec_opts = ['--backtrace --color']
58
+ end
59
+
60
+ desc "Update version number and gemspec"
61
+ task :bump do
62
+ puts "Updated version to #{bump_version}"
63
+ # Execute does not invoke dependencies.
64
+ # Manually invoke gemspec then validate.
65
+ Rake::Task[:gemspec].execute
66
+ Rake::Task[:validate].execute
67
+ end
68
+
69
+ desc 'Create a release build'
70
+ task :release => :build do
71
+ unless `git branch` =~ /^\* master$/
72
+ puts "You must be on the master branch to release!"
73
+ exit!
74
+ end
75
+ sh "git commit --allow-empty -a -m 'Release #{version}'"
76
+ sh "git pull --rebase origin master"
77
+ sh "git tag v#{version}"
78
+ sh "git push origin master"
79
+ sh "git push origin v#{version}"
80
+ sh "gem push pkg/#{gem_file}"
81
+ end
82
+
83
+ desc 'Publish to rubygems. Same as release'
84
+ task :publish => :release
85
+
86
+ desc 'Build gem'
87
+ task :build => :gemspec do
88
+ sh "mkdir -p pkg"
89
+ sh "gem build #{gemspec}"
90
+ sh "mv #{gem_file} pkg"
91
+ end
92
+
93
+ desc 'Update gemspec'
94
+ task :gemspec => :validate do
95
+ # read spec file and split out manifest section
96
+ spec = File.read(gemspec)
97
+ head, manifest, tail = spec.split(" # = MANIFEST =\n")
98
+
99
+ # replace name version and date
100
+ replace_header(head, :name)
101
+ replace_header(head, :date)
102
+
103
+ # determine file list from git ls-files
104
+ files = `git ls-files`.
105
+ split("\n").
106
+ sort.
107
+ reject { |file| file =~ /^\./ }.
108
+ reject { |file| file =~ /^(rdoc|pkg|spec|\.gitattributes|Guardfile)/ }.
109
+ map { |file| " #{file}" }.
110
+ join("\n")
111
+
112
+ # piece file back together and write
113
+ manifest = " s.files = %w(\n#{files}\n )\n"
114
+ spec = [head, manifest, tail].join(" # = MANIFEST =\n")
115
+ File.open(gemspec, 'w') { |io| io.write(spec) }
116
+ puts "Updated #{gemspec}"
117
+ end
118
+
119
+ desc 'Validate lib files and version file'
120
+ task :validate do
121
+ libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
122
+ unless libfiles.empty?
123
+ puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
124
+ exit!
125
+ end
126
+ end
@@ -0,0 +1 @@
1
+ require 'rugged_adapter/git_layer_rugged.rb'
@@ -0,0 +1,660 @@
1
+ # ~*~ encoding: utf-8 ~*~
2
+
3
+ require 'rugged'
4
+ require 'ostruct'
5
+ require 'mime-types'
6
+
7
+ module Gollum
8
+
9
+ def self.set_git_timeout(time)
10
+ end
11
+
12
+ def self.set_git_max_filesize(size)
13
+ end
14
+
15
+ module Git
16
+
17
+ DEFAULT_MIME_TYPE = "text/plain"
18
+ class NoSuchShaFound < StandardError; end
19
+
20
+ class Actor
21
+
22
+ attr_accessor :name, :email
23
+
24
+ def self.default_actor
25
+ self.new("Gollum", "Gollum@wiki")
26
+ end
27
+
28
+ def initialize(name, email)
29
+ @name = name
30
+ @email = email
31
+ end
32
+
33
+ def output(time)
34
+ # implementation from grit
35
+ offset = time.utc_offset / 60
36
+ "%s <%s> %d %+.2d%.2d" % [
37
+ @name,
38
+ @email || "null",
39
+ time.to_i,
40
+ offset / 60,
41
+ offset.abs % 60]
42
+ end
43
+
44
+ def to_h
45
+ {:name => @name, :email => @email}
46
+ end
47
+
48
+ end
49
+
50
+ class Blob
51
+
52
+ attr_reader :mode
53
+ attr_reader :name
54
+ attr_reader :id
55
+
56
+ def self.create(repo, options)
57
+ blob = repo.git.lookup(options[:id])
58
+ self.new(blob, options)
59
+ end
60
+
61
+ def initialize(blob, options = {})
62
+ @blob = blob
63
+ @mode = options[:mode]
64
+ @name = options[:name]
65
+ @size = options[:size]
66
+ @id = blob.oid
67
+ end
68
+
69
+ def data
70
+ @content ||= @blob.content
71
+ end
72
+
73
+ def is_symlink
74
+ @mode == 0120000
75
+ end
76
+
77
+ def mime_type
78
+ guesses = MIME::Types.type_for(self.name) rescue []
79
+ guesses.first ? guesses.first.simplified : DEFAULT_MIME_TYPE
80
+ end
81
+
82
+ def size
83
+ @size || @blob.size
84
+ end
85
+
86
+ def symlink_target(base_path = nil)
87
+ target = data
88
+ new_path = ::File.expand_path(::File.join('..', target), base_path)
89
+ return new_path if ::File.file? new_path
90
+ nil
91
+ end
92
+ end
93
+
94
+ class Commit
95
+
96
+ def initialize(commit)
97
+ @commit = commit
98
+ end
99
+
100
+ def id
101
+ @commit.oid
102
+ end
103
+ alias_method :sha, :id
104
+ alias_method :to_s, :id
105
+
106
+ attr_reader :commit
107
+
108
+ def author
109
+ @author ||= Gollum::Git::Actor.new(@commit.author[:name], @commit.author[:email])
110
+ end
111
+
112
+ def authored_date
113
+ @commit.author[:time]
114
+ end
115
+
116
+ def message
117
+ @commit.message
118
+ end
119
+
120
+ def tree
121
+ Gollum::Git::Tree.new(@commit.tree)
122
+ end
123
+
124
+ def stats
125
+ @stats ||= build_stats
126
+ end
127
+
128
+ private
129
+
130
+ def build_stats
131
+ additions = 0
132
+ deletions = 0
133
+ total = 0
134
+ files = []
135
+ parent = @commit.parents.first
136
+ diff = Rugged::Tree.diff(@commit.tree.repo, parent ? parent.tree : nil, @commit.tree)
137
+ diff = diff.each_patch do |patch|
138
+ new_additions = patch.stat[1]
139
+ new_deletions = patch.stat[0]
140
+ additions += new_additions
141
+ deletions += new_deletions
142
+ total += patch.changes
143
+ files << [patch.delta.new_file[:path].force_encoding("UTF-8"), new_deletions, new_additions, patch.changes] # Rugged seems to generate the stat diffs in the other direciton than grit does by default, so switch the order of additions and deletions.
144
+ end
145
+ OpenStruct.new(:additions => additions, :deletions => deletions, :files => files, :id => id, :total => total)
146
+ end
147
+
148
+ end
149
+
150
+ class Git
151
+
152
+ # Rugged does not have a Git class, but the Repository class should allows us to do what's necessary.
153
+ def initialize(repo)
154
+ @repo = repo
155
+ end
156
+
157
+ def exist?
158
+ ::File.exists?(@repo.path)
159
+ end
160
+
161
+ def grep(query, options={})
162
+ ref = options[:ref] ? options[:ref] : "HEAD"
163
+ tree = @repo.lookup(sha_from_ref(ref)).tree
164
+ tree = @repo.lookup(tree[options[:path]][:oid]) if options[:path]
165
+ results = []
166
+ tree.walk_blobs(:postorder) do |root, entry|
167
+ blob = @repo.lookup(entry[:oid])
168
+ count = 0
169
+ blob.content.each_line do |line|
170
+ next unless line.force_encoding("UTF-8").match(/#{Regexp.escape(query)}/i)
171
+ count += 1
172
+ end
173
+ path = options[:path] ? ::File.join(options[:path], root, entry[:name]) : "#{root}#{entry[:name]}"
174
+ results << {:name => path, :count => count} unless count == 0
175
+ end
176
+ results
177
+ end
178
+
179
+ def rm(path, options = {})
180
+ index = @repo.index
181
+ index.write
182
+ ::File.unlink ::File.join(@repo.workdir, path)
183
+ end
184
+
185
+ def cat_file(options, sha)
186
+ @repo.lookup(sha).read_raw
187
+ end
188
+
189
+ def apply_patch(head_sha = 'HEAD', patch=nil)
190
+ false # Rewrite gollum-lib's revert so that it doesn't require a direct equivalent of Grit's apply_patch
191
+ end
192
+
193
+ def revert(path, sha1, sha2, ref)
194
+ # FIXME: See https://github.com/gollum/grit_adapter/pull/14
195
+ fail NotImplementedError
196
+ end
197
+
198
+ def checkout(path, ref = 'HEAD', options = {})
199
+ path = path.nil? ? path : [path]
200
+ options = options.merge({:paths => path, :strategy => :force})
201
+ if ref == 'HEAD'
202
+ @repo.checkout_head(options)
203
+ else
204
+ ref = "refs/heads/#{ref}" unless ref =~ /^refs\/heads\//
205
+ @repo.checkout_tree(sha_from_ref(ref), options)
206
+ end
207
+ end
208
+
209
+ def log(ref = 'refs/heads/master', path = nil, options = {})
210
+ default_options = {
211
+ :limit => options[:max_count] ? options[:max_count] : 10,
212
+ :offset => options[:skip] ? options[:skip] : 0,
213
+ :path => path,
214
+ :follow => false,
215
+ :skip_merges => false
216
+ }
217
+ options = default_options.merge(options)
218
+ options[:limit] ||= 0
219
+ options[:offset] ||= 0
220
+ sha = sha_from_ref(ref)
221
+ return [] if sha.nil?
222
+ begin
223
+ build_log(sha, options)
224
+ rescue Rugged::OdbError, Rugged::InvalidError, Rugged::ReferenceError
225
+ # Return an empty array if the ref wasn't found
226
+ []
227
+ end
228
+ end
229
+
230
+ def versions_for_path(path = nil, ref = nil, options = {})
231
+ log(ref, path, options)
232
+ end
233
+
234
+ def ls_files(query, options = {})
235
+ ref = options[:ref] || "refs/heads/master"
236
+ tree = @repo.lookup(sha_from_ref(ref)).tree
237
+ tree = @repo.lookup(tree[options[:path]][:oid]) if options[:path]
238
+ results = []
239
+ tree.walk_blobs do |root, blob|
240
+ next unless blob[:name] =~ /#{query}/
241
+ path = options[:path] ? ::File.join(options[:path], root, blob[:name]) : "#{root}#{blob[:name]}"
242
+ results << path
243
+ end
244
+ results
245
+ end
246
+
247
+ def lookup(id)
248
+ @repo.lookup(id)
249
+ end
250
+
251
+ def ref_to_sha(query)
252
+ return query if sha?(query)
253
+ query = "refs/heads/#{query}" if !query.nil? && !(query =~ /^refs\/heads\//) && !(query == "HEAD")
254
+ begin
255
+ return @repo.rev_parse_oid(query)
256
+ rescue Rugged::ReferenceError, Rugged::InvalidError
257
+ return nil
258
+ end
259
+ end
260
+
261
+ def sha_or_commit_from_ref(ref, request_kind = nil)
262
+ sha = ref_to_sha(ref)
263
+ return nil if sha.nil?
264
+ object = @repo.lookup(sha)
265
+ if object.kind_of?(Rugged::Commit) then
266
+ return Gollum::Git::Commit.new(object) if request_kind == :commit
267
+ sha
268
+ elsif object.respond_to?(:target)
269
+ sha_or_commit_from_ref(object.target.oid, request_kind)
270
+ end
271
+ end
272
+ alias_method :sha_from_ref, :sha_or_commit_from_ref
273
+
274
+ def commit_from_ref(ref)
275
+ sha_or_commit_from_ref(ref, :commit)
276
+ end
277
+
278
+ def push(remote, branches = nil, options = {})
279
+ branches = [branches].flatten.map {|branch| "refs/heads/#{branch}" unless branch =~ /^refs\/heads\//}
280
+ @repo.push(remote, branches, options)
281
+ end
282
+
283
+ def pull(remote, branches = nil, options = {})
284
+ branches = [branches].flatten.map {|branch| "refs/heads/#{branch}" unless branch =~ /^refs\/heads\//}
285
+ r = @repo.remotes[remote]
286
+ r.fetch(branches, options)
287
+ branches.each do |branch|
288
+ branch_name = branch.match(/^refs\/heads\/(.*)/)[1]
289
+ remote_name = remote.match(/^(refs\/heads\/)?(.*)/)[2]
290
+ remote_ref = @repo.branches["#{remote_name}/#{branch_name}"].target
291
+ local_ref = @repo.branches[branch].target
292
+ index = @repo.merge_commits(local_ref, remote_ref)
293
+ options = { author: Actor.default_actor.to_h,
294
+ committer: Actor.default_actor.to_h,
295
+ message: "Merged branch #{branch} of #{remote}.",
296
+ parents: [local_ref, remote_ref],
297
+ tree: index.write_tree(@repo),
298
+ update_ref: branch
299
+ }
300
+ Rugged::Commit.create @repo, options
301
+ @repo.checkout(@repo.head.name, :strategy => :force) if !@repo.bare? && branch == @repo.head.name
302
+ end
303
+ end
304
+
305
+ private
306
+
307
+ def sha?(str)
308
+ !!(str =~ /^[0-9a-f]{40}$/)
309
+ end
310
+
311
+ # Return an array of log commits, given an SHA hash and a hash of
312
+ # options. From Gitlab::Git
313
+ def build_log(sha, options)
314
+ # Instantiate a Walker and add the SHA hash
315
+ walker = Rugged::Walker.new(@repo)
316
+ walker.push(sha)
317
+ commits = []
318
+ skipped = 0
319
+ current_path = options[:path]
320
+ current_path = nil if current_path == ''
321
+ limit = options[:limit].to_i
322
+ offset = options[:offset].to_i
323
+ skip_merges = options[:skip_merges]
324
+ walker.sorting(Rugged::SORT_DATE)
325
+
326
+ walker.each do |c|
327
+ break if limit > 0 && commits.length >= limit
328
+ if skip_merges
329
+ # Skip merge commits
330
+ next if c.parents.length > 1
331
+ end
332
+
333
+ if !current_path ||
334
+ commit_touches_path?(c, current_path, options[:follow], walker)
335
+ # This is a commit we care about, unless we haven't skipped enough
336
+ # yet
337
+ skipped += 1
338
+ commits.push(Gollum::Git::Commit.new(c)) if skipped > offset
339
+ end
340
+ end
341
+ walker.reset
342
+ commits
343
+ end
344
+
345
+ # Returns true if +commit+ introduced changes to +path+, using commit
346
+ # trees to make that determination. Uses the history simplification
347
+ # rules that `git log` uses by default, where a commit is omitted if it
348
+ # is TREESAME to any parent.
349
+ #
350
+ # If the +follow+ option is true and the file specified by +path+ was
351
+ # renamed, then the path value is set to the old path.
352
+ def commit_touches_path?(commit, path, follow, walker)
353
+ entry = tree_entry(commit, path)
354
+
355
+ if commit.parents.empty?
356
+ # This is the root commit, return true if it has +path+ in its tree
357
+ return entry != nil
358
+ end
359
+
360
+ num_treesame = 0
361
+ commit.parents.each do |parent|
362
+ parent_entry = tree_entry(parent, path)
363
+
364
+ # Only follow the first TREESAME parent for merge commits
365
+ if num_treesame > 0
366
+ walker.hide(parent)
367
+ next
368
+ end
369
+
370
+ if entry.nil? && parent_entry.nil?
371
+ num_treesame += 1
372
+ elsif entry && parent_entry && entry[:oid] == parent_entry[:oid]
373
+ num_treesame += 1
374
+ end
375
+ end
376
+
377
+ case num_treesame
378
+ when 0
379
+ detect_rename(commit, commit.parents.first, path) if follow
380
+ true
381
+ else false
382
+ end
383
+ end
384
+
385
+ # Find the entry for +path+ in the tree for +commit+
386
+ def tree_entry(commit, path)
387
+ pathname = Pathname.new(path)
388
+ tmp_entry = nil
389
+
390
+ pathname.each_filename do |dir|
391
+ tmp_entry = if tmp_entry.nil?
392
+ commit.tree[dir]
393
+ else
394
+ @repo.lookup(tmp_entry[:oid])[dir]
395
+ end
396
+
397
+ return nil unless tmp_entry
398
+ end
399
+ tmp_entry
400
+ end
401
+
402
+ # Compare +commit+ and +parent+ for +path+. If +path+ is a file and was
403
+ # renamed in +commit+, then set +path+ to the old filename.
404
+ def detect_rename(commit, parent, path)
405
+ diff = parent.diff(commit, paths: [path], disable_pathspec_match: true)
406
+
407
+ # If +path+ is a filename, not a directory, then we should only have
408
+ # one delta. We don't need to follow renames for directories.
409
+ return nil if diff.each_delta.count > 1
410
+
411
+ delta = diff.each_delta.first
412
+ if delta.added?
413
+ full_diff = parent.diff(commit)
414
+ full_diff.find_similar!
415
+
416
+ full_diff.each_delta do |full_delta|
417
+ if full_delta.renamed? && path == full_delta.new_file[:path]
418
+ # Look for the old path in ancestors
419
+ path.replace(full_delta.old_file[:path])
420
+ end
421
+ end
422
+ end
423
+ end
424
+
425
+ end
426
+
427
+ class Index
428
+
429
+ def initialize(index, repo)
430
+ @index = index
431
+ @rugged_repo = repo
432
+ @treemap = {}
433
+ end
434
+
435
+ def delete(path)
436
+ @index.remove_all(path)
437
+ update_treemap(path, false)
438
+ false
439
+ end
440
+
441
+ def add(path, data)
442
+ blob = @rugged_repo.write(data, :blob)
443
+ @index.add(:path => path, :oid => blob, :mode => 0100644)
444
+ update_treemap(path, data)
445
+ data
446
+ end
447
+
448
+ def index
449
+ @index
450
+ end
451
+
452
+ def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'refs/heads/master')
453
+ commit_options = {}
454
+ head = "refs/heads/#{head}" if head && head !~ %r(^refs/heads/)
455
+ parents = get_parents(parents, head) || []
456
+ actor = Gollum::Git::Actor.default_actor if actor.nil?
457
+ commit_options[:tree] = @index.write_tree
458
+ commit_options[:author] = actor.to_h
459
+ commit_options[:committer] = actor.to_h
460
+ commit_options[:message] = message.to_s
461
+ commit_options[:parents] = parents
462
+ commit_options[:update_ref] = head
463
+ Rugged::Commit.create(@rugged_repo, commit_options)
464
+ end
465
+
466
+ def tree
467
+ @treemap
468
+ end
469
+
470
+ def read_tree(id)
471
+ id = Gollum::Git::Git.new(@rugged_repo).ref_to_sha(id)
472
+ return nil if id.nil?
473
+ current_tree = @rugged_repo.lookup(id)
474
+ current_tree = current_tree.tree unless current_tree.is_a?(Rugged::Tree)
475
+ @index.read_tree(current_tree)
476
+ @current_tree = Gollum::Git::Tree.new(current_tree)
477
+ end
478
+
479
+ def current_tree
480
+ @current_tree
481
+ end
482
+
483
+ private
484
+
485
+ def get_parents(parents, head)
486
+ if parents
487
+ parents.map{|parent| parent.commit}
488
+ elsif ref = @rugged_repo.references[head]
489
+ ref = ref.target
490
+ ref = ref.target if ref.respond_to?(:target)
491
+ [ref]
492
+ end
493
+ end
494
+
495
+ def update_treemap(path, data)
496
+ # From RJGit::Plumbing::Index
497
+ path = path[1..-1] if path[0] == ::File::SEPARATOR
498
+ path = path.split(::File::SEPARATOR)
499
+ last = path.pop
500
+
501
+ current = @treemap
502
+
503
+ path.each do |dir|
504
+ current[dir] ||= {}
505
+ node = current[dir]
506
+ current = node
507
+ end
508
+
509
+ current[last] = data
510
+ @treemap
511
+ end
512
+
513
+ end
514
+
515
+ class Ref
516
+ def initialize(ref)
517
+ @ref = ref
518
+ end
519
+
520
+ def name
521
+ @ref.name
522
+ end
523
+
524
+ def commit
525
+ Gollum::Git::Commit.new(@ref.target)
526
+ end
527
+
528
+ end
529
+
530
+ class Repo
531
+
532
+ def initialize(path, options)
533
+ begin
534
+ @repo = Rugged::Repository.new(path, options)
535
+ #rescue Grit::InvalidGitRepositoryError
536
+ # raise Gollum::InvalidGitRepositoryError
537
+ #rescue Grit::NoSuchPathError
538
+ # raise Gollum::NoSuchPathError
539
+ end
540
+ end
541
+
542
+ def self.init(path)
543
+ Rugged::Repository.init_at(path, false)
544
+ self.new(path, :is_bare => false)
545
+ end
546
+
547
+ def self.init_bare(path)
548
+ Rugged::Repository.init_at(path, true)
549
+ self.new(path, :is_bare => true)
550
+ end
551
+
552
+ def bare
553
+ @repo.bare?
554
+ end
555
+
556
+ def config
557
+ @repo.config
558
+ end
559
+
560
+ def git
561
+ @git ||= Gollum::Git::Git.new(@repo)
562
+ end
563
+
564
+ def commit(id)
565
+ git.commit_from_ref(id)
566
+ end
567
+
568
+ def commits(start = 'refs/heads/master', max_count = 10, skip = 0)
569
+ git.log(start, nil, :max_count => max_count, :skip => skip)
570
+ end
571
+
572
+ def head
573
+ Gollum::Git::Ref.new(@repo.head)
574
+ end
575
+
576
+ def index
577
+ @index ||= Gollum::Git::Index.new(@repo.index, @repo)
578
+ end
579
+
580
+ def diff(sha1, sha2, *paths)
581
+ opts = path == nil ? {} : {:path => path}
582
+ patches = @repo.diff(sha1, sha2, opts).patches
583
+ if not paths.empty?
584
+ patches.keep_if { |p| paths.include? p.delta.new_file[:path] }
585
+ end
586
+ patches.map {|patch| OpenStruct.new(:diff => patch.to_s.split("\n")[2..-1].join("\n").force_encoding("UTF-8"))}.reverse # First remove two superfluous lines. Rugged seems to order the diffs differently than Grit, so reverse.
587
+ end
588
+
589
+ def log(commit = 'refs/heads/master', path = nil, options = {})
590
+ git.log(commit, path, options)
591
+ end
592
+
593
+ def lstree(sha, options = {})
594
+ results = []
595
+ @repo.lookup(sha).tree.walk(:postorder) do |root, entry|
596
+ entry[:sha] = entry[:oid]
597
+ entry[:mode] = entry[:filemode].to_s(8)
598
+ entry[:type] = entry[:type].to_s
599
+ entry[:path] = "#{root}#{entry[:name]}"
600
+ results << entry
601
+ end
602
+ results
603
+ end
604
+
605
+ def path
606
+ @repo.path
607
+ end
608
+
609
+ # Checkout branch and if necessary first create it. Currently used only in gollum-lib's tests.
610
+ def update_ref(ref, commit_sha)
611
+ ref = "refs/heads/#{ref}" unless ref =~ /^refs\/heads\//
612
+ if _ref = @repo.references[ref]
613
+ @repo.references.update(_ref, commit_sha)
614
+ else
615
+ @repo.create_branch(ref, commit_sha)
616
+ @repo.checkout(ref, :strategy => :force) unless @repo.bare?
617
+ end
618
+ end
619
+ end
620
+
621
+ class Tree
622
+
623
+ def initialize(tree)
624
+ @tree = tree
625
+ end
626
+
627
+ def keys
628
+ @tree.map{|entry| entry[:name]}
629
+ end
630
+
631
+ def [](i)
632
+ @tree[i]
633
+ end
634
+
635
+ def id
636
+ @tree.oid
637
+ end
638
+
639
+ def /(file)
640
+ return self if file == '/'
641
+ begin
642
+ obj = @tree.path(file)
643
+ rescue Rugged::TreeError
644
+ return nil
645
+ end
646
+ return nil if obj.nil?
647
+ obj = @tree.owner.lookup(obj[:oid])
648
+ obj.is_a?(Rugged::Tree) ? Gollum::Git::Tree.new(obj) : Gollum::Git::Blob.new(obj)
649
+ end
650
+
651
+ def blobs
652
+ blobs = []
653
+ @tree.each_blob {|blob| blobs << Gollum::Git::Blob.new(@tree.owner.lookup(blob[:oid]), blob) }
654
+ blobs
655
+ end
656
+
657
+ end
658
+
659
+ end
660
+ end
@@ -0,0 +1,7 @@
1
+ module Gollum
2
+ module Lib
3
+ module Git
4
+ VERSION = '0.4.4'
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "rugged_adapter/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "gitlab-gollum-rugged_adapter"
7
+ s.version = Gollum::Lib::Git::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ["Bart Kamphorst, Dawa Ometto"]
10
+ s.email = ["fjlopez@gitlab.com"]
11
+ s.homepage = "https://gitlab.com/gitlab-org/gitlab-gollum-rugged_adapter"
12
+ s.summary = %q{Adapter for Gollum to use Rugged (libgit2) at the backend.}
13
+ s.description = %q{Adapter for Gollum to use Rugged (libgit2) at the backend.}
14
+ s.license = "MIT"
15
+
16
+ s.add_runtime_dependency 'rugged', '~> 0.25'
17
+ s.add_runtime_dependency 'mime-types', '>= 1.15'
18
+ s.add_development_dependency "rspec", "3.4.0"
19
+
20
+ s.files = Dir['lib/**/*.rb'] + ["README.md", "Gemfile"]
21
+ s.require_paths = ["lib"]
22
+
23
+ # = MANIFEST =
24
+ s.files = %w(
25
+ Gemfile
26
+ LICENSE
27
+ README.md
28
+ Rakefile
29
+ lib/rugged_adapter.rb
30
+ lib/rugged_adapter/git_layer_rugged.rb
31
+ lib/rugged_adapter/version.rb
32
+ rugged_adapter.gemspec
33
+ )
34
+ # = MANIFEST =
35
+
36
+ end
metadata ADDED
@@ -0,0 +1,94 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: gitlab-gollum-rugged_adapter
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.4
5
+ platform: ruby
6
+ authors:
7
+ - Bart Kamphorst, Dawa Ometto
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2018-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rugged
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.25'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.25'
27
+ - !ruby/object:Gem::Dependency
28
+ name: mime-types
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '1.15'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '1.15'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 3.4.0
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 3.4.0
55
+ description: Adapter for Gollum to use Rugged (libgit2) at the backend.
56
+ email:
57
+ - fjlopez@gitlab.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - Gemfile
63
+ - LICENSE
64
+ - README.md
65
+ - Rakefile
66
+ - lib/rugged_adapter.rb
67
+ - lib/rugged_adapter/git_layer_rugged.rb
68
+ - lib/rugged_adapter/version.rb
69
+ - rugged_adapter.gemspec
70
+ homepage: https://gitlab.com/gitlab-org/gitlab-gollum-rugged_adapter
71
+ licenses:
72
+ - MIT
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubyforge_project:
90
+ rubygems_version: 2.5.2
91
+ signing_key:
92
+ specification_version: 4
93
+ summary: Adapter for Gollum to use Rugged (libgit2) at the backend.
94
+ test_files: []