gitdocs 0.5.0.pre6 → 0.5.0.pre7
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 +8 -8
- data/.gitignore +1 -0
- data/.haml-lint.yml +3 -0
- data/.jslint.yml +84 -0
- data/.rubocop.yml +13 -0
- data/CHANGELOG +11 -0
- data/README.md +6 -2
- data/Rakefile +22 -3
- data/gitdocs.gemspec +36 -29
- data/lib/gitdocs.rb +5 -2
- data/lib/gitdocs/cli.rb +31 -8
- data/lib/gitdocs/configuration.rb +95 -49
- data/lib/gitdocs/manager.rb +36 -28
- data/lib/gitdocs/migration/001_create_shares.rb +2 -0
- data/lib/gitdocs/migration/002_add_remote_branch.rb +2 -0
- data/lib/gitdocs/migration/003_create_configs.rb +2 -0
- data/lib/gitdocs/migration/004_add_index_for_path.rb +4 -0
- data/lib/gitdocs/migration/005_add_start_web_frontend.rb +2 -0
- data/lib/gitdocs/migration/006_add_web_port_to_config.rb +2 -0
- data/lib/gitdocs/migration/007_add_sync_type.rb +11 -0
- data/lib/gitdocs/notifier.rb +89 -6
- data/lib/gitdocs/public/img/file.png +0 -0
- data/lib/gitdocs/public/img/folder.png +0 -0
- data/lib/gitdocs/public/js/app.js +26 -11
- data/lib/gitdocs/public/js/edit.js +3 -3
- data/lib/gitdocs/public/js/settings.js +8 -5
- data/lib/gitdocs/public/js/util.js +21 -20
- data/lib/gitdocs/rendering.rb +14 -9
- data/lib/gitdocs/repository.rb +180 -216
- data/lib/gitdocs/repository/path.rb +166 -0
- data/lib/gitdocs/runner.rb +22 -65
- data/lib/gitdocs/search.rb +35 -0
- data/lib/gitdocs/server.rb +123 -86
- data/lib/gitdocs/version.rb +1 -1
- data/lib/gitdocs/views/_header.haml +6 -6
- data/lib/gitdocs/views/app.haml +17 -17
- data/lib/gitdocs/views/dir.haml +10 -10
- data/lib/gitdocs/views/edit.haml +8 -9
- data/lib/gitdocs/views/file.haml +1 -1
- data/lib/gitdocs/views/home.haml +4 -4
- data/lib/gitdocs/views/revisions.haml +6 -6
- data/lib/gitdocs/views/search.haml +6 -6
- data/lib/gitdocs/views/settings.haml +23 -16
- data/test/.rubocop.yml +13 -0
- data/test/integration/browse_test.rb +149 -0
- data/test/integration/full_sync_test.rb +3 -11
- data/test/integration/share_management_test.rb +59 -10
- data/test/integration/status_test.rb +2 -0
- data/test/integration/test_helper.rb +40 -7
- data/test/unit/configuration_test.rb +82 -0
- data/test/unit/notifier_test.rb +165 -0
- data/test/unit/repository_path_test.rb +368 -0
- data/test/{repository_test.rb → unit/repository_test.rb} +426 -245
- data/test/unit/runner_test.rb +122 -0
- data/test/unit/search_test.rb +52 -0
- data/test/{test_helper.rb → unit/test_helper.rb} +5 -0
- metadata +138 -41
- data/lib/gitdocs/docfile.rb +0 -23
- data/test/configuration_test.rb +0 -41
- data/test/notifier_test.rb +0 -68
- data/test/runner_test.rb +0 -123
data/lib/gitdocs/rendering.rb
CHANGED
@@ -1,12 +1,17 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
#
|
4
|
-
|
5
|
-
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
#
|
1
|
+
# -*- encoding : utf-8 -*-
|
2
|
+
|
3
|
+
# rubocop:disable LineLength
|
4
|
+
|
5
|
+
# This should not exist but I cannot find any other way to prevent redcarpet
|
6
|
+
# from complaining
|
7
|
+
# > WARN: tilt autoloading 'redcarpet' in a non thread-safe way; explicit require'redcarpet' suggested.
|
8
|
+
# > !! Unexpected error while processing request: Input must be UTF-8 or US-ASCII, ASCII-8BIT given
|
9
|
+
# > Input must be UTF-8 or US-ASCII, ASCII-8BIT given
|
10
|
+
# > gems/redcarpet-2.0.1/lib/redcarpet.rb:70:in `render'
|
11
|
+
# > gems/redcarpet-2.0.1/lib/redcarpet.rb:70:in `to_html'
|
12
|
+
# > gems/tilt-1.3.3/lib/tilt/markdown.rb:38:in `evaluate'
|
13
|
+
# > gems/tilt-1.3.3/lib/tilt/markdown.rb:61:in `evaluate'
|
14
|
+
# > gems/tilt-1.3.3/lib/tilt/template.rb:76:in `render'
|
10
15
|
|
11
16
|
require 'redcarpet'
|
12
17
|
|
data/lib/gitdocs/repository.rb
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
|
+
|
2
3
|
require 'find'
|
3
4
|
|
5
|
+
# rubocop:disable ClassLength
|
6
|
+
# This class is long, but at the moment everything in it seems to be
|
7
|
+
# appropriate.
|
8
|
+
|
4
9
|
# Wrapper for accessing the shared git repositories.
|
5
10
|
# Rugged or Grit will be used, in that order of preference, depending
|
6
11
|
# upon the features which are available with each option.
|
7
12
|
#
|
8
13
|
# @note If a repository is invalid then query methods will return nil, and
|
9
14
|
# command methods will raise exceptions.
|
10
|
-
#
|
11
15
|
class Gitdocs::Repository
|
12
16
|
attr_reader :invalid_reason
|
13
17
|
|
@@ -30,6 +34,7 @@ class Gitdocs::Repository
|
|
30
34
|
@grit = Grit::Repo.new(path)
|
31
35
|
Grit::Git.git_timeout = 120
|
32
36
|
@invalid_reason = nil
|
37
|
+
@commit_message_path = abs_path('.gitmessage~')
|
33
38
|
rescue Rugged::OSError
|
34
39
|
@invalid_reason = :directory_missing
|
35
40
|
rescue Rugged::RepositoryError
|
@@ -53,56 +58,10 @@ class Gitdocs::Repository
|
|
53
58
|
repository = new(path)
|
54
59
|
fail("Unable to clone into #{path}") unless repository.valid?
|
55
60
|
repository
|
56
|
-
rescue Grit::Git::GitTimeout
|
57
|
-
|
58
|
-
rescue Grit::Git::CommandFailed => e
|
59
|
-
fail("Unable to clone into #{path} because of #{e.err}")
|
60
|
-
end
|
61
|
-
|
62
|
-
RepoDescriptor = Struct.new(:name, :index)
|
63
|
-
|
64
|
-
# Search across multiple repositories
|
65
|
-
#
|
66
|
-
# @param [String] term
|
67
|
-
# @param [Array<Repository>} repositories
|
68
|
-
#
|
69
|
-
# @return [Hash<RepoDescriptor, Array<SearchResult>>]
|
70
|
-
def self.search(term, repositories)
|
71
|
-
results = {}
|
72
|
-
repositories.each_with_index do |repository, index|
|
73
|
-
descriptor = RepoDescriptor.new(repository.root, index)
|
74
|
-
results[descriptor] = repository.search(term)
|
75
|
-
end
|
76
|
-
results.delete_if { |key, value| value.empty? }
|
77
|
-
end
|
78
|
-
|
79
|
-
SearchResult = Struct.new(:file, :context)
|
80
|
-
|
81
|
-
# Search a single repository
|
82
|
-
#
|
83
|
-
# @param [String] term
|
84
|
-
#
|
85
|
-
# @return [Array<SearchResult>]
|
86
|
-
def search(term)
|
87
|
-
return [] if term.empty?
|
88
|
-
|
89
|
-
results = []
|
90
|
-
options = { raise: true, bare: false, chdir: root, ignore_case: true }
|
91
|
-
@grit.git.grep(options, term).scan(/(.*?):([^\n]*)/) do |(file, context)|
|
92
|
-
if result = results.find { |s| s.file == file }
|
93
|
-
result.context += ' ... ' + context
|
94
|
-
else
|
95
|
-
results << SearchResult.new(file, context)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
results
|
99
|
-
rescue Grit::Git::GitTimeout => e
|
100
|
-
# TODO: add logging to record the error details
|
101
|
-
[]
|
61
|
+
rescue Grit::Git::GitTimeout
|
62
|
+
raise("Unable to clone into #{path} because it timed out")
|
102
63
|
rescue Grit::Git::CommandFailed => e
|
103
|
-
|
104
|
-
# nothing found
|
105
|
-
[]
|
64
|
+
raise("Unable to clone into #{path} because of #{e.err}")
|
106
65
|
end
|
107
66
|
|
108
67
|
# @return [String]
|
@@ -138,107 +97,113 @@ class Gitdocs::Repository
|
|
138
97
|
nil
|
139
98
|
end
|
140
99
|
|
141
|
-
#
|
100
|
+
# Is the working directory dirty
|
142
101
|
#
|
143
|
-
# @
|
102
|
+
# @return [Boolean]
|
103
|
+
def dirty?
|
104
|
+
return false unless valid?
|
105
|
+
|
106
|
+
return Dir.glob(abs_path('*')).any? unless current_oid
|
107
|
+
@rugged.diff_workdir(current_oid, include_untracked: true).deltas.any?
|
108
|
+
end
|
109
|
+
|
110
|
+
# @return [Boolean]
|
111
|
+
def need_sync?
|
112
|
+
return false unless valid?
|
113
|
+
return false unless remote?
|
114
|
+
|
115
|
+
return !!current_oid unless remote_branch # rubocop:disable DoubleNegation
|
116
|
+
remote_branch.tip.oid != current_oid
|
117
|
+
end
|
118
|
+
|
119
|
+
# @param [String] term
|
120
|
+
# @yield [file, context] Gives the files and context for each of the results
|
121
|
+
# @yieldparam file [String]
|
122
|
+
# @yieldparam context [String]
|
123
|
+
def grep(term, &block)
|
124
|
+
@grit.git.grep(
|
125
|
+
{ raise: true, bare: false, chdir: root, ignore_case: true },
|
126
|
+
term
|
127
|
+
).scan(/(.*?):([^\n]*)/, &block)
|
128
|
+
rescue Grit::Git::GitTimeout
|
129
|
+
# TODO: add logging to record the error details
|
130
|
+
''
|
131
|
+
rescue Grit::Git::CommandFailed
|
132
|
+
# TODO: add logging to record the error details if they are not just
|
133
|
+
# nothing found
|
134
|
+
''
|
135
|
+
end
|
136
|
+
|
137
|
+
# Fetch all the remote branches
|
144
138
|
#
|
145
139
|
# @return [nil] if the repository is invalid
|
146
140
|
# @return [:no_remote] if the remote is not yet set
|
147
141
|
# @return [String] if there is an error return the message
|
148
|
-
# @return [
|
149
|
-
|
150
|
-
# @return [:ok] if pulled and merged with no errors or conflicts
|
151
|
-
def pull
|
142
|
+
# @return [:ok] if the fetch worked
|
143
|
+
def fetch
|
152
144
|
return nil unless valid?
|
153
|
-
return :no_remote unless
|
154
|
-
|
155
|
-
begin
|
156
|
-
@rugged.remotes.each { |x| @grit.remote_fetch(x.name) }
|
157
|
-
rescue Grit::Git::GitTimeout
|
158
|
-
return "Fetch timed out for #{root}"
|
159
|
-
rescue Grit::Git::CommandFailed => e
|
160
|
-
return e.err
|
161
|
-
end
|
145
|
+
return :no_remote unless remote?
|
162
146
|
|
163
|
-
|
147
|
+
@rugged.remotes.each { |x| @grit.remote_fetch(x.name) }
|
148
|
+
:ok
|
149
|
+
rescue Grit::Git::GitTimeout
|
150
|
+
"Fetch timed out for #{root}"
|
151
|
+
rescue Grit::Git::CommandFailed => e
|
152
|
+
e.err
|
153
|
+
end
|
164
154
|
|
165
|
-
|
155
|
+
# Merge the repository
|
156
|
+
#
|
157
|
+
# @return [nil] if the repository is invalid
|
158
|
+
# @return [:no_remote] if the remote is not yet set
|
159
|
+
# @return [String] if there is an error return the message
|
160
|
+
# @return [Array<String>] if there is a conflict return the Array of
|
161
|
+
# conflicted file names
|
162
|
+
# @return [:ok] if the merged with no errors or conflicts
|
163
|
+
def merge
|
164
|
+
return nil unless valid?
|
165
|
+
return :no_remote unless remote?
|
166
|
+
|
167
|
+
return :ok unless remote_branch
|
168
|
+
return :ok if remote_branch.tip.oid == current_oid
|
169
|
+
|
170
|
+
@grit.git.merge(
|
171
|
+
{ raise: true, chdir: root },
|
172
|
+
"#{@remote_name}/#{@branch_name}"
|
173
|
+
)
|
166
174
|
:ok
|
167
175
|
rescue Grit::Git::GitTimeout
|
168
|
-
"
|
176
|
+
"Merge timed out for #{root}"
|
169
177
|
rescue Grit::Git::CommandFailed => e
|
170
178
|
# HACK: The rugged in-memory index will not have been updated after the
|
171
179
|
# Grit merge command. Reload it before checking for conflicts.
|
172
180
|
@rugged.index.reload
|
173
181
|
return e.err unless @rugged.index.conflicts?
|
174
|
-
|
175
|
-
# Collect all the index entries by their paths.
|
176
|
-
index_path_entries = Hash.new { |h, k| h[k] = Array.new }
|
177
|
-
@rugged.index.map do |index_entry|
|
178
|
-
index_path_entries[index_entry[:path]].push(index_entry)
|
179
|
-
end
|
180
|
-
|
181
|
-
# Filter to only the conflicted entries.
|
182
|
-
conflicted_path_entries = index_path_entries.delete_if { |_k, v| v.length == 1 }
|
183
|
-
|
184
|
-
conflicted_path_entries.each_pair do |path, index_entries|
|
185
|
-
# Write out the different versions of the conflicted file.
|
186
|
-
index_entries.each do |index_entry|
|
187
|
-
filename, extension = index_entry[:path].scan(/(.*?)(|\.[^\.]+)$/).first
|
188
|
-
author = ' original' if index_entry[:stage] == 1
|
189
|
-
short_oid = index_entry[:oid][0..6]
|
190
|
-
new_filename = "#{filename} (#{short_oid}#{author})#{extension}"
|
191
|
-
File.open(File.join(root, new_filename), 'wb') do |f|
|
192
|
-
f.write(Rugged::Blob.lookup(@rugged, index_entry[:oid]).content)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
# And remove the original.
|
197
|
-
FileUtils.remove(File.join(root, path), force: true)
|
198
|
-
end
|
199
|
-
|
200
|
-
# NOTE: Let commit be handled by the next regular commit.
|
201
|
-
|
202
|
-
conflicted_path_entries.keys
|
182
|
+
mark_conflicts
|
203
183
|
end
|
204
184
|
|
205
185
|
# Commit the working directory
|
206
186
|
#
|
207
|
-
# @param [String] message
|
208
|
-
#
|
209
187
|
# @return [nil] if the repository is invalid
|
210
188
|
# @return [Boolean] whether a commit was made or not
|
211
|
-
def commit
|
189
|
+
def commit
|
212
190
|
return nil unless valid?
|
213
191
|
|
214
|
-
#
|
215
|
-
|
216
|
-
Find.prune if File.basename(path) == '.git'
|
217
|
-
if File.directory?(path) && Dir.entries(path).count == 2
|
218
|
-
FileUtils.touch(File.join(path, '.gitignore'))
|
219
|
-
end
|
220
|
-
end
|
192
|
+
# Do this first to allow the message file to be deleted, if it exists.
|
193
|
+
message = read_and_delete_commit_message_file
|
221
194
|
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
Dir.glob(File.join(root, '*')).any?
|
226
|
-
else
|
227
|
-
@rugged.diff_workdir(current_oid, include_untracked: true).deltas.any?
|
228
|
-
end
|
195
|
+
mark_empty_directories
|
196
|
+
|
197
|
+
return false unless dirty?
|
229
198
|
|
230
199
|
# Commit any changes in the working directory.
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
@rugged.index.update_all
|
235
|
-
end
|
236
|
-
@rugged.index.write
|
237
|
-
@grit.commit_index(message)
|
238
|
-
true
|
239
|
-
else
|
240
|
-
false
|
200
|
+
Dir.chdir(root) do
|
201
|
+
@rugged.index.add_all
|
202
|
+
@rugged.index.update_all
|
241
203
|
end
|
204
|
+
@rugged.index.write
|
205
|
+
@grit.commit_index(message)
|
206
|
+
true
|
242
207
|
end
|
243
208
|
|
244
209
|
# Push the repository
|
@@ -250,21 +215,16 @@ class Gitdocs::Repository
|
|
250
215
|
# @return [:ok] if committed and pushed without errors or conflicts
|
251
216
|
def push
|
252
217
|
return nil unless valid?
|
253
|
-
return :no_remote unless
|
218
|
+
return :no_remote unless remote?
|
254
219
|
|
255
220
|
return :nothing if current_oid.nil?
|
221
|
+
return :nothing if remote_branch && remote_branch.tip.oid == current_oid
|
256
222
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
return :conflict if e.err[/\[rejected\]/]
|
263
|
-
e.err # return the output on error
|
264
|
-
end
|
265
|
-
else
|
266
|
-
:nothing
|
267
|
-
end
|
223
|
+
@grit.git.push({ raise: true }, @remote_name, @branch_name)
|
224
|
+
:ok
|
225
|
+
rescue Grit::Git::CommandFailed => e
|
226
|
+
return :conflict if e.err[/\[rejected\]/]
|
227
|
+
e.err # return the output on error
|
268
228
|
end
|
269
229
|
|
270
230
|
# Get the count of commits by author from the head to the specified oid.
|
@@ -275,7 +235,7 @@ class Gitdocs::Repository
|
|
275
235
|
def author_count(last_oid)
|
276
236
|
walker = head_walker
|
277
237
|
walker.hide(last_oid) if last_oid
|
278
|
-
walker.
|
238
|
+
walker.reduce(Hash.new(0)) do |result, commit|
|
279
239
|
result["#{commit.author[:name]} <#{commit.author[:email]}>"] += 1
|
280
240
|
result
|
281
241
|
end
|
@@ -285,101 +245,51 @@ class Gitdocs::Repository
|
|
285
245
|
{}
|
286
246
|
end
|
287
247
|
|
288
|
-
#
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
# => { :author => "Nick", :size => 1000, :modified => ... }
|
293
|
-
#
|
294
|
-
# @param [String] file relative path to file in repository
|
295
|
-
#
|
296
|
-
# @raise [RuntimeError] if the file is not found in any commits
|
297
|
-
#
|
298
|
-
# @return [Hash<Symbol=>String,Integer,Time>] the author, size and
|
299
|
-
# modification date of the file
|
300
|
-
def file_meta(file)
|
301
|
-
file = file.gsub(%r{^/}, '')
|
302
|
-
|
303
|
-
commit = head_walker.find { |x| x.diff(paths: [file]).size > 0 }
|
304
|
-
|
305
|
-
fail "File #{file} not found" unless commit
|
306
|
-
|
307
|
-
full_path = File.expand_path(file, root)
|
308
|
-
size = if File.directory?(full_path)
|
309
|
-
Dir[File.join(full_path, '**', '*')].reduce(0) do |size, file|
|
310
|
-
File.symlink?(file) ? size : size += File.size(file)
|
311
|
-
end
|
312
|
-
else
|
313
|
-
File.symlink?(full_path) ? 0 : File.size(full_path)
|
314
|
-
end
|
315
|
-
size = -1 if size == 0 # A value of 0 breaks the table sort for some reason
|
248
|
+
# @param [String] message
|
249
|
+
def write_commit_message(message)
|
250
|
+
return unless message
|
251
|
+
return if message.empty?
|
316
252
|
|
317
|
-
|
253
|
+
File.open(@commit_message_path, 'w') { |f| f.print(message) }
|
318
254
|
end
|
319
255
|
|
320
|
-
#
|
256
|
+
# Excluding the initial commit (without a parent) which keeps things
|
257
|
+
# consistent with the original behaviour.
|
258
|
+
# TODO: reconsider if this is the correct behaviour
|
321
259
|
#
|
322
|
-
# @
|
323
|
-
#
|
260
|
+
# @param [String] relative_path
|
261
|
+
# @param [Integer] limit the number of commits which will be returned
|
324
262
|
#
|
325
|
-
# @
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
# TODO:
|
333
|
-
|
334
|
-
|
335
|
-
.map do |commit|
|
336
|
-
{
|
337
|
-
commit: commit.oid[0, 7],
|
338
|
-
subject: commit.message.split("\n")[0],
|
339
|
-
author: commit.author[:name],
|
340
|
-
date: commit.author[:time]
|
341
|
-
}
|
342
|
-
end
|
263
|
+
# @return [Array<Rugged::Commit>]
|
264
|
+
def commits_for(relative_path, limit)
|
265
|
+
# TODO: should add a filter here for checking that the commit actually has
|
266
|
+
# an associated blob.
|
267
|
+
commits = head_walker.select do |commit|
|
268
|
+
commit.parents.size == 1 && commit.diff(paths: [relative_path]).size > 0
|
269
|
+
end
|
270
|
+
# TODO: should re-write this limit in a way that will skip walking all of
|
271
|
+
# the commits.
|
272
|
+
commits.first(limit)
|
343
273
|
end
|
344
274
|
|
345
|
-
#
|
346
|
-
#
|
347
|
-
# @example
|
348
|
-
# file_revision_at("README", "a4c56h")
|
349
|
-
# => "/tmp/some/path/README"
|
350
|
-
#
|
351
|
-
# @param [String] file
|
352
|
-
# @param [String] ref
|
275
|
+
# @param [String] relative_path
|
353
276
|
#
|
354
|
-
# @return [
|
355
|
-
def
|
356
|
-
|
357
|
-
content = @rugged.blob_at(ref, file).text
|
358
|
-
tmp_path = File.expand_path(File.basename(file), Dir.tmpdir)
|
359
|
-
File.open(tmp_path, 'w') { |f| f.puts content }
|
360
|
-
tmp_path
|
277
|
+
# @return [Rugged::Commit]
|
278
|
+
def last_commit_for(relative_path)
|
279
|
+
head_walker.find { |commit| commit.diff(paths: [relative_path]).size > 0 }
|
361
280
|
end
|
362
281
|
|
363
|
-
#
|
364
|
-
#
|
365
|
-
|
366
|
-
|
367
|
-
def file_revert(file, ref)
|
368
|
-
file = file.gsub(%r{^/}, '')
|
369
|
-
blob = @rugged.blob_at(ref, file)
|
370
|
-
# Silently fail if the file/ref do not existing in the repository.
|
371
|
-
# Which is consistent with the original behaviour.
|
372
|
-
# TODO: should consider throwing an exception on this condition
|
373
|
-
return unless blob
|
374
|
-
|
375
|
-
File.open(File.expand_path(file, root), 'w') { |f| f.puts(blob.text) }
|
282
|
+
# @param [String] relative_path
|
283
|
+
# @param [String] oid
|
284
|
+
def blob_at(relative_path, ref)
|
285
|
+
@rugged.blob_at(ref, relative_path)
|
376
286
|
end
|
377
287
|
|
378
288
|
##############################################################################
|
379
289
|
|
380
290
|
private
|
381
291
|
|
382
|
-
def
|
292
|
+
def remote?
|
383
293
|
@rugged.remotes.any?
|
384
294
|
end
|
385
295
|
|
@@ -400,4 +310,58 @@ class Gitdocs::Repository
|
|
400
310
|
walker.push(@rugged.head.target)
|
401
311
|
walker
|
402
312
|
end
|
313
|
+
|
314
|
+
def read_and_delete_commit_message_file
|
315
|
+
return 'Auto-commit from gitdocs' unless File.exist?(@commit_message_path)
|
316
|
+
|
317
|
+
message = File.read(@commit_message_path)
|
318
|
+
File.delete(@commit_message_path)
|
319
|
+
message
|
320
|
+
end
|
321
|
+
|
322
|
+
def mark_empty_directories
|
323
|
+
Find.find(root).each do |path| # rubocop:disable Style/Next
|
324
|
+
Find.prune if File.basename(path) == '.git'
|
325
|
+
if File.directory?(path) && Dir.entries(path).count == 2
|
326
|
+
FileUtils.touch(File.join(path, '.gitignore'))
|
327
|
+
end
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
def mark_conflicts
|
332
|
+
# assert(@rugged.index.conflicts?)
|
333
|
+
|
334
|
+
# Collect all the index entries by their paths.
|
335
|
+
index_path_entries = Hash.new { |h, k| h[k] = Array.new }
|
336
|
+
@rugged.index.map do |index_entry|
|
337
|
+
index_path_entries[index_entry[:path]].push(index_entry)
|
338
|
+
end
|
339
|
+
|
340
|
+
# Filter to only the conflicted entries.
|
341
|
+
conflicted_path_entries = index_path_entries.delete_if { |_k, v| v.length == 1 }
|
342
|
+
|
343
|
+
conflicted_path_entries.each_pair do |path, index_entries|
|
344
|
+
# Write out the different versions of the conflicted file.
|
345
|
+
index_entries.each do |index_entry|
|
346
|
+
filename, extension = index_entry[:path].scan(/(.*?)(|\.[^\.]+)$/).first
|
347
|
+
author = ' original' if index_entry[:stage] == 1
|
348
|
+
short_oid = index_entry[:oid][0..6]
|
349
|
+
new_filename = "#{filename} (#{short_oid}#{author})#{extension}"
|
350
|
+
File.open(abs_path(new_filename), 'wb') do |f|
|
351
|
+
f.write(Rugged::Blob.lookup(@rugged, index_entry[:oid]).content)
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
# And remove the original.
|
356
|
+
FileUtils.remove(abs_path(path), force: true)
|
357
|
+
end
|
358
|
+
|
359
|
+
# NOTE: Let commit be handled by the next regular commit.
|
360
|
+
|
361
|
+
conflicted_path_entries.keys
|
362
|
+
end
|
363
|
+
|
364
|
+
def abs_path(*path)
|
365
|
+
File.join(root, *path)
|
366
|
+
end
|
403
367
|
end
|