lib/gitdocs/runner.rb in gitdocs-0.4.15 vs lib/gitdocs/runner.rb in gitdocs-0.5.0.pre1
- old
+ new
@@ -2,24 +2,30 @@
class Runner
include ShellTools
attr_reader :root, :listener
+ def self.start_all(shares)
+ runners = shares.map { |share| Runner.new(share) }
+ runners.each(&:run)
+ runners
+ end
+
def initialize(share)
@share = share
- @root = share.path.sub(%r{/+$},'') if share.path
+ @root = share.path.sub(%r{/+$}, '') if share.path
@polling_interval = share.polling_interval
- @icon = File.expand_path("../../img/icon.png", __FILE__)
+ @icon = File.expand_path('../../img/icon.png', __FILE__)
end
SearchResult = Struct.new(:file, :context)
def search(term)
return [] if term.empty?
results = []
if result_test = sh_string("git grep -i #{ShellTools.escape(term)}")
- result_test.scan(/(.*?):([^\n]*)/) do |(file, context)|
+ result_test.scan(/(.*?):([^\n]*)/) do |(file, context)|
if result = results.find { |s| s.file == file }
result.context += ' ... ' + context
else
results << SearchResult.new(file, context)
end
@@ -32,45 +38,45 @@
return false unless self.valid?
@show_notifications = @share.notification
@current_remote = @share.remote_name
@current_branch = @share.branch_name
- @current_revision = sh_string("git rev-parse HEAD")
+ @current_revision = sh_string('git rev-parse HEAD')
Guard::Notifier.turn_on if @show_notifications
mutex = Mutex.new
- info("Running gitdocs!", "Running gitdocs in `#{@root}'")
+ info('Running gitdocs!', "Running gitdocs in `#{@root}'")
# Pull changes from remote repository
syncer = proc do
EM.defer(proc do
mutex.synchronize { sync_changes }
end, proc do
- EM.add_timer(@polling_interval) {
+ EM.add_timer(@polling_interval) do
syncer.call
- }
+ end
end)
end
syncer.call
# Listen for changes in local repository
- EM.defer(proc{
- listener = Guard::Listener.select_and_init(@root, :watch_all_modifications => true)
- listener.on_change { |directories|
+ EM.defer(proc do
+ listener = Guard::Listener.select_and_init(@root, watch_all_modifications: true)
+ listener.on_change do |directories|
directories.uniq!
- directories.delete_if {|d| d =~ /\/\.git/}
+ directories.delete_if { |d| d =~ /\/\.git/ }
unless directories.empty?
EM.next_tick do
- EM.defer(proc {
+ EM.defer(proc do
mutex.synchronize { push_changes }
- }, proc {} )
+ end, proc {})
end
end
- }
+ end
listener.start
- }, proc{EM.stop_reactor})
+ end, proc { EM.stop_reactor })
end
def clear_state
@state = nil
end
@@ -78,63 +84,70 @@
def sync_changes
out, status = sh_with_code("git fetch --all && git merge #{@current_remote}/#{@current_branch}")
if status.success?
changes = get_latest_changes
unless changes.empty?
- author_list = changes.inject(Hash.new{|h, k| h[k] = 0}) {|h, c| h[c['author']] += 1; h}.to_a.sort{|a,b| b[1] <=> a[1]}.map{|(name, count)| "* #{name} (#{count} change#{count == 1 ? '' : 's'})"}.join("\n")
+ author_list = changes.reduce(Hash.new { |h, k| h[k] = 0 }) { |h, c| h[c['author']] += 1; h }.to_a.sort { |a, b| b[1] <=> a[1] }.map { |(name, count)| "* #{name} (#{count} change#{count == 1 ? '' : 's'})" }.join("\n")
info("Updated with #{changes.size} change#{changes.size == 1 ? '' : 's'}", "In `#{@root}':\n#{author_list}")
end
push_changes
elsif out[/CONFLICT/]
- conflicted_files = sh("git ls-files -u --full-name -z").split("\0").
- inject(Hash.new{|h, k| h[k] = []}) {|h, line|
+ conflicted_files = sh('git ls-files -u --full-name -z').split("\0")
+ .reduce(Hash.new { |h, k| h[k] = [] }) do|h, line|
parts = line.split(/\t/)
h[parts.last] << parts.first.split(/ /)
h
- }
- warn("There were some conflicts", "#{conflicted_files.keys.map{|f| "* #{f}"}.join("\n")}")
+ end
+ warn('There were some conflicts', "#{conflicted_files.keys.map { |f| "* #{f}" }.join("\n")}")
conflicted_files.each do |conflict, ids|
conflict_start, conflict_end = conflict.scan(/(.*?)(|\.[^\.]+)$/).first
ids.each do |(mode, sha, id)|
- author = " original" if id == "1"
+ author = ' original' if id == '1'
system("cd #{@root} && git show :#{id}:#{conflict} > '#{conflict_start} (#{sha[0..6]}#{author})#{conflict_end}'")
end
- system("cd #{@root} && git rm #{conflict}") or raise
+ system("cd #{@root} && git rm #{conflict}") || fail
end
push_changes
- elsif sh_string("git remote").nil? # no remote to pull from
+ elsif sh_string('git remote').nil? # no remote to pull from
# Do nothing, no remote repo yet
else
- error("There was a problem synchronizing this gitdoc", "A problem occurred in #{@root}:\n#{out}")
+ error('There was a problem synchronizing this gitdoc', "A problem occurred in #{@root}:\n#{out}")
end
end
def push_changes
- message_file = File.expand_path(".gitmessage~", @root)
+ message_file = File.expand_path('.gitmessage~', @root)
if File.exist? message_file
message = File.read message_file
File.delete message_file
else
message = 'Auto-commit from gitdocs'
end
sh 'find . -type d -regex ``./[^.].*'' -empty -exec touch \'{}/.gitignore\' \;'
sh 'git add .'
- sh "git commit -a -m #{ShellTools.escape(message)}" unless sh("git status -s").strip.empty?
+ sh "git commit -a -m #{ShellTools.escape(message)}" unless sh('git status -s').strip.empty?
if @current_revision.nil? || sh('git status')[/branch is ahead/]
out, code = sh_with_code("git push #{@current_remote} #{@current_branch}")
if code.success?
changes = get_latest_changes
info("Pushed #{changes.size} change#{changes.size == 1 ? '' : 's'}", "`#{@root}' has been pushed")
elsif @current_revision.nil?
# ignorable
elsif out[/\[rejected\]/]
- warn("There was a conflict in #{@root}, retrying", "")
+ warn("There was a conflict in #{@root}, retrying", '')
else
error("BAD Could not push changes in #{@root}", out)
- exit
+ # TODO: need to add a status on shares so that the push problem can be
+ # displayed.
end
end
+ rescue
+ # Rescue any standard exceptions which come from the push related
+ # commands. This will prevent problems on a single share from killing
+ # the entire daemon.
+ error("Unexpected error pushing changes in #{@root}")
+ # TODO: get logging and/or put the error message into a status field in the database
end
def get_latest_changes
if @current_revision
out = sh "git log #{@current_revision}.. --pretty='format:{\"commit\": \"%H\",%n \"author\": \"%an <%ae>\",%n \"date\": \"%ad\",%n \"message\": \"%s\"%n}'"
@@ -143,11 +156,11 @@
else
lines = []
Yajl::Parser.new.parse(out) do |obj|
lines << obj
end
- @current_revision = sh("git rev-parse HEAD").strip
+ @current_revision = sh('git rev-parse HEAD').strip
lines
end
else
[]
end
@@ -155,45 +168,43 @@
IGNORED_FILES = ['.gitignore']
# Returns the list of files in a given directory
# dir_files("some/dir") => [<Docfile>, <Docfile>]
def dir_files(dir_path)
- Dir[File.join(dir_path, "*")].to_a.map { |path| Docfile.new(path) }
+ Dir[File.join(dir_path, '*')].to_a.map { |path| Docfile.new(path) }
end
# Returns file meta data based on relative file path
# file_meta("path/to/file")
# => { :author => "Nick", :size => 1000, :modified => ... }
def file_meta(file)
- result = {}
file = file.gsub(%r{^/}, '')
full_path = File.expand_path(file, @root)
log_result = sh_string("git log --format='%aN|%ai' -n1 #{ShellTools.escape(file)}")
- result = {} unless File.exist?(full_path) && log_result
- author, modified = log_result.split("|")
+ author, modified = log_result.split('|')
modified = Time.parse(modified.sub(' ', 'T')).utc.iso8601
size = if File.directory?(full_path)
- Dir[File.join(full_path, '**', '*')].inject(0) do |size, file|
- File.symlink?(file) ? size : size += File.size(file)
- end
- else
- File.symlink?(full_path) ? 0 : File.size(full_path)
- end
+ Dir[File.join(full_path, '**', '*')].reduce(0) do |size, file|
+ File.symlink?(file) ? size : size += File.size(file)
+ end
+ else
+ File.symlink?(full_path) ? 0 : File.size(full_path)
+ end
size = -1 if size == 0 # A value of 0 breaks the table sort for some reason
- result = { :author => author, :size => size, :modified => modified }
- result
+
+ { author: author, size: size, modified: modified }
end
# Returns the revisions available for a particular file
# file_revisions("README")
def file_revisions(file)
file = file.gsub(%r{^/}, '')
output = sh_string("git log --format='%h|%s|%aN|%ai' -n100 #{ShellTools.escape(file)}")
output.to_s.split("\n").map do |log_result|
- commit, subject, author, date = log_result.split("|")
+ commit, subject, author, date = log_result.split('|')
date = Time.parse(date.sub(' ', 'T')).utc.iso8601
- { :commit => commit, :subject => subject, :author => author, :date => date }
+ { commit: commit, subject: subject, author: author, date: date }
end
end
# Returns the temporary path of a particular revision of a file
# file_revision_at("README", "a4c56h") => "/tmp/some/path/README"
@@ -205,50 +216,53 @@
tmp_path
end
# Revert a file to a particular revision
def file_revert(file, ref)
- if file_revisions(file).map {|r| r[:commit]}.include? ref
+ if file_revisions(file).map { |r| r[:commit] }.include? ref
file = file.gsub(%r{^/}, '')
full_path = File.expand_path(file, @root)
content = File.read(file_revision_at(file, ref))
File.open(full_path, 'w') { |f| f.puts content }
end
end
def valid?
- out, status = sh_with_code "git status"
+ out, status = sh_with_code 'git status'
@root.present? && status.success?
end
def warn(title, msg)
if @show_notifications
- Guard::Notifier.notify(msg, :title => title)
+ Guard::Notifier.notify(msg, title: title)
else
Kernel.warn("#{title}: #{msg}")
end
+ rescue # Prevent StandardErrors from stopping the daemon.
end
def info(title, msg)
if @show_notifications
- Guard::Notifier.notify(msg, :title => title, :image => @icon)
+ Guard::Notifier.notify(msg, title: title, image: @icon)
else
puts("#{title}: #{msg}")
end
+ rescue # Prevent StandardErrors from stopping the daemon.
end
def error(title, msg)
if @show_notifications
- Guard::Notifier.notify(msg, :title => title, :image => :failure)
+ Guard::Notifier.notify(msg, title: title, image: :failure)
else
Kernel.warn("#{title}: #{msg}")
end
+ rescue # Prevent StandardErrors from stopping the daemon.
end
# sh_string("git config branch.`git branch | grep '^\*' | sed -e 's/\* //'`.remote", "origin")
- def sh_string(cmd, default=nil)
+ def sh_string(cmd, default = nil)
val = sh(cmd).strip rescue nil
- (val.nil? || val.empty?) ? default : val
+ val.nil? || val.empty? ? default : val
end
# Run in shell, return both status and output
# @see #sh
def sh_with_code(cmd)