smeagol 0.6.0 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/.index +82 -0
  3. data/HISTORY.md +14 -0
  4. data/lib/smeagol.rb +2 -1
  5. data/lib/smeagol/app.rb +1 -1
  6. data/lib/smeagol/gollum/file.rb +1 -1
  7. data/lib/smeagol/wiki.rb +1 -0
  8. data/vendor/grit/lib/grit.rb +75 -0
  9. data/vendor/grit/lib/grit/actor.rb +52 -0
  10. data/vendor/grit/lib/grit/blame.rb +70 -0
  11. data/vendor/grit/lib/grit/blob.rb +126 -0
  12. data/vendor/grit/lib/grit/commit.rb +313 -0
  13. data/vendor/grit/lib/grit/commit_stats.rb +128 -0
  14. data/vendor/grit/lib/grit/config.rb +44 -0
  15. data/vendor/grit/lib/grit/diff.rb +79 -0
  16. data/vendor/grit/lib/grit/errors.rb +10 -0
  17. data/vendor/grit/lib/grit/git-ruby.rb +262 -0
  18. data/vendor/grit/lib/grit/git-ruby/commit_db.rb +52 -0
  19. data/vendor/grit/lib/grit/git-ruby/git_object.rb +353 -0
  20. data/vendor/grit/lib/grit/git-ruby/internal/file_window.rb +58 -0
  21. data/vendor/grit/lib/grit/git-ruby/internal/loose.rb +137 -0
  22. data/vendor/grit/lib/grit/git-ruby/internal/pack.rb +397 -0
  23. data/vendor/grit/lib/grit/git-ruby/internal/raw_object.rb +44 -0
  24. data/vendor/grit/lib/grit/git-ruby/repository.rb +775 -0
  25. data/vendor/grit/lib/grit/git.rb +501 -0
  26. data/vendor/grit/lib/grit/index.rb +222 -0
  27. data/vendor/grit/lib/grit/lazy.rb +35 -0
  28. data/vendor/grit/lib/grit/merge.rb +45 -0
  29. data/vendor/grit/lib/grit/ref.rb +78 -0
  30. data/vendor/grit/lib/grit/repo.rb +709 -0
  31. data/vendor/grit/lib/grit/ruby1.9.rb +7 -0
  32. data/vendor/grit/lib/grit/status.rb +153 -0
  33. data/vendor/grit/lib/grit/submodule.rb +88 -0
  34. data/vendor/grit/lib/grit/tag.rb +102 -0
  35. data/vendor/grit/lib/grit/tree.rb +125 -0
  36. metadata +125 -56
  37. data/.ruby +0 -80
