gitlab-gollum-lib 1.0.0
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.
- checksums.yaml +7 -0
- data/Gemfile +4 -0
- data/HISTORY.md +3 -0
- data/LICENSE +21 -0
- data/README.md +601 -0
- data/Rakefile +171 -0
- data/docs/sanitization.md +33 -0
- data/gollum-lib.gemspec +75 -0
- data/lib/gollum-lib.rb +53 -0
- data/lib/gollum-lib/blob_entry.rb +95 -0
- data/lib/gollum-lib/committer.rb +236 -0
- data/lib/gollum-lib/file.rb +101 -0
- data/lib/gollum-lib/file_view.rb +155 -0
- data/lib/gollum-lib/git_access.rb +249 -0
- data/lib/gollum-lib/gitcode.rb +48 -0
- data/lib/gollum-lib/grit_ext.rb +20 -0
- data/lib/gollum-lib/helpers.rb +13 -0
- data/lib/gollum-lib/markup.rb +689 -0
- data/lib/gollum-lib/markups.rb +14 -0
- data/lib/gollum-lib/page.rb +485 -0
- data/lib/gollum-lib/pagination.rb +62 -0
- data/lib/gollum-lib/remote_code.rb +39 -0
- data/lib/gollum-lib/sanitization.rb +176 -0
- data/lib/gollum-lib/web_sequence_diagram.rb +44 -0
- data/lib/gollum-lib/wiki.rb +833 -0
- data/licenses/licenses.txt +6 -0
- metadata +315 -0
data/Rakefile
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'date'
|
4
|
+
|
5
|
+
#############################################################################
|
6
|
+
#
|
7
|
+
# Helper functions
|
8
|
+
#
|
9
|
+
#############################################################################
|
10
|
+
|
11
|
+
def name
|
12
|
+
@name ||= Dir['*.gemspec'].first.split('.').first
|
13
|
+
end
|
14
|
+
|
15
|
+
def version
|
16
|
+
line = File.read("lib/#{name}.rb")[/^\s*VERSION\s*=\s*.*/]
|
17
|
+
line.match(/.*VERSION\s*=\s*['"](.*)['"]/)[1]
|
18
|
+
end
|
19
|
+
|
20
|
+
# assumes x.y.z all digit version
|
21
|
+
def next_version
|
22
|
+
# x.y.z
|
23
|
+
v = version.split '.'
|
24
|
+
# bump z
|
25
|
+
v[-1] = v[-1].to_i + 1
|
26
|
+
v.join '.'
|
27
|
+
end
|
28
|
+
|
29
|
+
def bump_version
|
30
|
+
old_file = File.read("lib/#{name}.rb")
|
31
|
+
old_version_line = old_file[/^\s*VERSION\s*=\s*.*/]
|
32
|
+
new_version = next_version
|
33
|
+
# replace first match of old vesion with new version
|
34
|
+
old_file.sub!(old_version_line, " VERSION = '#{new_version}'")
|
35
|
+
|
36
|
+
File.write("lib/#{name}.rb", old_file)
|
37
|
+
|
38
|
+
new_version
|
39
|
+
end
|
40
|
+
|
41
|
+
def date
|
42
|
+
Date.today.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
def rubyforge_project
|
46
|
+
name
|
47
|
+
end
|
48
|
+
|
49
|
+
def gemspec_file
|
50
|
+
"#{name}.gemspec"
|
51
|
+
end
|
52
|
+
|
53
|
+
def gem_file
|
54
|
+
"#{name}-#{version}.gem"
|
55
|
+
end
|
56
|
+
|
57
|
+
def replace_header(head, header_name)
|
58
|
+
head.sub!(/(\.#{header_name}\s*= ').*'/) { "#{$1}#{send(header_name)}'"}
|
59
|
+
end
|
60
|
+
|
61
|
+
#############################################################################
|
62
|
+
#
|
63
|
+
# Standard tasks
|
64
|
+
#
|
65
|
+
#############################################################################
|
66
|
+
|
67
|
+
task :default => :test
|
68
|
+
|
69
|
+
require 'rake/testtask'
|
70
|
+
Rake::TestTask.new(:test) do |test|
|
71
|
+
test.libs << 'lib' << 'test' << '.'
|
72
|
+
test.pattern = 'test/**/test_*.rb'
|
73
|
+
test.verbose = true
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "Generate RCov test coverage and open in your browser"
|
77
|
+
task :coverage do
|
78
|
+
require 'rcov'
|
79
|
+
sh "rm -fr coverage"
|
80
|
+
sh "rcov test/test_*.rb"
|
81
|
+
sh "open coverage/index.html"
|
82
|
+
end
|
83
|
+
|
84
|
+
desc "Open an irb session preloaded with this library"
|
85
|
+
task :console do
|
86
|
+
sh "irb -rubygems -r ./lib/#{name}.rb"
|
87
|
+
end
|
88
|
+
|
89
|
+
#############################################################################
|
90
|
+
#
|
91
|
+
# Custom tasks (add your own tasks here)
|
92
|
+
#
|
93
|
+
#############################################################################
|
94
|
+
|
95
|
+
desc "Update version number and gemspec"
|
96
|
+
task :bump do
|
97
|
+
puts "Updated version to #{bump_version}"
|
98
|
+
# Execute does not invoke dependencies.
|
99
|
+
# Manually invoke gemspec then validate.
|
100
|
+
Rake::Task[:gemspec].execute
|
101
|
+
Rake::Task[:validate].execute
|
102
|
+
end
|
103
|
+
|
104
|
+
#############################################################################
|
105
|
+
#
|
106
|
+
# Packaging tasks
|
107
|
+
#
|
108
|
+
#############################################################################
|
109
|
+
|
110
|
+
desc 'Create a release build'
|
111
|
+
task :release => :build do
|
112
|
+
unless `git branch` =~ /^\* master$/
|
113
|
+
puts "You must be on the master branch to release!"
|
114
|
+
exit!
|
115
|
+
end
|
116
|
+
sh "git commit --allow-empty -a -m 'Release #{version}'"
|
117
|
+
sh "git pull"
|
118
|
+
sh "git tag v#{version}"
|
119
|
+
sh "git push origin master"
|
120
|
+
sh "git push origin v#{version}"
|
121
|
+
sh "gem push pkg/#{name}-#{version}.gem"
|
122
|
+
end
|
123
|
+
|
124
|
+
desc 'Build gem'
|
125
|
+
task :build => :gemspec do
|
126
|
+
sh "mkdir -p pkg"
|
127
|
+
sh "gem build #{gemspec_file}"
|
128
|
+
sh "mv #{gem_file} pkg"
|
129
|
+
end
|
130
|
+
|
131
|
+
desc 'Update gemspec'
|
132
|
+
task :gemspec => :validate do
|
133
|
+
# read spec file and split out manifest section
|
134
|
+
spec = File.read(gemspec_file)
|
135
|
+
head, manifest, tail = spec.split(" # = MANIFEST =\n")
|
136
|
+
|
137
|
+
# replace name version and date
|
138
|
+
replace_header(head, :name)
|
139
|
+
replace_header(head, :version)
|
140
|
+
replace_header(head, :date)
|
141
|
+
#comment this out if your rubyforge_project has a different name
|
142
|
+
replace_header(head, :rubyforge_project)
|
143
|
+
|
144
|
+
# determine file list from git ls-files
|
145
|
+
files = `git ls-files`.
|
146
|
+
split("\n").
|
147
|
+
sort.
|
148
|
+
reject { |file| file =~ /^\./ }.
|
149
|
+
reject { |file| file =~ /^(rdoc|pkg|test|Home\.md|\.gitattributes)/ }.
|
150
|
+
map { |file| " #{file}" }.
|
151
|
+
join("\n")
|
152
|
+
|
153
|
+
# piece file back together and write
|
154
|
+
manifest = " s.files = %w[\n#{files}\n ]\n"
|
155
|
+
spec = [head, manifest, tail].join(" # = MANIFEST =\n")
|
156
|
+
File.open(gemspec_file, 'w') { |io| io.write(spec) }
|
157
|
+
puts "Updated #{gemspec_file}"
|
158
|
+
end
|
159
|
+
|
160
|
+
desc 'Validate lib files and version file'
|
161
|
+
task :validate do
|
162
|
+
libfiles = Dir['lib/*'] - ["lib/#{name}.rb", "lib/#{name}"]
|
163
|
+
unless libfiles.empty?
|
164
|
+
puts "Directory `lib` should only contain a `#{name}.rb` file and `#{name}` dir."
|
165
|
+
exit!
|
166
|
+
end
|
167
|
+
unless Dir['VERSION*'].empty?
|
168
|
+
puts "A `VERSION` file at root level violates Gem best practices."
|
169
|
+
exit!
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
Sanitization Rules
|
2
|
+
==================
|
3
|
+
|
4
|
+
Gollum uses the [Sanitize](http://wonko.com/post/sanitize) gem for HTML
|
5
|
+
sanitization.
|
6
|
+
|
7
|
+
See `lib/gollum-lib/sanitization.rb` for actual settings.
|
8
|
+
|
9
|
+
## ALLOWED TAGS
|
10
|
+
|
11
|
+
a, abbr, acronym, address, area, b, big, blockquote, br, button, caption,
|
12
|
+
center, cite, code, col, colgroup, dd, del, dfn, dir, div, dl, dt, em,
|
13
|
+
fieldset, font, form, h1, h2, h3, h4, h5, h6, hr, i, img, input, ins, kbd,
|
14
|
+
label, legend, li, map, menu, ol, optgroup, option, p, pre, q, s, samp,
|
15
|
+
select, small, span, strike, strong, sub, sup, table, tbody, td, textarea,
|
16
|
+
tfoot, th, thead, tr, tt, u, ul, var
|
17
|
+
|
18
|
+
## ALLOWED ATTRIBUTES
|
19
|
+
|
20
|
+
abbr, accept, accept-charset, accesskey, action, align, alt, axis, border,
|
21
|
+
cellpadding, cellspacing, char, charoff, charset, checked, cite, class, clear,
|
22
|
+
cols, colspan, color, compact, coords, datetime, dir, disabled, enctype, for,
|
23
|
+
frame, headers, height, href, hreflang, hspace, id, ismap, label, lang,
|
24
|
+
longdesc, maxlength, media, method, multiple, name, nohref, noshade, nowrap,
|
25
|
+
prompt, readonly, rel, rev, rows, rowspan, rules, scope, selected, shape,
|
26
|
+
size, span, src, start, summary, tabindex, target, title, type, usemap,
|
27
|
+
valign, value, vspace, width
|
28
|
+
|
29
|
+
## ALLOWED PROTOCOLS
|
30
|
+
|
31
|
+
a href: http, https, mailto, ftp, irc, apt
|
32
|
+
img src: http, https
|
33
|
+
form action: http, https
|
data/gollum-lib.gemspec
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
3
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
4
|
+
s.rubygems_version = '0.0.1'
|
5
|
+
s.required_ruby_version = ">= 1.8.7"
|
6
|
+
|
7
|
+
s.name = 'gitlab-gollum-lib'
|
8
|
+
s.version = '1.0.0'
|
9
|
+
s.date = '2013-04-02'
|
10
|
+
s.rubyforge_project = 'gollum-lib'
|
11
|
+
|
12
|
+
s.summary = "A simple, Git-powered wiki."
|
13
|
+
s.description = "A simple, Git-powered wiki with a sweet API and local frontend."
|
14
|
+
|
15
|
+
s.authors = ["Tom Preston-Werner", "Rick Olson"]
|
16
|
+
s.email = 'tom@github.com'
|
17
|
+
s.homepage = 'http://github.com/gollum/gollum-lib'
|
18
|
+
|
19
|
+
s.require_paths = %w[lib]
|
20
|
+
|
21
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
22
|
+
s.extra_rdoc_files = %w[README.md LICENSE]
|
23
|
+
|
24
|
+
s.add_dependency('gitlab-grit', '~> 2.5.1')
|
25
|
+
s.add_dependency('github-markup', ['>= 0.7.5', '< 1.0.0'])
|
26
|
+
s.add_dependency('github-markdown', '~> 0.5.3')
|
27
|
+
s.add_dependency('pygments.rb', '~> 0.4.2')
|
28
|
+
s.add_dependency('sanitize', '~> 2.0.3')
|
29
|
+
s.add_dependency('nokogiri', '~> 1.5.9')
|
30
|
+
s.add_dependency('stringex', '~> 1.5.1')
|
31
|
+
|
32
|
+
s.add_development_dependency('RedCloth', '~> 4.2.9')
|
33
|
+
s.add_development_dependency('mocha', '~> 0.13.2')
|
34
|
+
s.add_development_dependency('org-ruby', '~> 0.8.1')
|
35
|
+
s.add_development_dependency('shoulda', '~> 3.4.0')
|
36
|
+
s.add_development_dependency('wikicloth', '~> 0.8.0')
|
37
|
+
s.add_development_dependency('rake', '~> 10.0.3')
|
38
|
+
s.add_development_dependency('pry', '~> 0.9.12')
|
39
|
+
# required by pry
|
40
|
+
s.add_development_dependency('rb-readline', '~> 0.4.2')
|
41
|
+
s.add_development_dependency 'minitest-reporters', '~> 0.14.10'
|
42
|
+
s.add_development_dependency('nokogiri-diff', '~> 0.1.2')
|
43
|
+
|
44
|
+
# = MANIFEST =
|
45
|
+
s.files = %w[
|
46
|
+
Gemfile
|
47
|
+
HISTORY.md
|
48
|
+
LICENSE
|
49
|
+
README.md
|
50
|
+
Rakefile
|
51
|
+
docs/sanitization.md
|
52
|
+
gollum-lib.gemspec
|
53
|
+
lib/gollum-lib.rb
|
54
|
+
lib/gollum-lib/blob_entry.rb
|
55
|
+
lib/gollum-lib/committer.rb
|
56
|
+
lib/gollum-lib/file.rb
|
57
|
+
lib/gollum-lib/file_view.rb
|
58
|
+
lib/gollum-lib/git_access.rb
|
59
|
+
lib/gollum-lib/gitcode.rb
|
60
|
+
lib/gollum-lib/grit_ext.rb
|
61
|
+
lib/gollum-lib/helpers.rb
|
62
|
+
lib/gollum-lib/markup.rb
|
63
|
+
lib/gollum-lib/markups.rb
|
64
|
+
lib/gollum-lib/page.rb
|
65
|
+
lib/gollum-lib/pagination.rb
|
66
|
+
lib/gollum-lib/remote_code.rb
|
67
|
+
lib/gollum-lib/sanitization.rb
|
68
|
+
lib/gollum-lib/web_sequence_diagram.rb
|
69
|
+
lib/gollum-lib/wiki.rb
|
70
|
+
licenses/licenses.txt
|
71
|
+
]
|
72
|
+
# = MANIFEST =
|
73
|
+
|
74
|
+
s.test_files = s.files.select { |path| path =~ /^test\/test_.*\.rb/ }
|
75
|
+
end
|
data/lib/gollum-lib.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
# stdlib
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'digest/sha1'
|
5
|
+
require 'ostruct'
|
6
|
+
|
7
|
+
# external
|
8
|
+
require 'grit'
|
9
|
+
require File.expand_path('../gollum-lib/grit_ext', __FILE__)
|
10
|
+
require 'github/markup'
|
11
|
+
require 'sanitize'
|
12
|
+
|
13
|
+
# internal
|
14
|
+
require File.expand_path('../gollum-lib/git_access', __FILE__)
|
15
|
+
require File.expand_path('../gollum-lib/committer', __FILE__)
|
16
|
+
require File.expand_path('../gollum-lib/pagination', __FILE__)
|
17
|
+
require File.expand_path('../gollum-lib/blob_entry', __FILE__)
|
18
|
+
require File.expand_path('../gollum-lib/wiki', __FILE__)
|
19
|
+
require File.expand_path('../gollum-lib/page', __FILE__)
|
20
|
+
require File.expand_path('../gollum-lib/file', __FILE__)
|
21
|
+
require File.expand_path('../gollum-lib/file_view', __FILE__)
|
22
|
+
require File.expand_path('../gollum-lib/markup', __FILE__)
|
23
|
+
require File.expand_path('../gollum-lib/markups', __FILE__)
|
24
|
+
require File.expand_path('../gollum-lib/sanitization', __FILE__)
|
25
|
+
require File.expand_path('../gollum-lib/web_sequence_diagram', __FILE__)
|
26
|
+
|
27
|
+
# Set ruby to UTF-8 mode
|
28
|
+
# This is required for Ruby 1.8.7 which gollum still supports.
|
29
|
+
$KCODE = 'U' if RUBY_VERSION[0,3] == '1.8'
|
30
|
+
|
31
|
+
module Gollum
|
32
|
+
VERSION = '1.0.0'
|
33
|
+
|
34
|
+
def self.assets_path
|
35
|
+
::File.expand_path('gollum/frontend/public', ::File.dirname(__FILE__))
|
36
|
+
end
|
37
|
+
|
38
|
+
class Error < StandardError; end
|
39
|
+
|
40
|
+
class DuplicatePageError < Error
|
41
|
+
attr_accessor :dir
|
42
|
+
attr_accessor :existing_path
|
43
|
+
attr_accessor :attempted_path
|
44
|
+
|
45
|
+
def initialize(dir, existing, attempted, message = nil)
|
46
|
+
@dir = dir
|
47
|
+
@existing_path = existing
|
48
|
+
@attempted_path = attempted
|
49
|
+
super(message || "Cannot write #{@dir}/#{@attempted_path}, found #{@dir}/#{@existing_path}.")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
module Gollum
|
3
|
+
class BlobEntry
|
4
|
+
# Gets the String SHA for this blob.
|
5
|
+
attr_reader :sha
|
6
|
+
|
7
|
+
# Gets the full path String for this blob.
|
8
|
+
attr_reader :path
|
9
|
+
|
10
|
+
# Gets the Fixnum size of this blob.
|
11
|
+
attr_reader :size
|
12
|
+
|
13
|
+
# Gets the Fixnum mode of this blob.
|
14
|
+
attr_reader :mode
|
15
|
+
|
16
|
+
def initialize(sha, path, size = nil, mode = nil)
|
17
|
+
@sha = sha
|
18
|
+
@path = path
|
19
|
+
@size = size
|
20
|
+
@mode = mode
|
21
|
+
@dir = @name = @blob = nil
|
22
|
+
end
|
23
|
+
|
24
|
+
# Gets the normalized directory path String for this blob.
|
25
|
+
def dir
|
26
|
+
@dir ||= self.class.normalize_dir(::File.dirname(@path))
|
27
|
+
end
|
28
|
+
|
29
|
+
# Gets the file base name String for this blob.
|
30
|
+
def name
|
31
|
+
@name ||= ::File.basename(@path)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Gets a Grit::Blob instance for this blob.
|
35
|
+
#
|
36
|
+
# repo - Grit::Repo instance for the Grit::Blob.
|
37
|
+
#
|
38
|
+
# Returns an unbaked Grit::Blob instance.
|
39
|
+
def blob(repo)
|
40
|
+
@blob ||= Grit::Blob.create(repo,
|
41
|
+
:id => @sha, :name => name, :size => @size, :mode => @mode)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Gets a Page instance for this blob.
|
45
|
+
#
|
46
|
+
# wiki - Gollum::Wiki instance for the Gollum::Page
|
47
|
+
#
|
48
|
+
# Returns a Gollum::Page instance.
|
49
|
+
def page(wiki, commit)
|
50
|
+
blob = self.blob(wiki.repo)
|
51
|
+
page = wiki.page_class.new(wiki).populate(blob, self.dir)
|
52
|
+
page.version = commit
|
53
|
+
page
|
54
|
+
end
|
55
|
+
|
56
|
+
# Gets a File instance for this blob.
|
57
|
+
#
|
58
|
+
# wiki - Gollum::Wiki instance for the Gollum::File
|
59
|
+
#
|
60
|
+
# Returns a Gollum::File instance.
|
61
|
+
def file(wiki, commit)
|
62
|
+
blob = self.blob(wiki.repo)
|
63
|
+
file = wiki.file_class.new(wiki).populate(blob, self.dir)
|
64
|
+
file.version = commit
|
65
|
+
file
|
66
|
+
end
|
67
|
+
|
68
|
+
def inspect
|
69
|
+
%(#<Gollum::BlobEntry #{@sha} #{@path}>)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Normalizes a given directory name for searching through tree paths.
|
73
|
+
# Ensures that a directory begins with a slash, or
|
74
|
+
#
|
75
|
+
# normalize_dir("") # => ""
|
76
|
+
# normalize_dir(".") # => ""
|
77
|
+
# normalize_dir("foo") # => "/foo"
|
78
|
+
# normalize_dir("/foo/") # => "/foo"
|
79
|
+
# normalize_dir("/") # => ""
|
80
|
+
# normalize_dir("c:/") # => ""
|
81
|
+
#
|
82
|
+
# dir - String directory name.
|
83
|
+
#
|
84
|
+
# Returns a normalized String directory name, or nil if no directory
|
85
|
+
# is given.
|
86
|
+
def self.normalize_dir(dir)
|
87
|
+
return '' if dir =~ /^.:\/$/
|
88
|
+
if dir
|
89
|
+
dir = ::File.expand_path(dir, '/')
|
90
|
+
dir = '' if dir == '/'
|
91
|
+
end
|
92
|
+
dir
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,236 @@
|
|
1
|
+
# ~*~ encoding: utf-8 ~*~
|
2
|
+
module Gollum
|
3
|
+
# Responsible for handling the commit process for a Wiki. It sets up the
|
4
|
+
# Git index, provides methods for modifying the tree, and stores callbacks
|
5
|
+
# to be fired after the commit has been made. This is specifically
|
6
|
+
# designed to handle multiple updated pages in a single commit.
|
7
|
+
class Committer
|
8
|
+
# Gets the instance of the Gollum::Wiki that is being updated.
|
9
|
+
attr_reader :wiki
|
10
|
+
|
11
|
+
# Gets a Hash of commit options.
|
12
|
+
attr_reader :options
|
13
|
+
|
14
|
+
# Initializes the Committer.
|
15
|
+
#
|
16
|
+
# wiki - The Gollum::Wiki instance that is being updated.
|
17
|
+
# options - The commit Hash details:
|
18
|
+
# :message - The String commit message.
|
19
|
+
# :name - The String author full name.
|
20
|
+
# :email - The String email address.
|
21
|
+
# :parent - Optional Grit::Commit parent to this update.
|
22
|
+
# :tree - Optional String SHA of the tree to create the
|
23
|
+
# index from.
|
24
|
+
# :committer - Optional Gollum::Committer instance. If provided,
|
25
|
+
# assume that this operation is part of batch of
|
26
|
+
# updates and the commit happens later.
|
27
|
+
#
|
28
|
+
# Returns the Committer instance.
|
29
|
+
def initialize(wiki, options = {})
|
30
|
+
@wiki = wiki
|
31
|
+
@options = options
|
32
|
+
@callbacks = []
|
33
|
+
end
|
34
|
+
|
35
|
+
# Public: References the Git index for this commit.
|
36
|
+
#
|
37
|
+
# Returns a Grit::Index.
|
38
|
+
def index
|
39
|
+
@index ||= begin
|
40
|
+
idx = @wiki.repo.index
|
41
|
+
if tree = options[:tree]
|
42
|
+
idx.read_tree(tree)
|
43
|
+
elsif parent = parents.first
|
44
|
+
idx.read_tree(parent.tree.id)
|
45
|
+
end
|
46
|
+
idx
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Public: The committer for this commit.
|
51
|
+
#
|
52
|
+
# Returns a Grit::Actor.
|
53
|
+
def actor
|
54
|
+
@actor ||= begin
|
55
|
+
@options[:name] = @wiki.default_committer_name if @options[:name].to_s.empty?
|
56
|
+
@options[:email] = @wiki.default_committer_email if @options[:email].to_s.empty?
|
57
|
+
Grit::Actor.new(@options[:name], @options[:email])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Public: The parent commits to this pending commit.
|
62
|
+
#
|
63
|
+
# Returns an array of Grit::Commit instances.
|
64
|
+
def parents
|
65
|
+
@parents ||= begin
|
66
|
+
arr = [@options[:parent] || @wiki.repo.commit(@wiki.ref)]
|
67
|
+
arr.flatten!
|
68
|
+
arr.compact!
|
69
|
+
arr
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# Adds a page to the given Index.
|
74
|
+
#
|
75
|
+
# dir - The String subdirectory of the Gollum::Page without any
|
76
|
+
# prefix or suffix slashes (e.g. "foo/bar").
|
77
|
+
# name - The String Gollum::Page filename_stripped.
|
78
|
+
# format - The Symbol Gollum::Page format.
|
79
|
+
# data - The String wiki data to store in the tree map.
|
80
|
+
# allow_same_ext - A Boolean determining if the tree map allows the same
|
81
|
+
# filename with the same extension.
|
82
|
+
#
|
83
|
+
# Raises Gollum::DuplicatePageError if a matching filename already exists.
|
84
|
+
# This way, pages are not inadvertently overwritten.
|
85
|
+
#
|
86
|
+
# Returns nothing (modifies the Index in place).
|
87
|
+
def add_to_index(dir, name, format, data, allow_same_ext = false)
|
88
|
+
# spaces must be dashes
|
89
|
+
dir.gsub!(' ', '-')
|
90
|
+
name.gsub!(' ', '-')
|
91
|
+
|
92
|
+
path = @wiki.page_file_name(name, format)
|
93
|
+
|
94
|
+
dir = '/' if dir.strip.empty?
|
95
|
+
|
96
|
+
fullpath = ::File.join(*[@wiki.page_file_dir, dir, path].compact)
|
97
|
+
fullpath = fullpath[1..-1] if fullpath =~ /^\//
|
98
|
+
|
99
|
+
if index.current_tree && tree = index.current_tree / (@wiki.page_file_dir || '/')
|
100
|
+
tree = tree / dir unless tree.nil?
|
101
|
+
end
|
102
|
+
|
103
|
+
if tree
|
104
|
+
downpath = path.downcase.sub(/\.\w+$/, '')
|
105
|
+
|
106
|
+
tree.blobs.each do |blob|
|
107
|
+
next if page_path_scheduled_for_deletion?(index.tree, fullpath)
|
108
|
+
|
109
|
+
existing_file = blob.name.downcase.sub(/\.\w+$/, '')
|
110
|
+
existing_file_ext = ::File.extname(blob.name).sub(/^\./, '')
|
111
|
+
|
112
|
+
new_file_ext = ::File.extname(path).sub(/^\./, '')
|
113
|
+
|
114
|
+
if downpath == existing_file && !(allow_same_ext && new_file_ext == existing_file_ext)
|
115
|
+
raise DuplicatePageError.new(dir, blob.name, path)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
fullpath = fullpath.force_encoding('ascii-8bit') if fullpath.respond_to?(:force_encoding)
|
121
|
+
|
122
|
+
index.add(fullpath, @wiki.normalize(data))
|
123
|
+
end
|
124
|
+
|
125
|
+
# Update the given file in the repository's working directory if there
|
126
|
+
# is a working directory present.
|
127
|
+
#
|
128
|
+
# dir - The String directory in which the file lives.
|
129
|
+
# name - The String name of the page or the stripped filename
|
130
|
+
# (should be pre-canonicalized if required).
|
131
|
+
# format - The Symbol format of the page.
|
132
|
+
#
|
133
|
+
# Returns nothing.
|
134
|
+
def update_working_dir(dir, name, format)
|
135
|
+
unless @wiki.repo.bare
|
136
|
+
if @wiki.page_file_dir
|
137
|
+
dir = dir.size.zero? ? @wiki.page_file_dir : ::File.join(dir, @wiki.page_file_dir)
|
138
|
+
end
|
139
|
+
|
140
|
+
path =
|
141
|
+
if dir == ''
|
142
|
+
@wiki.page_file_name(name, format)
|
143
|
+
else
|
144
|
+
::File.join(dir, @wiki.page_file_name(name, format))
|
145
|
+
end
|
146
|
+
|
147
|
+
path = path.force_encoding('ascii-8bit') if path.respond_to?(:force_encoding)
|
148
|
+
|
149
|
+
Dir.chdir(::File.join(@wiki.repo.path, '..')) do
|
150
|
+
if file_path_scheduled_for_deletion?(index.tree, path)
|
151
|
+
@wiki.repo.git.rm({'f' => true}, '--', path)
|
152
|
+
else
|
153
|
+
@wiki.repo.git.checkout({}, 'HEAD', '--', path)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
# Writes the commit to Git and runs the after_commit callbacks.
|
160
|
+
#
|
161
|
+
# Returns the String SHA1 of the new commit.
|
162
|
+
def commit
|
163
|
+
sha1 = index.commit(@options[:message], parents, actor, nil, @wiki.ref)
|
164
|
+
@callbacks.each do |cb|
|
165
|
+
cb.call(self, sha1)
|
166
|
+
end
|
167
|
+
sha1
|
168
|
+
end
|
169
|
+
|
170
|
+
# Adds a callback to be fired after a commit.
|
171
|
+
#
|
172
|
+
# block - A block that expects this Committer instance and the created
|
173
|
+
# commit's SHA1 as the arguments.
|
174
|
+
#
|
175
|
+
# Returns nothing.
|
176
|
+
def after_commit(&block)
|
177
|
+
@callbacks << block
|
178
|
+
end
|
179
|
+
|
180
|
+
# Determine if a given page (regardless of format) is scheduled to be
|
181
|
+
# deleted in the next commit for the given Index.
|
182
|
+
#
|
183
|
+
# map - The Hash map:
|
184
|
+
# key - The String directory or filename.
|
185
|
+
# val - The Hash submap or the String contents of the file.
|
186
|
+
# path - The String path of the page file. This may include the format
|
187
|
+
# extension in which case it will be ignored.
|
188
|
+
#
|
189
|
+
# Returns the Boolean response.
|
190
|
+
def page_path_scheduled_for_deletion?(map, path)
|
191
|
+
parts = path.split('/')
|
192
|
+
if parts.size == 1
|
193
|
+
deletions = map.keys.select { |k| !map[k] }
|
194
|
+
downfile = parts.first.downcase.sub(/\.\w+$/, '')
|
195
|
+
deletions.any? { |d| d.downcase.sub(/\.\w+$/, '') == downfile }
|
196
|
+
else
|
197
|
+
part = parts.shift
|
198
|
+
if rest = map[part]
|
199
|
+
page_path_scheduled_for_deletion?(rest, parts.join('/'))
|
200
|
+
else
|
201
|
+
false
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# Determine if a given file is scheduled to be deleted in the next commit
|
207
|
+
# for the given Index.
|
208
|
+
#
|
209
|
+
# map - The Hash map:
|
210
|
+
# key - The String directory or filename.
|
211
|
+
# val - The Hash submap or the String contents of the file.
|
212
|
+
# path - The String path of the file including extension.
|
213
|
+
#
|
214
|
+
# Returns the Boolean response.
|
215
|
+
def file_path_scheduled_for_deletion?(map, path)
|
216
|
+
parts = path.split('/')
|
217
|
+
if parts.size == 1
|
218
|
+
deletions = map.keys.select { |k| !map[k] }
|
219
|
+
deletions.any? { |d| d == parts.first }
|
220
|
+
else
|
221
|
+
part = parts.shift
|
222
|
+
if rest = map[part]
|
223
|
+
file_path_scheduled_for_deletion?(rest, parts.join('/'))
|
224
|
+
else
|
225
|
+
false
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
# Proxies methods t
|
231
|
+
def method_missing(name, *args)
|
232
|
+
args.map! { |item| item.respond_to?(:force_encoding) ? item.force_encoding('ascii-8bit') : item }
|
233
|
+
index.send(name, *args)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|