# encoding: utf-8 module LocalPac class GitRepository private attr_reader :repository, :root_commit, :null_file, :file_creator public attr_reader :storage_path def initialize(storage_path, file_creator = LocalPac::File, null_file = LocalPac::NullFile.new) @storage_path = ::File.expand_path(storage_path) @repository = Rugged::Repository.new(storage_path) @file_creator = file_creator @null_file = null_file rescue Rugged::RepositoryError raise Exceptions::RepositoryDoesNotExist, "Sorry, but #{storage_path} is not a git repository." end def self.create(storage_path) storage_path = ::File.expand_path(storage_path) Rugged::Repository.init_at(storage_path, :bare) new(storage_path) end def add_content(path, content = '', mode = 0100644, commit_info = default_commit_info) index = Rugged::Index.new unless repository.empty? root_commit = repository.lookup(repository.head.target) root_commit.tree.walk_blobs(:postorder) do |r, e| e.merge!( { path: "#{r}#{e[:name]}" } ) e.delete(:name) index.add(e) end end oid = repository.write(content, :blob) index.add(:path => path, :oid => oid, :mode => mode) options = {} options[:tree] = index.write_tree(repository) options[:parents] = repository.empty? ? [] : [ repository.head.target ].compact options[:update_ref] = 'HEAD' options.merge! commit_info Rugged::Commit.create(repository, options) end def added_files(old_commit_id, new_commit_id) begin commit_old = repository.lookup(old_commit_id) rescue Rugged::OdbError LocalPac.ui_logger.warn "Invalid commit id \"#{old_commit_id}\". Object cannot be found in repository \"#{storage_path}\"." raise Exceptions::CommitDoesNotExist end begin commit_new = repository.lookup(new_commit_id) rescue Rugged::OdbError LocalPac.ui_logger.warn "Invalid commit id \"#{old_commit_id}\". Object cannot be found in repository \"#{storage_path}\"." raise Exceptions::CommitDoesNotExist end commit_old.diff(commit_new).deltas.keep_if { |d| [:added, :modified].include?(d.status) }.collect { |d| File.new(d.new_file[:path], repository.lookup(d.new_file[:oid]).content) } end def find_file(name) files.fetch(name, null_file) end def all_files files.collect { |_,f| f } end def each_file(&block) all_files.each(&block) end private def files files_in_repository.reduce({}) do |memo, file| memo[file.name.to_sym] = file memo end end def files_in_repository return [] if repository.empty? head_commit = repository.lookup(repository.head.target) files = [] head_commit.tree.walk_blobs(:postorder) do |root, entry| files << file_creator.new("#{root}#{entry[:name]}", repository.lookup(entry[:oid]).content ) end files end def default_commit_info options = {} options[:author] = { :email => 'local_pac@local_pac', :name => 'Local Pac', :time => Time.now } options[:committer] = { :email => 'local_pac@local_pac', :name => 'Local Pac', :time => Time.now } options[:message] = 'Commit made by local pac itself' options end end end