lib/gitolite/gitolite_admin.rb in jbox-gitolite-1.1.10 vs lib/gitolite/gitolite_admin.rb in jbox-gitolite-1.1.11

- old
+ new

@@ -1,209 +1,241 @@ require File.join(File.dirname(__FILE__), "dirty_proxy") module Gitolite class GitoliteAdmin + attr_accessor :gl_admin - CONF = "gitolite.conf" - CONFDIR = "conf" - KEYDIR = "keydir" - DEBUG = false + CONFIG_FILE = "gitolite.conf" + CONF_DIR = "conf" + KEY_DIR = "keydir" + DEBUG = false + TIMEOUT = 10 - #Gitolite gem's default git commit message + # Gitolite gem's default commit message DEFAULT_COMMIT_MSG = "Committed by the gitolite gem" + class << self + + # Checks to see if the given path is a gitolite-admin repository + # A valid repository contains a conf folder, keydir folder, + # and a configuration file within the conf folder + def is_gitolite_admin_repo?(dir) + # First check if it is a git repository + begin + Grit::Repo.new(dir) + rescue Grit::NoSuchPathError, Grit::InvalidGitRepositoryError + return false + end + + # If we got here it is a valid git repo, + # now check directory structure + File.exists?(File.join(dir, 'conf')) && + File.exists?(File.join(dir, 'keydir')) && + !Dir.glob(File.join(dir, 'conf', '*.conf')).empty? + end + + + # This method will bootstrap a gitolite-admin repo + # at the given path. A typical gitolite-admin + # repo will have the following tree: + # + # gitolite-admin + # conf + # gitolite.conf + # keydir + def bootstrap(path, options = {}) + if self.is_gitolite_admin_repo?(path) + if options[:overwrite] + FileUtils.rm_rf(File.join(path, '*')) + else + return self.new(path) + end + end + + FileUtils.mkdir_p([File.join(path, "conf"), File.join(path, "keydir")]) + + options[:perm] ||= "RW+" + options[:refex] ||= "" + options[:user] ||= "git" + + c = Config.init + r = Config::Repo.new(options[:repo] || "gitolite-admin") + r.add_permission(options[:perm], options[:refex], options[:user]) + c.add_repo(r) + config = c.to_file(File.join(path, "conf")) + + gl_admin = Grit::Repo.init(path) + gl_admin.git.native(:add, {:chdir => gl_admin.working_dir}, config) + gl_admin.git.native(:commit, {:chdir => gl_admin.working_dir}, '-a', '-m', options[:message] || "Config bootstrapped by the gitolite gem") + + self.new(path) + end + + end + + # Intialize with the path to # the gitolite-admin repository def initialize(path, options = {}) @path = path - @gl_admin = Grit::Repo.new(path) - @conf = options[:conf] || CONF - @confdir = options[:confdir] || CONFDIR - @keydir = options[:keydir] || KEYDIR + @config_file = options[:config_file] || CONFIG_FILE + @conf_dir = options[:conf_dir] || CONF_DIR + @key_dir = options[:key_dir] || KEY_DIR + @env = options[:env] || {} + + @config_file_path = File.join(@path, @conf_dir, @config_file) + @conf_dir_path = File.join(@path, @conf_dir) + @key_dir_path = File.join(@path, @key_dir) + + Grit::Git.git_timeout = options[:timeout] || TIMEOUT Grit.debug = options[:debug] || DEBUG + @gl_admin = Grit::Repo.new(path) + + reload! end - # This method will bootstrap a gitolite-admin repo - # at the given path. A typical gitolite-admin - # repo will have the following tree: - # - # gitolite-admin - # conf - # gitolite.conf - # keydir - def self.bootstrap(path, options = {}) - if self.is_gitolite_admin_repo?(path) - if options[:overwrite] - FileUtils.rm_rf(File.join(path, '*')) - else - return self.new(path) - end - end - FileUtils.mkdir_p([File.join(path,"conf"), File.join(path,"keydir")]) + def config + @config ||= load_config + end - options[:perm] ||= "RW+" - options[:refex] ||= "" - options[:user] ||= "git" - c = Config.init - r = Config::Repo.new(options[:repo] || "gitolite-admin") - r.add_permission(options[:perm], options[:refex], options[:user]) - c.add_repo(r) - config = c.to_file(File.join(path, "conf")) + def config=(config) + @config = config + end - repo = Grit::Repo.init(path) - Dir.chdir(path) do - repo.add(config) - repo.commit_index(options[:message] || "Config bootstrapped by the gitolite gem") - end - self.new(path) + def ssh_keys + @ssh_keys ||= load_keys end - #Writes all changed aspects out to the file system - #will also stage all changes - def save(commit_message = DEFAULT_COMMIT_MSG) - confdir = File.join(@gl_admin.working_dir, @confdir) - keydir = File.join(@gl_admin.working_dir, @keydir) + def add_key(key) + raise "Key must be of type Gitolite::SSHKey!" unless key.instance_of? Gitolite::SSHKey + ssh_keys[key.owner] << key + end + + + def rm_key(key) + raise "Key must be of type Gitolite::SSHKey!" unless key.instance_of? Gitolite::SSHKey + ssh_keys[key.owner].delete key + end + + + # This method will destroy all local tracked changes, resetting the local gitolite + # git repo to HEAD and reloading the entire repository + # Note that this will also delete all untracked files + def reset! + @gl_admin.git.native(:reset, {:env => @env, :chdir => @gl_admin.working_dir, :hard => true}, 'HEAD') + @gl_admin.git.native(:clean, {:env => @env, :chdir => @gl_admin.working_dir, :d => true, :q => true, :f => true}) + reload! + end + + + # This method will destroy the in-memory data structures and reload everything + # from the file system + def reload! + @ssh_keys = load_keys + @config = load_config + end + + + # Writes all changed aspects out to the file system + # will also stage all changes then commit + def save(commit_message = DEFAULT_COMMIT_MSG, options = {}) + #Process config file (if loaded, i.e. may be modified) if @config - new_conf = @config.to_file(confdir).gsub(@gl_admin.working_dir + '/', '') - @gl_admin.git.native(:add, {:chdir => @gl_admin.working_dir}, new_conf) + new_conf = @config.to_file(@conf_dir_path) + @gl_admin.git.native(:add, {:env => @env, :chdir => @gl_admin.working_dir}, new_conf) end #Process ssh keys (if loaded, i.e. may be modified) if @ssh_keys - files = list_keys(keydir).map{|f| File.basename f} - keys = @ssh_keys.values.map{|f| f.map {|t| t.filename}}.flatten + files = list_keys.map{|f| File.basename f} + keys = @ssh_keys.values.map{|f| f.map {|t| t.filename}}.flatten - to_remove = (files - keys).map { |f| File.join(@keydir, f) } + to_remove = (files - keys).map { |f| File.join(@key_dir, f) } to_remove.each do |key| - @gl_admin.git.native(:rm, {:chdir => @gl_admin.working_dir}, key) + @gl_admin.git.native(:rm, {:env => @env, :chdir => @gl_admin.working_dir}, key) end @ssh_keys.each_value do |key| - #Write only keys from sets that has been modified + # Write only keys from sets that has been modified next if key.respond_to?(:dirty?) && !key.dirty? key.each do |k| - new_key = k.to_file(keydir).gsub(@gl_admin.working_dir + '/', '') - @gl_admin.git.native(:add, {:chdir => @gl_admin.working_dir}, new_key) + new_key = k.to_file(@key_dir_path) + @gl_admin.git.native(:add, {:env => @env, :chdir => @gl_admin.working_dir}, new_key) end end end - @gl_admin.git.native(:commit, {:chdir => @gl_admin.working_dir}, '-a', '-m', commit_message) - end + args = [] - # This method will destroy all local tracked changes, resetting the local gitolite - # git repo to HEAD and reloading the entire repository - # Note that this will also delete all untracked files - def reset! - Dir.chdir(@gl_admin.working_dir) do - @gl_admin.git.reset({:hard => true}, 'HEAD') - @gl_admin.git.clean({:d => true, :q => true, :f => true}) + if options.has_key?(:author) && !options[:author].empty? + args << "--author='#{options[:author]}'" end - reload! - end - # This method will destroy the in-memory data structures and reload everything - # from the file system - def reload! - @ssh_keys = load_keys - @config = load_config + @gl_admin.git.native(:commit, {:env => @env, :chdir => @gl_admin.working_dir}, '-a', '-m', commit_message, args.join(' ')) end + # Push back to origin def apply - @gl_admin.git.native(:push, {:chdir => @gl_admin.working_dir}, "origin", "master") + @gl_admin.git.native(:push, {:env => @env, :chdir => @gl_admin.working_dir}, "origin", "master") end + # Commits all staged changes and pushes back to origin def save_and_apply(commit_message = DEFAULT_COMMIT_MSG) - self.save(commit_message) - self.apply + save(commit_message) + apply end + # Updates the repo with changes from remote master def update(options = {}) options = {:reset => true, :rebase => false}.merge(options) reset! if options[:reset] - @gl_admin.git.native(:pull, {:chdir => @gl_admin.working_dir, :rebase => options[:rebase]}, "origin", "master") + @gl_admin.git.native(:pull, {:env => @env, :chdir => @gl_admin.working_dir, :rebase => options[:rebase]}, "origin", "master") reload! end - def add_key(key) - raise "Key must be of type Gitolite::SSHKey!" unless key.instance_of? Gitolite::SSHKey - ssh_keys[key.owner] << key - end - def rm_key(key) - raise "Key must be of type Gitolite::SSHKey!" unless key.instance_of? Gitolite::SSHKey - ssh_keys[key.owner].delete key - end + private - #Checks to see if the given path is a gitolite-admin repository - #A valid repository contains a conf folder, keydir folder, - #and a configuration file within the conf folder - def self.is_gitolite_admin_repo?(dir) - # First check if it is a git repository - begin - Grit::Repo.new(dir) - rescue Grit::InvalidGitRepositoryError - return false - end - # If we got here it is a valid git repo, - # now check directory structure - File.exists?(File.join(dir, 'conf')) && - File.exists?(File.join(dir, 'keydir')) && - !Dir.glob(File.join(dir, 'conf', '*.conf')).empty? + def load_config + Config.new(@config_file_path) end - def ssh_keys - @ssh_keys ||= load_keys - end - def config - @config ||= load_config + def list_keys + Dir.glob(@key_dir_path + '/**/*.pub') end - def config=(config) - @config = config - end - private - #Loads all .pub files in the gitolite-admin - #keydir directory - def load_keys(path = nil) - path ||= File.join(@path, @keydir) - keys = Hash.new {|k,v| k[v] = DirtyProxy.new([])} + # Loads all .pub files in the gitolite-admin + # keydir directory + def load_keys + keys = Hash.new {|k,v| k[v] = DirtyProxy.new([])} - list_keys(path).each do |key| - new_key = SSHKey.from_file(key) - owner = new_key.owner + list_keys.each do |key| + new_key = SSHKey.from_file(key) + owner = new_key.owner - keys[owner] << new_key - end - #Mark key sets as unmodified (for dirty checking) - keys.values.each{|set| set.clean_up!} - - keys + keys[owner] << new_key end - def load_config(path = nil) - path ||= File.join(@path, @confdir, @conf) - Config.new(path) - end + # Mark key sets as unmodified (for dirty checking) + keys.values.each{|set| set.clean_up!} - def list_keys(path) - keys = Dir.glob(path + '/**/*.pub') - keys - end + keys + end + end end