lib/gitolite/config.rb in gitolite-0.0.2.alpha vs lib/gitolite/config.rb in gitolite-0.0.3.alpha

- old
+ new

@@ -1,85 +1,86 @@ +require 'tempfile' +require File.join(File.dirname(__FILE__), 'config', 'repo') +require File.join(File.dirname(__FILE__), 'config', 'group') + module Gitolite class Config attr_accessor :repos, :groups, :filename def initialize(config) @repos = {} - @groups = Hash.new { |k,v| k[v] = [] } + @groups = {} @filename = File.basename(config) process_config(config) end - #Represents a repo inside the gitolite configuration. The name, permissions, and git config - #options are all encapsulated in this class - class Repo - ALLOWED_PERMISSIONS = ['C', 'R', 'RW', 'RW+', 'RWC', 'RW+C', 'RWD', 'RW+D', 'RWCD', 'RW+CD', '-'] + def self.init(filename = "gitolite.conf") + file = Tempfile.new(filename) + conf = self.new(file.path) + conf.filename = filename #kill suffix added by Tempfile + file.close(unlink_now = true) + conf + end - attr_accessor :permissions, :name, :config + #TODO: merge repo unless overwrite = true + def add_repo(repo, overwrite = false) + raise ArgumentError, "Repo must be of type Gitolite::Config::Repo!" unless repo.instance_of? Gitolite::Config::Repo + @repos[repo.name] = repo + end - def initialize(name) - @name = name - @permissions = Hash.new {|k,v| k[v] = Hash.new{|k2, v2| k2[v2] = [] }} - @config = {} - end + def rm_repo(repo) + name = normalize_repo_name(repo) + @repos.delete(name) + end - def add_permission(perm, refex, *users) - if ALLOWED_PERMISSIONS.include? perm - @permissions[perm][refex].concat users - else - raise InvalidPermissionError, "#{perm} is not in the allowed list of permissions!" - end - end + def has_repo?(repo) + name = normalize_repo_name(repo) + @repos.has_key?(name) + end - def set_git_config(key, value) - @config[key] = value - end + def get_repo(repo) + name = normalize_repo_name(repo) + @repos[name] + end - def unset_git_config(key) - @config.delete(key) - end + def add_group(group, overwrite = false) + raise ArgumentError, "Group must be of type Gitolite::Config::Group!" unless group.instance_of? Gitolite::Config::Group + @groups[group.name] = group + end - def to_s - repo = "repo #{@name}\n" + def rm_group(group) + name = normalize_group_name(group) + @groups.delete(name) + end - @permissions.each do |perm, list| - list.each do |refex, users| - repo += " " + perm.ljust(6) + refex.ljust(20) + "= " + users.join(' ') + "\n" - end - end - - repo - end - - #Gets raised if a permission that isn't in the allowed - #list is passed in - class InvalidPermissionError < RuntimeError - end + def has_group?(group) + name = normalize_group_name(group) + @groups.has_key?(name) end - #TODO: merge repo unless overwrite = true - def add_repo(repo, overwrite = false) - raise "Repo must be of type Gitolite::Config::Repo!" unless repo.instance_of? Gitolite::Config::Repo - @repos[repo.name] = repo + def get_group(group) + name = normalize_group_name(group) + @groups[name] end - - def rm_repo(repo) - raise "Repo must be of type Gitolite::Config::Repo!" unless repo.instance_of? Gitolite::Config::Repo - @repos.delete repo.name - end - def to_file(path) - new_conf = File.join(path, @filename) + def to_file(path=".", filename=@filename) + raise ArgumentError, "Path contains a filename or does not exist" unless File.directory?(path) + + new_conf = File.join(path, filename) File.open(new_conf, "w") do |f| - @groups.each do |k,v| - members = v.join(' ') - f.write "#{k.ljust(20)}= #{members}\n" - end + #Output groups + @groups.each_value {|group| f.write group.to_s } + gitweb_descs = [] @repos.each do |k, v| f.write v.to_s + + gwd = v.gitweb_description + gitweb_descs.push(gwd) unless gwd.nil? end + + f.write gitweb_descs.join("\n") end new_conf end @@ -91,11 +92,11 @@ line.gsub!(/^((".*?"|[^#"])*)#.*/) {|m| m=$1} #fix whitespace line.gsub!('=', ' = ') line.gsub!(/\s+/, ' ') - line.strip! + line.strip end def process_config(config) context = [] #will store our context for permissions or config declarations @@ -113,11 +114,11 @@ repos = $1.split repos.each do |r| context << r - @repos[r] = Repo.new(r) unless @repos.has_key? r + @repos[r] = Repo.new(r) unless has_repo?(r) end #repo permissions when /^(-|C|R|RW\+?(?:C?D?|D?C?)) (.* )?= (.+)/ perm = $1 refex = $2 || "" @@ -133,25 +134,73 @@ context.each do |c| @repos[c].set_git_config(key, value) end #group definition - when /^(@\S+) = ?(.*)/ + when /^#{Group::PREPEND_CHAR}(\S+) = ?(.*)/ group = $1 users = $2.split - @groups[group].concat users - @groups[group].uniq! + @groups[group] = Group.new(group) unless has_group?(group) + @groups[group].add_users(users) #gitweb definition when /^(\S+)(?: "(.*?)")? = "(.*)"$/ - #ignore gitweb right now - puts line + repo = $1 + owner = $2 + description = $3 + + #Check for missing description + raise ParseError, "Missing Gitweb description for repo: #{repo}" if description.nil? + + #Check for groups + raise ParseError, "Gitweb descriptions cannot be set for groups" if repo =~ /@.+/ + + if has_repo? repo + r = @repos[repo] + else + r = Repo.new(repo) + add_repo(r) + end + + r.owner = owner + r.description = description when /^include "(.+)"/ + #TODO: implement includes #ignore includes for now else - puts "The following line cannot be processed:" - puts "'#{line}'" + raise ParseError, "'#{line}' cannot be processed" end end + end + + # Normalizes the various different input objects to Strings + def normalize_name(context, constant = nil) + case context + when constant + context.name + when Symbol + context.to_s + else + context + end + end + + def method_missing(meth, *args, &block) + if meth.to_s =~ /normalize_(\w+)_name/ + #Could use Object.const_get to figure out the constant here + #but for only two cases, this is more readable + case $1 + when "repo" + normalize_name(args[0], Gitolite::Config::Repo) + when "group" + normalize_name(args[0], Gitolite::Config::Group) + end + else + super + end + end + + #Raised when something in a config fails to parse properly + class ParseError < RuntimeError end end end