lib/gitolite/config.rb in jbox-gitolite-1.2.0 vs lib/gitolite/config.rb in jbox-gitolite-1.2.1

- old
+ new

@@ -1,77 +1,87 @@ 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 = {} - @filename = File.basename(config) - process_config(config) - end - 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 - #TODO: merge repo unless overwrite = true + + def initialize(config) + @repos = {} + @groups = {} + @filename = File.basename(config) + process_config(config) + end + + + # 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 rm_repo(repo) name = normalize_repo_name(repo) @repos.delete(name) end + def has_repo?(repo) name = normalize_repo_name(repo) @repos.has_key?(name) end + def get_repo(repo) name = normalize_repo_name(repo) @repos[name] 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 rm_group(group) name = normalize_group_name(group) @groups.delete(name) end + def has_group?(group) name = normalize_group_name(group) @groups.has_key?(name) end + def get_group(group) name = normalize_group_name(group) @groups[name] end + 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| f.sync = true - #Output groups + # Output groups dep_order = build_groups_depgraph dep_order.each {|group| f.write group.to_s } gitweb_descs = [] @repos.sort.each do |k, v| @@ -87,169 +97,188 @@ end new_conf end + private - #Based on - #https://github.com/sitaramc/gitolite/blob/pu/src/gl-compile-conf#cleanup_conf_line - def cleanup_config_line(line) - #remove comments, even those that happen inline - line.gsub!(/^((".*?"|[^#"])*)#.*/) {|m| m=$1} - #fix whitespace - line.gsub!('=', ' = ') - line.gsub!(/\s+/, ' ') - line.strip - end - def process_config(config) - context = [] #will store our context for permissions or config declarations + # Based on + # https://github.com/sitaramc/gitolite/blob/pu/src/gl-compile-conf#cleanup_conf_line + def cleanup_config_line(line) + # remove comments, even those that happen inline + line.gsub!(/^((".*?"|[^#"])*)#.*/) {|m| m=$1} - #Read each line of our config - File.open(config, 'r').each do |l| + # fix whitespace + line.gsub!('=', ' = ') + line.gsub!(/\s+/, ' ') + line.strip + end - line = cleanup_config_line(l) - next if line.empty? #lines are empty if we killed a comment - case line - #found a repo definition - when /^repo (.*)/ - #Empty our current context - context = [] + def process_config(config) + context = [] #will store our context for permissions or config declarations - repos = $1.split - repos.each do |r| - context << r + #Read each line of our config + File.open(config, 'r').each do |l| - @repos[r] = Repo.new(r) unless has_repo?(r) - end - #repo permissions - when /^(-|C|R|RW\+?(?:C?D?|D?C?)M?) (.* )?= (.+)/ - perm = $1 - refex = $2 || "" - users = $3.split + line = cleanup_config_line(l) + next if line.empty? #lines are empty if we killed a comment - context.each do |c| - @repos[c].add_permission(perm, refex, users) - end - #repo git config - when /^config (.+) = ?(.*)/ - key = $1 - value = $2 + case line - context.each do |c| - @repos[c].set_git_config(key, value) - end - #repo gitolite option - when /^option (.+) = (.*)/ - key = $1 - value = $2 + # found a repo definition + when /^repo (.*)/ + #Empty our current context + context = [] - raise ParseError, "Missing gitolite option value for repo: #{repo} and key: #{key}" if value.nil? + repos = $1.split + repos.each do |r| + context << r - context.each do |c| - @repos[c].set_gitolite_option(key, value) - end - #group definition - when /^#{Group::PREPEND_CHAR}(\S+) = ?(.*)/ - group = $1 - users = $2.split + @repos[r] = Repo.new(r) unless has_repo?(r) + end - @groups[group] = Group.new(group) unless has_group?(group) - @groups[group].add_users(users) - #gitweb definition - when /^(\S+)(?: "(.*?)")? = "(.*)"$/ - repo = $1 - owner = $2 - description = $3 + # repo permissions + when /^(-|C|R|RW\+?(?:C?D?|D?C?)M?) (.* )?= (.+)/ + perm = $1 + refex = $2 || "" + users = $3.split - #Check for missing description - raise ParseError, "Missing Gitweb description for repo: #{repo}" if description.nil? + context.each do |c| + @repos[c].add_permission(perm, refex, users) + end - #Check for groups - raise ParseError, "Gitweb descriptions cannot be set for groups" if repo =~ /@.+/ + # repo git config + when /^config (.+) = ?(.*)/ + key = $1 + value = $2 - if has_repo? repo - r = @repos[repo] - else - r = Repo.new(repo) - add_repo(r) - end + context.each do |c| + @repos[c].set_git_config(key, value) + end - r.owner = owner - r.description = description - when /^include "(.+)"/ - #TODO: implement includes - #ignore includes for now - when /^subconf (\S+)$/ - #TODO: implement subconfs - #ignore subconfs for now + # repo gitolite option + when /^option (.+) = (.*)/ + key = $1 + value = $2 + + raise ParseError, "Missing gitolite option value for repo: #{repo} and key: #{key}" if value.nil? + + context.each do |c| + @repos[c].set_gitolite_option(key, value) + end + + # group definition + when /^#{Group::PREPEND_CHAR}(\S+) = ?(.*)/ + group = $1 + users = $2.split + + @groups[group] = Group.new(group) unless has_group?(group) + @groups[group].add_users(users) + + # gitweb definition + when /^(\S+)(?: "(.*?)")? = "(.*)"$/ + 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 - raise ParseError, "'#{line}' cannot be processed" - end - end - end + r = Repo.new(repo) + add_repo(r) + 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 + r.owner = owner + r.description = description + + when /^include "(.+)"/ + #TODO: implement includes + #ignore includes for now + + when /^subconf (\S+)$/ + #TODO: implement subconfs + #ignore subconfs for now + else - context + raise ParseError, "'#{line}' cannot be processed" end 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 + + # 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 - super - end + context end + end - # Builds a dependency tree from the groups in order to ensure all groups - # are defined before they are used - def build_groups_depgraph - dp = ::GRATR::Digraph.new - # Add each group to the graph - @groups.each_value do |group| - dp.add_vertex! group + 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 - # Select group names from the users - subgroups = group.users.select {|u| u =~ /^#{Group::PREPEND_CHAR}.*$/}.map{|g| get_group g.gsub(Group::PREPEND_CHAR, '') } - subgroups.each do |subgroup| - dp.add_edge! subgroup, group - end - end + # Builds a dependency tree from the groups in order to ensure all groups + # are defined before they are used + def build_groups_depgraph + dp = ::Plexus::Digraph.new - # Figure out if we have a good depedency graph - dep_order = dp.topsort + # Add each group to the graph + @groups.each_value do |group| + dp.add_vertex! group - if dep_order.empty? - raise GroupDependencyError unless @groups.empty? - end + # Select group names from the users + subgroups = group.users.select {|u| u =~ /^#{Group::PREPEND_CHAR}.*$/}.map{|g| get_group g.gsub(Group::PREPEND_CHAR, '') } - dep_order + subgroups.each do |subgroup| + dp.add_edge! subgroup, group + end end - #Raised when something in a config fails to parse properly - class ParseError < RuntimeError - end + # Figure out if we have a good depedency graph + dep_order = dp.topsort - # Raised when group dependencies cannot be suitably resolved for output - class GroupDependencyError < RuntimeError + if dep_order.empty? + raise GroupDependencyError unless @groups.empty? end + + dep_order + end + + + #Raised when something in a config fails to parse properly + class ParseError < RuntimeError + end + + + # Raised when group dependencies cannot be suitably resolved for output + class GroupDependencyError < RuntimeError + end + end end