@@ -0,0 +1,501 @@
1
+ require 'tempfile'
2
+ require 'posix-spawn'
3
+ module Grit
4
+
5
+ class Git
6
+ include POSIX::Spawn
7
+
8
+ class GitTimeout < RuntimeError
9
+ attr_accessor :command
10
+ attr_accessor :bytes_read
11
+
12
+ def initialize(command = nil, bytes_read = nil)
13
+ @command = command
14
+ @bytes_read = bytes_read
15
+ end
16
+ end
17
+
18
+ # Raised when a native git command exits with non-zero.
19
+ class CommandFailed < StandardError
20
+ # The full git command that failed as a String.
21
+ attr_reader :command
22
+
23
+ # The integer exit status.
24
+ attr_reader :exitstatus
25
+
26
+ # Everything output on the command's stderr as a String.
27
+ attr_reader :err
28
+
29
+ def initialize(command, exitstatus=nil, err='')
30
+ if exitstatus
31
+ @command = command
32
+ @exitstatus = exitstatus
33
+ @err = err
34
+ message = "Command failed [#{exitstatus}]: #{command}"
35
+ message << "\n\n" << err unless err.nil? || err.empty?
36
+ super message
37
+ else
38
+ super command
39
+ end
40
+ end
41
+ end
42
+
43
+ undef_method :clone
44
+
45
+ include GitRuby
46
+
47
+ def exist?
48
+ File.exist?(self.git_dir)
49
+ end
50
+
51
+ def put_raw_object(content, type)
52
+ ruby_git.put_raw_object(content, type)
53
+ end
54
+
55
+ def get_raw_object(object_id)
56
+ ruby_git.get_raw_object_by_sha1(object_id).content
57
+ end
58
+
59
+ def get_git_object(object_id)
60
+ ruby_git.get_raw_object_by_sha1(object_id).to_hash
61
+ end
62
+
63
+ def object_exists?(object_id)
64
+ ruby_git.object_exists?(object_id)
65
+ end
66
+
67
+ def select_existing_objects(object_ids)
68
+ object_ids.select do |object_id|
69
+ object_exists?(object_id)
70
+ end
71
+ end
72
+
73
+ class << self
74
+ attr_accessor :git_timeout, :git_max_size
75
+ def git_binary
76
+ @git_binary ||=
77
+ ENV['PATH'].split(':').
78
+ map { |p| File.join(p, 'git') }.
79
+ find { |p| File.exist?(p) }
80
+ end
81
+ attr_writer :git_binary
82
+ end
83
+
84
+ self.git_timeout = 10
85
+ self.git_max_size = 5242880 # 5.megabytes
86
+
87
+ def self.with_timeout(timeout = 10)
88
+ old_timeout = Grit::Git.git_timeout
89
+ Grit::Git.git_timeout = timeout
90
+ yield
91
+ Grit::Git.git_timeout = old_timeout
92
+ end
93
+
94
+ attr_accessor :git_dir, :bytes_read, :work_tree
95
+
96
+ def initialize(git_dir)
97
+ self.git_dir = git_dir
98
+ self.work_tree = git_dir.gsub(/\/\.git$/,'')
99
+ self.bytes_read = 0
100
+ end
101
+
102
+ def shell_escape(str)
103
+ str.to_s.gsub("'", "\\\\'").gsub(";", '\\;')
104
+ end
105
+ alias_method :e, :shell_escape
106
+
107
+ # Check if a normal file exists on the filesystem
108
+ # +file+ is the relative path from the Git dir
109
+ #
110
+ # Returns Boolean
111
+ def fs_exist?(file)
112
+ File.exist?(File.join(self.git_dir, file))
113
+ end
114
+
115
+ # Read a normal file from the filesystem.
116
+ # +file+ is the relative path from the Git dir
117
+ #
118
+ # Returns the String contents of the file
119
+ def fs_read(file)
120
+ File.read(File.join(self.git_dir, file))
121
+ end
122
+
123
+ # Write a normal file to the filesystem.
124
+ # +file+ is the relative path from the Git dir
125
+ # +contents+ is the String content to be written
126
+ #
127
+ # Returns nothing
128
+ def fs_write(file, contents)
129
+ path = File.join(self.git_dir, file)
130
+ FileUtils.mkdir_p(File.dirname(path))
131
+ File.open(path, 'w') do |f|
132
+ f.write(contents)
133
+ end
134
+ end
135
+
136
+ # Delete a normal file from the filesystem
137
+ # +file+ is the relative path from the Git dir
138
+ #
139
+ # Returns nothing
140
+ def fs_delete(file)
141
+ FileUtils.rm_rf(File.join(self.git_dir, file))
142
+ end
143
+
144
+ # Move a normal file
145
+ # +from+ is the relative path to the current file
146
+ # +to+ is the relative path to the destination file
147
+ #
148
+ # Returns nothing
149
+ def fs_move(from, to)
150
+ FileUtils.mv(File.join(self.git_dir, from), File.join(self.git_dir, to))
151
+ end
152
+
153
+ # Make a directory
154
+ # +dir+ is the relative path to the directory to create
155
+ #
156
+ # Returns nothing
157
+ def fs_mkdir(dir)
158
+ FileUtils.mkdir_p(File.join(self.git_dir, dir))
159
+ end
160
+
161
+ # Chmod the the file or dir and everything beneath
162
+ # +file+ is the relative path from the Git dir
163
+ #
164
+ # Returns nothing
165
+ def fs_chmod(mode, file = '/')
166
+ FileUtils.chmod_R(mode, File.join(self.git_dir, file))
167
+ end
168
+
169
+ def list_remotes
170
+ remotes = []
171
+ Dir.chdir(File.join(self.git_dir, 'refs/remotes')) do
172
+ remotes = Dir.glob('*')
173
+ end
174
+ remotes
175
+ rescue
176
+ []
177
+ end
178
+
179
+ def create_tempfile(seed, unlink = false)
180
+ path = Tempfile.new(seed).path
181
+ File.unlink(path) if unlink
182
+ return path
183
+ end
184
+
185
+ def commit_from_sha(id)
186
+ git_ruby_repo = GitRuby::Repository.new(self.git_dir)
187
+ object = git_ruby_repo.get_object_by_sha1(id)
188
+
189
+ if object.type == :commit
190
+ id
191
+ elsif object.type == :tag
192
+ object.object
193
+ else
194
+ ''
195
+ end
196
+ end
197
+
198
+ # Checks if the patch of a commit can be applied to the given head.
199
+ #
200
+ # options - grit command options hash
201
+ # head_sha - String SHA or ref to check the patch against.
202
+ # applies_sha - String SHA of the patch. The patch itself is retrieved
203
+ # with #get_patch.
204
+ #
205
+ # Returns 0 if the patch applies cleanly (according to `git apply`), or
206
+ # an Integer that is the sum of the failed exit statuses.
207
+ def check_applies(options={}, head_sha=nil, applies_sha=nil)
208
+ options, head_sha, applies_sha = {}, options, head_sha if !options.is_a?(Hash)
209
+ options = options.dup
210
+ options[:env] &&= options[:env].dup
211
+
212
+ git_index = create_tempfile('index', true)
213
+ (options[:env] ||= {}).merge!('GIT_INDEX_FILE' => git_index)
214
+ options[:raise] = true
215
+
216
+ status = 0
217
+ begin
218
+ native(:read_tree, options.dup, head_sha)
219
+ stdin = native(:diff, options.dup, "#{applies_sha}^", applies_sha)
220
+ native(:apply, options.merge(:check => true, :cached => true, :input => stdin))
221
+ rescue CommandFailed => fail
222
+ status += fail.exitstatus
223
+ end
224
+ status
225
+ end
226
+
227
+ # Gets a patch for a given SHA using `git diff`.
228
+ #
229
+ # options - grit command options hash
230
+ # applies_sha - String SHA to get the patch from, using this command:
231
+ # `git diff #{applies_sha}^ #{applies_sha}`
232
+ #
233
+ # Returns the String patch from `git diff`.
234
+ def get_patch(options={}, applies_sha=nil)
235
+ options, applies_sha = {}, options if !options.is_a?(Hash)
236
+ options = options.dup
237
+ options[:env] &&= options[:env].dup
238
+
239
+ git_index = create_tempfile('index', true)
240
+ (options[:env] ||= {}).merge!('GIT_INDEX_FILE' => git_index)
241
+
242
+ native(:diff, options, "#{applies_sha}^", applies_sha)
243
+ end
244
+
245
+ # Applies the given patch against the given SHA of the current repo.
246
+ #
247
+ # options - grit command hash
248
+ # head_sha - String SHA or ref to apply the patch to.
249
+ # patch - The String patch to apply. Get this from #get_patch.
250
+ #
251
+ # Returns the String Tree SHA on a successful patch application, or false.
252
+ def apply_patch(options={}, head_sha=nil, patch=nil)
253
+ options, head_sha, patch = {}, options, head_sha if !options.is_a?(Hash)
254
+ options = options.dup
255
+ options[:env] &&= options[:env].dup
256
+ options[:raise] = true
257
+
258
+ git_index = create_tempfile('index', true)
259
+ (options[:env] ||= {}).merge!('GIT_INDEX_FILE' => git_index)
260
+
261
+ begin
262
+ native(:read_tree, options.dup, head_sha)
263
+ native(:apply, options.merge(:cached => true, :input => patch))
264
+ rescue CommandFailed
265
+ return false
266
+ end
267
+ native(:write_tree, :env => options[:env]).to_s.chomp!
268
+ end
269
+
270
+ # Execute a git command, bypassing any library implementation.
271
+ #
272
+ # cmd - The name of the git command as a Symbol. Underscores are
273
+ # converted to dashes as in :rev_parse => 'rev-parse'.
274
+ # options - Command line option arguments passed to the git command.
275
+ # Single char keys are converted to short options (:a => -a).
276
+ # Multi-char keys are converted to long options (:arg => '--arg').
277
+ # Underscores in keys are converted to dashes. These special options
278
+ # are used to control command execution and are not passed in command
279
+ # invocation:
280
+ # :timeout - Maximum amount of time the command can run for before
281
+ # being aborted. When true, use Grit::Git.git_timeout; when numeric,
282
+ # use that number of seconds; when false or 0, disable timeout.
283
+ # :base - Set false to avoid passing the --git-dir argument when
284
+ # invoking the git command.
285
+ # :env - Hash of environment variable key/values that are set on the
286
+ # child process.
287
+ # :raise - When set true, commands that exit with a non-zero status
288
+ # raise a CommandFailed exception. This option is available only on
289
+ # platforms that support fork(2).
290
+ # :process_info - By default, a single string with output written to
291
+ # the process's stdout is returned. Setting this option to true
292
+ # results in a [exitstatus, out, err] tuple being returned instead.
293
+ # args - Non-option arguments passed on the command line.
294
+ #
295
+ # Optionally yields to the block an IO object attached to the child
296
+ # process's STDIN.
297
+ #
298
+ # Examples
299
+ # git.native(:rev_list, {:max_count => 10, :header => true}, "master")
300
+ #
301
+ # Returns a String with all output written to the child process's stdout
302
+ # when the :process_info option is not set.
303
+ # Returns a [exitstatus, out, err] tuple when the :process_info option is
304
+ # set. The exitstatus is an small integer that was the process's exit
305
+ # status. The out and err elements are the data written to stdout and
306
+ # stderr as Strings.
307
+ # Raises Grit::Git::GitTimeout when the timeout is exceeded or when more
308
+ # than Grit::Git.git_max_size bytes are output.
309
+ # Raises Grit::Git::CommandFailed when the :raise option is set true and the
310
+ # git command exits with a non-zero exit status. The CommandFailed's #command,
311
+ # #exitstatus, and #err attributes can be used to retrieve additional
312
+ # detail about the error.
313
+ def native(cmd, options = {}, *args, &block)
314
+ args = args.first if args.size == 1 && args[0].is_a?(Array)
315
+ args.map! { |a| a.to_s }
316
+ args.reject! { |a| a.empty? }
317
+
318
+ # special option arguments
319
+ env = options.delete(:env) || {}
320
+ raise_errors = options.delete(:raise)
321
+ process_info = options.delete(:process_info)
322
+
323
+ # fall back to using a shell when the last argument looks like it wants to
324
+ # start a pipeline for compatibility with previous versions of grit.
325
+ return run(prefix, cmd, '', options, args) if args[-1].to_s[0] == ?|
326
+
327
+ # more options
328
+ input = options.delete(:input)
329
+ timeout = options.delete(:timeout); timeout = true if timeout.nil?
330
+ base = options.delete(:base); base = true if base.nil?
331
+ chdir = options.delete(:chdir)
332
+
333
+ # build up the git process argv
334
+ argv = []
335
+ argv << Git.git_binary
336
+ argv << "--git-dir=#{git_dir}" if base
337
+ argv << cmd.to_s.tr('_', '-')
338
+ argv.concat(options_to_argv(options))
339
+ argv.concat(args)
340
+
341
+ # run it and deal with fallout
342
+ Grit.log(argv.join(' ')) if Grit.debug
343
+
344
+ process =
345
+ Child.new(env, *(argv + [{
346
+ :input => input,
347
+ :chdir => chdir,
348
+ :timeout => (Grit::Git.git_timeout if timeout == true),
349
+ :max => (Grit::Git.git_max_size if timeout == true)
350
+ }]))
351
+ Grit.log(process.out) if Grit.debug
352
+ Grit.log(process.err) if Grit.debug
353
+
354
+ status = process.status
355
+ if raise_errors && !status.success?
356
+ raise CommandFailed.new(argv.join(' '), status.exitstatus, process.err)
357
+ elsif process_info
358
+ [status.exitstatus, process.out, process.err]
359
+ else
360
+ process.out
361
+ end
362
+ rescue TimeoutExceeded, MaximumOutputExceeded
363
+ raise GitTimeout, argv.join(' ')
364
+ end
365
+
366
+ # Methods not defined by a library implementation execute the git command
367
+ # using #native, passing the method name as the git command name.
368
+ #
369
+ # Examples:
370
+ # git.rev_list({:max_count => 10, :header => true}, "master")
371
+ def method_missing(cmd, options={}, *args, &block)
372
+ native(cmd, options, *args, &block)
373
+ end
374
+
375
+ # Transform a ruby-style options hash to command-line arguments sutiable for
376
+ # use with Kernel::exec. No shell escaping is performed.
377
+ #
378
+ # Returns an Array of String option arguments.
379
+ def options_to_argv(options)
380
+ argv = []
381
+ options.each do |key, val|
382
+ if key.to_s.size == 1
383
+ if val == true
384
+ argv << "-#{key}"
385
+ elsif val == false
386
+ # ignore
387
+ else
388
+ argv << "-#{key}"
389
+ argv << val.to_s
390
+ end
391
+ else
392
+ if val == true
393
+ argv << "--#{key.to_s.tr('_', '-')}"
394
+ elsif val == false
395
+ # ignore
396
+ else
397
+ argv << "--#{key.to_s.tr('_', '-')}=#{val}"
398
+ end
399
+ end
400
+ end
401
+ argv
402
+ end
403
+
404
+ # Simple wrapper around Timeout::timeout.
405
+ #
406
+ # seconds - Float number of seconds before a Timeout::Error is raised. When
407
+ # true, the Grit::Git.git_timeout value is used. When the timeout is less
408
+ # than or equal to 0, no timeout is established.
409
+ #
410
+ # Raises Timeout::Error when the timeout has elapsed.
411
+ def timeout_after(seconds)
412
+ seconds = self.class.git_timeout if seconds == true
413
+ if seconds && seconds > 0
414
+ Timeout.timeout(seconds) { yield }
415
+ else
416
+ yield
417
+ end
418
+ end
419
+
420
+ # DEPRECATED OPEN3-BASED COMMAND EXECUTION
421
+
422
+ def run(prefix, cmd, postfix, options, args, &block)
423
+ timeout = options.delete(:timeout) rescue nil
424
+ timeout = true if timeout.nil?
425
+
426
+ base = options.delete(:base) rescue nil
427
+ base = true if base.nil?
428
+
429
+ if input = options.delete(:input)
430
+ block = lambda { |stdin| stdin.write(input) }
431
+ end
432
+
433
+ opt_args = transform_options(options)
434
+
435
+ if RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|bccwin/
436
+ ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|' || Grit.no_quote) ? a : "\"#{e(a)}\"" }
437
+ gitdir = base ? "--git-dir=\"#{self.git_dir}\"" : ""
438
+ call = "#{prefix}#{Git.git_binary} #{gitdir} #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
439
+ else
440
+ ext_args = args.reject { |a| a.empty? }.map { |a| (a == '--' || a[0].chr == '|' || Grit.no_quote) ? a : "'#{e(a)}'" }
441
+ gitdir = base ? "--git-dir='#{self.git_dir}'" : ""
442
+ call = "#{prefix}#{Git.git_binary} #{gitdir} #{cmd.to_s.gsub(/_/, '-')} #{(opt_args + ext_args).join(' ')}#{e(postfix)}"
443
+ end
444
+
445
+ Grit.log(call) if Grit.debug
446
+ response, err = timeout ? sh(call, &block) : wild_sh(call, &block)
447
+ Grit.log(response) if Grit.debug
448
+ Grit.log(err) if Grit.debug
449
+ response
450
+ end
451
+
452
+ def sh(command, &block)
453
+ process =
454
+ Child.new(
455
+ command,
456
+ :timeout => Git.git_timeout,
457
+ :max => Git.git_max_size
458
+ )
459
+ [process.out, process.err]
460
+ rescue TimeoutExceeded, MaximumOutputExceeded
461
+ raise GitTimeout, command
462
+ end
463
+
464
+ def wild_sh(command, &block)
465
+ process = Child.new(command)
466
+ [process.out, process.err]
467
+ end
468
+
469
+ # Transform Ruby style options into git command line options
470
+ # +options+ is a hash of Ruby style options
471
+ #
472
+ # Returns String[]
473
+ # e.g. ["--max-count=10", "--header"]
474
+ def transform_options(options)
475
+ args = []
476
+ options.keys.each do |opt|
477
+ if opt.to_s.size == 1
478
+ if options[opt] == true
479
+ args << "-#{opt}"
480
+ elsif options[opt] == false
481
+ # ignore
482
+ else
483
+ val = options.delete(opt)
484
+ args << "-#{opt.to_s} '#{e(val)}'"
485
+ end
486
+ else
487
+ if options[opt] == true
488
+ args << "--#{opt.to_s.gsub(/_/, '-')}"
489
+ elsif options[opt] == false
490
+ # ignore
491
+ else
492
+ val = options.delete(opt)
493
+ args << "--#{opt.to_s.gsub(/_/, '-')}='#{e(val)}'"
494
+ end
495
+ end
496
+ end
497
+ args
498
+ end
499
+ end # Git
500
+
501
+ end # Grit