class WikiMD::Repository

Handles reading and writing of files in the repo. Also interacts with GIT.

Attributes

path[R]

Public Class Methods

new(path) click to toggle source
# File lib/wikimd/repository.rb, line 16
def initialize(path)
  @path = Pathname(path).realpath
  @path.mkpath
end

Public Instance Methods

diff(path, old, new) click to toggle source
# File lib/wikimd/repository.rb, line 95
def diff(path, old, new)
  path = pathname(path)
  raw_diff = git :diff, "-p --no-color #{old} #{new} -- #{path.to_s.shellescape}"
  diff = []
  raw_diff.each_line do |line|
    next if line =~ /^(diff|index|\+\+\+|---)/
    case line[0]
    when '@'
      parts = line.chomp.split('@@')
      diff << {
        start: parts[1].gsub(/^\s|\s$/, ''),
        lines: [(parts[2])].compact
      }
    else
      diff.last[:lines] << line.chomp
    end
  end
  diff
end
files(root = '') click to toggle source

return an array of all files

# File lib/wikimd/repository.rb, line 82
def files(root = '')
  files = []
  dir = @path.join(root)
  Dir.chdir(dir) do
    files = Dir.glob('**/*').select { |p| dir.join(p).file? }
  end
end
history(path) click to toggle source
# File lib/wikimd/repository.rb, line 38
def history(path)
  params = %(--pretty='format:%h;%cr;%s' --no-decorate --no-color -z)
  out = git :log, "#{params} -- #{path.shellescape}"
  out.split("\x0").map do |e|
    h, d, m = e.split(';', 3)
    {
      hash: h,
      date: d,
      message: m
    }
  end
end
list_dirs(path) click to toggle source

List all directories in path.

@param path [String,Pathname] path to the directory within the repo @return [Array] an array of directory names

# File lib/wikimd/repository.rb, line 55
def list_dirs(path)
  dir = pathname(path)

  Dir.chdir(dir) do
    Dir['*/'].sort
  end

rescue
  raise FileNotFound, "no such file in repo - #{path}"
end
list_files(path) click to toggle source

List all files in path.

@param path [String,Pathname] path to the directory within the repo @return [Array] an array of file names

# File lib/wikimd/repository.rb, line 70
def list_files(path)
  dir = pathname(path)

  Dir.chdir(dir) do
    Dir['*'].select { |n| File.file?(n) }.sort
  end

rescue
  raise FileNotFound, "no such file in repo - #{path}"
end
read(path, rev=nil) click to toggle source

Reads a file from the repository. path will have its leading slashes removed and must be within the repository path.

@param path [String,Pathname] path to the file to be read @return [String] the content of file @raise [FileNotFound] if file doesn't exist within the repo or is a dir

# File lib/wikimd/repository.rb, line 27
def read(path, rev=nil)
  if rev.nil?
    file = pathname(path)
    return file.read
  else
    git :show, %(#{rev}:"./#{path.shellescape}")
  end
rescue
  raise FileNotFound, "no such file in repo - #{path}"
end
tree(root = '') click to toggle source

return a hash containing all dirs and files

# File lib/wikimd/repository.rb, line 91
def tree(root = '')
  build_hash(files(root), root)
end
update(path, content) click to toggle source

Updates the given file with `content`. The file must be present!

@param path [String] absolute path of file to update. @param content [String] the new file content @raise [FileNotFound] if file doesn't exist within the repo or is a dir

# File lib/wikimd/repository.rb, line 120
def update(path, content)
  file = pathname(path)

  # fail if path is a dir or similar
  fail FileNotFound unless file.file?

  # get rid of CRLFs
  content.gsub!(/\r\n?/, "\n")

  # don't do anything if the contents are identical
  return if file.read == content

  # write, add, commit
  file.write(content)
  git :add, path.shellescape
  git :commit, "-m 'update #{path}' -- #{path.shellescape}"
end

Private Instance Methods

build_hash(files, root) click to toggle source

convert an array of absolute path names into a hash.

# File lib/wikimd/repository.rb, line 151
def build_hash(files, root)
  tree = {}
  files.each do |path|
    build_tree(tree, path.split(File::SEPARATOR), root)
  end
  tree
end
build_tree(tree, parts, path) click to toggle source

add an array of path parts to the tree

# File lib/wikimd/repository.rb, line 160
def build_tree(tree, parts, path)
  path += '/' unless path.empty? || path.end_with?('/')
  parts[0...-1].each do |p|
    path += "#{p}/"
    tree[p] ||= { type: :directory, path: path, sub: {} }
    tree = tree[p][:sub]
  end
  fname = parts[-1]
  tree[fname] = { type: :text, path: path + fname }
end
git(cmd, arg) click to toggle source
# File lib/wikimd/repository.rb, line 140
def git(cmd, arg)
  command = "git #{cmd.to_s} #{arg}"
  out, err, stat = nil
  Dir.chdir(@path) do
    out, err, stat = Open3.capture3(command)
  end
  fail GitError, "Error running `#{command}` - #{err}" unless stat.success?
  out
end
pathname(path) click to toggle source
# File lib/wikimd/repository.rb, line 171
def pathname(path)
  # calling `realpath` does several things for us:
  # - returns an absolute pathname
  # - ... which does not contain any useless dots (., ..)
  # - and checks that the file actually exists.
  file = @path.join(path.sub(%r{\A/+}, '')).realpath
  fail unless file.to_s.start_with?(@path.to_s)
  file
rescue
  raise FileNotFound, "no such file or directory in repo - #{path}"
end