Chris@1538: #!/usr/bin/env ruby Chris@1538: Chris@1538: # Create authormap files for hg repos based on the changeset & project Chris@1538: # member info available to Redmine. Chris@1538: # Chris@1538: # We have a set of hg repos in a given directory: Chris@1538: # Chris@1538: # /var/hg/repo_1 Chris@1538: # /var/hg/repo_2 Chris@1538: # /var/hg/repo_3 Chris@1538: # Chris@1538: # and we want to produce authormap files in another directory: Chris@1538: # Chris@1538: # /var/repo-export/authormap/authormap_repo_1 Chris@1538: # /var/repo-export/authormap/authormap_repo_2 Chris@1538: # /var/repo-export/authormap/authormap_repo_3 Chris@1538: # Chris@1538: # This script does that, if given the two directory names as arguments Chris@1538: # to the -s and -o options. In the above example: Chris@1538: # Chris@1543: # ./script/rails runner -e production extra/soundsoftware/create-repo-authormaps.rb -s /var/hg -o /var/repo-export/authormap Chris@1538: # Chris@1538: # Note that this script will overwrite any existing authormap Chris@1538: # files. (That's why the output files are given an authormap_ prefix, Chris@1538: # so we're less likely to clobber something else if the user gets the Chris@1538: # arguments wrong.) Chris@1538: Chris@1538: require 'getoptlong' Chris@1538: Chris@1538: opts = GetoptLong.new( Chris@1543: ['--scm-dir', '-s', GetoptLong::REQUIRED_ARGUMENT], Chris@1543: ['--out-dir', '-o', GetoptLong::REQUIRED_ARGUMENT], Chris@1543: ['--environment', '-e', GetoptLong::OPTIONAL_ARGUMENT] Chris@1538: ) Chris@1538: Chris@1538: $repos_base = '' Chris@1538: $out_base = '' Chris@1538: Chris@1538: def usage Chris@1538: puts "See source code for supported options" Chris@1538: exit Chris@1538: end Chris@1538: Chris@1538: begin Chris@1538: opts.each do |opt, arg| Chris@1538: case opt Chris@1538: when '--scm-dir'; $repos_base = arg.dup Chris@1538: when '--out-dir'; $out_base = arg.dup Chris@1538: end Chris@1538: end Chris@1538: rescue Chris@1538: exit 1 Chris@1538: end Chris@1538: Chris@1538: if ($repos_base.empty? or $out_base.empty?) Chris@1538: usage Chris@1538: end Chris@1538: Chris@1538: unless File.directory?($repos_base) chris@1540: puts "input directory '#{$repos_base}' doesn't exist" chris@1540: exit 1 Chris@1538: end Chris@1538: Chris@1538: unless File.directory?($out_base) chris@1540: puts "output directory '#{$out_base}' doesn't exist" chris@1540: exit 1 Chris@1538: end Chris@1538: Chris@1538: projects = Project.find(:all) Chris@1538: Chris@1538: if projects.nil? chris@1540: puts 'No projects found' chris@1540: exit 1 Chris@1538: end Chris@1538: Chris@1538: projects.each do |proj| Chris@1548: Chris@1548: next unless proj.is_public Chris@1548: Chris@1538: next unless proj.respond_to?(:repository) Chris@1538: Chris@1538: repo = proj.repository chris@1539: next if repo.nil? or repo.url.empty? Chris@1538: Chris@1538: repo_url = repo.url Chris@1538: repo_url = repo_url.gsub(/^file:\/*/, "/"); Chris@1538: if repo_url != File.join($repos_base, proj.identifier) Chris@1542: puts "Project #{proj.identifier} has repo in unsupported location #{repo_url}, skipping" Chris@1538: next Chris@1538: end Chris@1538: Chris@1542: committers = repo.committers Chris@1538: Chris@1538: authormap = "" Chris@1542: committers.each do |c, uid| Chris@1552: Chris@1552: # Some of our repos have broken email addresses in them: e.g. one Chris@1552: # changeset has a committer name of the form Chris@1552: # Chris@1552: # NAME Chris@1552: # Chris@1552: # I don't know how it got like that... If the committer has more Chris@1552: # than one '<' in it, truncate it just before the first one, and Chris@1553: # then look up the author name again. Chris@1553: # Chris@1552: if c =~ /<.*\n" Chris@1553: else Chris@1553: authormap << "#{c}=#{user.name} <#{user.mail}>\n" Chris@1553: end Chris@1553: elsif not c =~ /[^<]+<.*@.*>/ then Chris@1553: # This is the "normal" case that needs work, where a user has Chris@1553: # their name in the commit but no email address Chris@1542: user = User.find_by_id uid chris@1539: authormap << "#{c}=#{user.name} <#{user.mail}>\n" unless user.nil? Chris@1538: end Chris@1538: end Chris@1538: chris@1539: File.open(File.join($out_base, "authormap_#{proj.identifier}"), "w") do |f| Chris@1538: f.puts(authormap) Chris@1538: end Chris@1538: Chris@1538: end Chris@1538: