Chris@1538
|
1 #!/usr/bin/env ruby
|
Chris@1538
|
2
|
Chris@1538
|
3 # Create authormap files for hg repos based on the changeset & project
|
Chris@1538
|
4 # member info available to Redmine.
|
Chris@1538
|
5 #
|
Chris@1538
|
6 # We have a set of hg repos in a given directory:
|
Chris@1538
|
7 #
|
Chris@1538
|
8 # /var/hg/repo_1
|
Chris@1538
|
9 # /var/hg/repo_2
|
Chris@1538
|
10 # /var/hg/repo_3
|
Chris@1538
|
11 #
|
Chris@1538
|
12 # and we want to produce authormap files in another directory:
|
Chris@1538
|
13 #
|
Chris@1538
|
14 # /var/repo-export/authormap/authormap_repo_1
|
Chris@1538
|
15 # /var/repo-export/authormap/authormap_repo_2
|
Chris@1538
|
16 # /var/repo-export/authormap/authormap_repo_3
|
Chris@1538
|
17 #
|
Chris@1538
|
18 # This script does that, if given the two directory names as arguments
|
Chris@1538
|
19 # to the -s and -o options. In the above example:
|
Chris@1538
|
20 #
|
Chris@1543
|
21 # ./script/rails runner -e production extra/soundsoftware/create-repo-authormaps.rb -s /var/hg -o /var/repo-export/authormap
|
Chris@1538
|
22 #
|
Chris@1538
|
23 # Note that this script will overwrite any existing authormap
|
Chris@1538
|
24 # files. (That's why the output files are given an authormap_ prefix,
|
Chris@1538
|
25 # so we're less likely to clobber something else if the user gets the
|
Chris@1538
|
26 # arguments wrong.)
|
Chris@1538
|
27
|
Chris@1538
|
28 require 'getoptlong'
|
Chris@1538
|
29
|
Chris@1538
|
30 opts = GetoptLong.new(
|
Chris@1543
|
31 ['--scm-dir', '-s', GetoptLong::REQUIRED_ARGUMENT],
|
Chris@1543
|
32 ['--out-dir', '-o', GetoptLong::REQUIRED_ARGUMENT],
|
Chris@1543
|
33 ['--environment', '-e', GetoptLong::OPTIONAL_ARGUMENT]
|
Chris@1538
|
34 )
|
Chris@1538
|
35
|
Chris@1538
|
36 $repos_base = ''
|
Chris@1538
|
37 $out_base = ''
|
Chris@1538
|
38
|
Chris@1538
|
39 def usage
|
Chris@1538
|
40 puts "See source code for supported options"
|
Chris@1538
|
41 exit
|
Chris@1538
|
42 end
|
Chris@1538
|
43
|
Chris@1538
|
44 begin
|
Chris@1538
|
45 opts.each do |opt, arg|
|
Chris@1538
|
46 case opt
|
Chris@1538
|
47 when '--scm-dir'; $repos_base = arg.dup
|
Chris@1538
|
48 when '--out-dir'; $out_base = arg.dup
|
Chris@1538
|
49 end
|
Chris@1538
|
50 end
|
Chris@1538
|
51 rescue
|
Chris@1538
|
52 exit 1
|
Chris@1538
|
53 end
|
Chris@1538
|
54
|
Chris@1538
|
55 if ($repos_base.empty? or $out_base.empty?)
|
Chris@1538
|
56 usage
|
Chris@1538
|
57 end
|
Chris@1538
|
58
|
Chris@1538
|
59 unless File.directory?($repos_base)
|
chris@1540
|
60 puts "input directory '#{$repos_base}' doesn't exist"
|
chris@1540
|
61 exit 1
|
Chris@1538
|
62 end
|
Chris@1538
|
63
|
Chris@1538
|
64 unless File.directory?($out_base)
|
chris@1540
|
65 puts "output directory '#{$out_base}' doesn't exist"
|
chris@1540
|
66 exit 1
|
Chris@1538
|
67 end
|
Chris@1538
|
68
|
Chris@1538
|
69 projects = Project.find(:all)
|
Chris@1538
|
70
|
Chris@1538
|
71 if projects.nil?
|
chris@1540
|
72 puts 'No projects found'
|
chris@1540
|
73 exit 1
|
Chris@1538
|
74 end
|
Chris@1538
|
75
|
Chris@1538
|
76 projects.each do |proj|
|
Chris@1548
|
77
|
Chris@1548
|
78 next unless proj.is_public
|
Chris@1548
|
79
|
Chris@1538
|
80 next unless proj.respond_to?(:repository)
|
Chris@1538
|
81
|
Chris@1538
|
82 repo = proj.repository
|
chris@1539
|
83 next if repo.nil? or repo.url.empty?
|
Chris@1538
|
84
|
Chris@1538
|
85 repo_url = repo.url
|
Chris@1538
|
86 repo_url = repo_url.gsub(/^file:\/*/, "/");
|
Chris@1538
|
87 if repo_url != File.join($repos_base, proj.identifier)
|
Chris@1542
|
88 puts "Project #{proj.identifier} has repo in unsupported location #{repo_url}, skipping"
|
Chris@1538
|
89 next
|
Chris@1538
|
90 end
|
Chris@1538
|
91
|
Chris@1542
|
92 committers = repo.committers
|
Chris@1538
|
93
|
Chris@1538
|
94 authormap = ""
|
Chris@1542
|
95 committers.each do |c, uid|
|
Chris@1552
|
96
|
Chris@1552
|
97 # Some of our repos have broken email addresses in them: e.g. one
|
Chris@1552
|
98 # changeset has a committer name of the form
|
Chris@1552
|
99 #
|
Chris@1552
|
100 # NAME <name <NAME <name@example.com">
|
Chris@1552
|
101 #
|
Chris@1552
|
102 # I don't know how it got like that... If the committer has more
|
Chris@1552
|
103 # than one '<' in it, truncate it just before the first one, and
|
Chris@1553
|
104 # then look up the author name again.
|
Chris@1553
|
105 #
|
Chris@1552
|
106 if c =~ /<.*</ then
|
Chris@1553
|
107 # So this is a completely pathological case
|
Chris@1553
|
108 user = User.find_by_id uid
|
Chris@1553
|
109 if user.nil? then
|
Chris@1553
|
110 # because the given committer is bogus, we must write something in the map
|
Chris@1554
|
111 name = c.sub(/\s*<.*$/, "")
|
Chris@1554
|
112 authormap << "#{c}=#{name} <unknown@example.com>\n"
|
Chris@1553
|
113 else
|
Chris@1553
|
114 authormap << "#{c}=#{user.name} <#{user.mail}>\n"
|
Chris@1553
|
115 end
|
Chris@1553
|
116 elsif not c =~ /[^<]+<.*@.*>/ then
|
Chris@1553
|
117 # This is the "normal" case that needs work, where a user has
|
Chris@1553
|
118 # their name in the commit but no email address
|
Chris@1542
|
119 user = User.find_by_id uid
|
chris@1539
|
120 authormap << "#{c}=#{user.name} <#{user.mail}>\n" unless user.nil?
|
Chris@1538
|
121 end
|
Chris@1538
|
122 end
|
Chris@1538
|
123
|
chris@1539
|
124 File.open(File.join($out_base, "authormap_#{proj.identifier}"), "w") do |f|
|
Chris@1538
|
125 f.puts(authormap)
|
Chris@1538
|
126 end
|
Chris@1538
|
127
|
Chris@1538
|
128 end
|
Chris@1538
|
129
|