1 | #!/usr/bin/perl |
---|
2 | # ------------------------------------------------------------------------------ |
---|
3 | # NAME |
---|
4 | # fcm_add_trac.pl |
---|
5 | # |
---|
6 | # SYNOPSIS |
---|
7 | # fcm_add_trac.pl [OPTIONS] <system> |
---|
8 | # fcm_add_trac.pl -h |
---|
9 | # |
---|
10 | # DESCRIPTION |
---|
11 | # See $usage for further information. |
---|
12 | # |
---|
13 | # COPYRIGHT |
---|
14 | # (C) Crown copyright Met Office. All rights reserved. |
---|
15 | # For further details please refer to the file COPYRIGHT.txt |
---|
16 | # which you should have received as part of this distribution. |
---|
17 | # ------------------------------------------------------------------------------ |
---|
18 | |
---|
19 | # Standard pragmas |
---|
20 | use strict; |
---|
21 | use warnings; |
---|
22 | |
---|
23 | # Standard modules |
---|
24 | use Getopt::Long; |
---|
25 | use File::Basename; |
---|
26 | use File::Spec; |
---|
27 | use Config::IniFiles; |
---|
28 | |
---|
29 | # In-house modules |
---|
30 | use lib File::Spec->catfile ( |
---|
31 | dirname ( |
---|
32 | (grep {-x File::Spec->catfile ($_, 'fcm')} split (/:/, $ENV{PATH})) [0] |
---|
33 | ), |
---|
34 | 'lib', |
---|
35 | ); |
---|
36 | use Fcm::Util; |
---|
37 | |
---|
38 | # ------------------------------------------------------------------------------ |
---|
39 | |
---|
40 | # Program information |
---|
41 | my $this = basename ($0); |
---|
42 | my $year = (localtime)[5] + 1900; |
---|
43 | my $copyright = <<EOF; |
---|
44 | |
---|
45 | (C) Crown copyright $year Met Office. All rights reserved. |
---|
46 | EOF |
---|
47 | my $usage = <<EOF; |
---|
48 | NAME |
---|
49 | $this: add a new Trac browser for a FCM project |
---|
50 | |
---|
51 | SYNOPSIS |
---|
52 | $this [OPTIONS] <project> # normal usage |
---|
53 | $this [-h] # print help and exit |
---|
54 | |
---|
55 | DESCRIPTION |
---|
56 | This script adds a new Trac browser for a project managed by FCM. The name of |
---|
57 | the project is specified in the first argument. |
---|
58 | |
---|
59 | With the except of --authorised and --help, all options to the script take at |
---|
60 | least one argument. If an option can take more than one argument, the |
---|
61 | arguments should be specified in a comma-separated list. |
---|
62 | |
---|
63 | OPTIONS |
---|
64 | -a, --authorised - specify an "authorised" permission. Only those users |
---|
65 | granted this permission will have "_CREATE" and |
---|
66 | "_MODIFY" access. The default is to grant all |
---|
67 | authenticated users "_CREATE" and "_MODIFY" access. |
---|
68 | |
---|
69 | -c, --component - specify one or more components. |
---|
70 | |
---|
71 | -d, --description - specify a description of the project. |
---|
72 | |
---|
73 | -e, --smtp-always-cc - specify one or more e-mail addresses, where e-mails |
---|
74 | will be sent to on ticket changes. |
---|
75 | |
---|
76 | -h, --help - prints the usage string and exits. |
---|
77 | |
---|
78 | -m, --milestone - specify one or more milestones. |
---|
79 | |
---|
80 | -s, --svn-repos - specify the Subversion repository location. Use an |
---|
81 | empty string if no Subversion repository is needed. |
---|
82 | |
---|
83 | -u, --admin-user - specify one or more admin users. |
---|
84 | |
---|
85 | -v, --version - specify one or more versions. |
---|
86 | $copyright |
---|
87 | EOF |
---|
88 | |
---|
89 | # ------------------------------------------------------------------------------ |
---|
90 | |
---|
91 | # Options |
---|
92 | my ($authorised, $help, $description, $svn_repos); |
---|
93 | my (@admin_users, @components, @emails, @milestones, @versions); |
---|
94 | |
---|
95 | GetOptions ( |
---|
96 | 'a|authorised' => \$authorised, |
---|
97 | 'c|component=s' => \@components, |
---|
98 | 'd|description=s' => \$description, |
---|
99 | 'e|smtp-always-cc=s' => \@emails, |
---|
100 | 'h|help' => \$help, |
---|
101 | 'm|milestone=s' => \@milestones, |
---|
102 | 's|svn-repos=s' => \$svn_repos, |
---|
103 | 'u|admin-user=s' => \@admin_users, |
---|
104 | 'v|version=s' => \@versions, |
---|
105 | ); |
---|
106 | |
---|
107 | @admin_users = split (/,/, join (',', @admin_users)); |
---|
108 | @components = split (/,/, join (',', @components)); |
---|
109 | @emails = split (/,/, join (',', @emails)); |
---|
110 | @milestones = split (/,/, join (',', @milestones)); |
---|
111 | @versions = split (/,/, join (',', @versions)); |
---|
112 | |
---|
113 | if ($help) { |
---|
114 | print $usage; |
---|
115 | exit; |
---|
116 | } |
---|
117 | |
---|
118 | # Arguments |
---|
119 | my $project = $ARGV[0]; |
---|
120 | if (not $project) { |
---|
121 | print $usage; |
---|
122 | exit; |
---|
123 | } |
---|
124 | |
---|
125 | # ------------------------------------------------------------------------------ |
---|
126 | |
---|
127 | # Useful variables |
---|
128 | my $svn_root = '/data/local/fcm/svn/live'; |
---|
129 | my $trac_root = File::Spec->catfile ((getpwnam ('fcm'))[7], 'trac', 'live'); |
---|
130 | |
---|
131 | # Parse the central configuration file |
---|
132 | my $central_ini = Config::IniFiles->new ( |
---|
133 | '-file' => File::Spec->catfile ($trac_root, 'trac.ini'), |
---|
134 | ); |
---|
135 | |
---|
136 | # ------------------------------------------------------------------------------ |
---|
137 | |
---|
138 | MAIN: { |
---|
139 | # Check for the existence of Trac for the current project |
---|
140 | # ---------------------------------------------------------------------------- |
---|
141 | my $trac_project = File::Spec->catfile ($trac_root, $project); |
---|
142 | die $this, ': ', $trac_project, ': already exists, abort' if -d $trac_project; |
---|
143 | |
---|
144 | # Check for the existence of SVN for the current project |
---|
145 | # ---------------------------------------------------------------------------- |
---|
146 | my $svn_project = defined ($svn_repos) |
---|
147 | ? $svn_repos |
---|
148 | : File::Spec->catfile ($svn_root, $project . '_svn'); |
---|
149 | die $this, ': ', $svn_project, ': does not exist, abort' |
---|
150 | if $svn_project and not -d $svn_project; |
---|
151 | |
---|
152 | # Set up "trac-admin" command for this project |
---|
153 | # ---------------------------------------------------------------------------- |
---|
154 | my @admin_cmd = ('trac-admin', $trac_project); |
---|
155 | |
---|
156 | # Create project's Trac |
---|
157 | my $trac_templates = '/usr/share/trac/templates'; |
---|
158 | |
---|
159 | my @command = ( |
---|
160 | @admin_cmd, |
---|
161 | 'initenv', |
---|
162 | $project, |
---|
163 | 'sqlite:db/trac.db', |
---|
164 | ($svn_project ? ('svn', $svn_project) : ('', '')), |
---|
165 | $trac_templates, |
---|
166 | ); |
---|
167 | |
---|
168 | &run_command (\@command, PRINT => 1); |
---|
169 | |
---|
170 | # Ensure the new Trac has the correct group and permissions |
---|
171 | &run_command ([qw/chgrp -R apache/, $trac_project], PRINT => 1); |
---|
172 | &run_command ([qw/chmod -R g+w/, $trac_project], PRINT => 1); |
---|
173 | |
---|
174 | # Components |
---|
175 | # ---------------------------------------------------------------------------- |
---|
176 | my @cur_cmd = (@admin_cmd, 'component'); |
---|
177 | |
---|
178 | # Remove example components |
---|
179 | for my $component (qw/component1 component2/) { |
---|
180 | &run_command ([@cur_cmd, 'remove', $component], PRINT => 1); |
---|
181 | } |
---|
182 | |
---|
183 | # Add specified components |
---|
184 | for my $component (@components) { |
---|
185 | &run_command ([@cur_cmd, 'add', $component, ''], PRINT => 1); |
---|
186 | } |
---|
187 | |
---|
188 | # List components |
---|
189 | &run_command ([@cur_cmd, 'list'], PRINT => 1); |
---|
190 | |
---|
191 | # Versions |
---|
192 | # ---------------------------------------------------------------------------- |
---|
193 | @cur_cmd = (@admin_cmd, 'version'); |
---|
194 | |
---|
195 | # Remove example versions |
---|
196 | for my $version (qw/1.0 2.0/) { |
---|
197 | &run_command ([@cur_cmd, 'remove', $version], PRINT => 1); |
---|
198 | } |
---|
199 | |
---|
200 | # Add specified versions |
---|
201 | for my $version (@versions) { |
---|
202 | &run_command ([@cur_cmd, 'add', $version], PRINT => 1); |
---|
203 | } |
---|
204 | |
---|
205 | # List versions |
---|
206 | &run_command ([@cur_cmd, 'list'], PRINT => 1); |
---|
207 | |
---|
208 | # Milestones |
---|
209 | # ---------------------------------------------------------------------------- |
---|
210 | @cur_cmd = (@admin_cmd, 'milestone'); |
---|
211 | |
---|
212 | # Remove example milestones |
---|
213 | for my $milestone (qw/milestone1 milestone2 milestone3 milestone4/) { |
---|
214 | &run_command ([@cur_cmd, 'remove', $milestone], PRINT => 1); |
---|
215 | } |
---|
216 | |
---|
217 | # Add specified milestones |
---|
218 | for my $milestone (@milestones) { |
---|
219 | &run_command ([@cur_cmd, 'add', $milestone], PRINT => 1); |
---|
220 | } |
---|
221 | |
---|
222 | # List milestones |
---|
223 | &run_command ([@cur_cmd, 'list'], PRINT => 1); |
---|
224 | |
---|
225 | # Priority |
---|
226 | # ---------------------------------------------------------------------------- |
---|
227 | @cur_cmd = (@admin_cmd, 'priority'); |
---|
228 | |
---|
229 | # Change default priorities |
---|
230 | my %priorities = ( |
---|
231 | blocker => 'highest', |
---|
232 | critical => 'high', |
---|
233 | major => 'normal', |
---|
234 | minor => 'low', |
---|
235 | trivial => 'lowest', |
---|
236 | ); |
---|
237 | while (my ($old, $new) = each %priorities) { |
---|
238 | &run_command ([@cur_cmd, 'change', $old, $new], PRINT => 1); |
---|
239 | } |
---|
240 | |
---|
241 | # List priorities |
---|
242 | &run_command ([@cur_cmd, 'list'], PRINT => 1); |
---|
243 | |
---|
244 | # Severity |
---|
245 | # ---------------------------------------------------------------------------- |
---|
246 | @cur_cmd = (@admin_cmd, 'severity'); |
---|
247 | |
---|
248 | # Add serverities |
---|
249 | for my $severity (qw/blocker critical major normal minor trivial/) { |
---|
250 | &run_command ([@cur_cmd, 'add', $severity], PRINT => 1); |
---|
251 | } |
---|
252 | |
---|
253 | # List serverities |
---|
254 | &run_command ([@cur_cmd, 'list'], PRINT => 1); |
---|
255 | |
---|
256 | # Permission |
---|
257 | # ---------------------------------------------------------------------------- |
---|
258 | @cur_cmd = (@admin_cmd, 'permission'); |
---|
259 | |
---|
260 | # Add permissions to admin users |
---|
261 | for my $user (@admin_users) { |
---|
262 | &run_command ([@cur_cmd, 'add', $user, 'admin'], PRINT => 1); |
---|
263 | } |
---|
264 | &run_command ([@cur_cmd, qw/add admin TRAC_ADMIN/], PRINT => 1); |
---|
265 | |
---|
266 | # Remove wiki/ticket create/modify permissions from anonymous users |
---|
267 | for my $per (qw/TICKET_CREATE TICKET_MODIFY WIKI_CREATE WIKI_MODIFY/) { |
---|
268 | &run_command ([@cur_cmd, qw/remove anonymous/, $per], PRINT => 1); |
---|
269 | } |
---|
270 | |
---|
271 | # Add wiki/ticket create/modify permissions to authenticated/authorised users |
---|
272 | for my $per (qw/TICKET_CREATE TICKET_MODIFY WIKI_CREATE WIKI_MODIFY/) { |
---|
273 | &run_command ( |
---|
274 | [@cur_cmd, 'add', ($authorised ? 'authorised' : 'authenticated'), $per], |
---|
275 | PRINT => 1, |
---|
276 | ); |
---|
277 | } |
---|
278 | |
---|
279 | # List permissions |
---|
280 | &run_command ([@cur_cmd, 'list'], PRINT => 1); |
---|
281 | |
---|
282 | # Misc modifications to "trac.ini" |
---|
283 | # ---------------------------------------------------------------------------- |
---|
284 | my $local_file = File::Spec->catfile ($trac_project, 'conf', 'trac.ini'); |
---|
285 | |
---|
286 | # Read and parse "trac.ini" |
---|
287 | my $local_ini = Config::IniFiles->new ('-file' => $local_file); |
---|
288 | |
---|
289 | # Descriptive name for the current project |
---|
290 | my $descr = $description ? $description : $project; |
---|
291 | |
---|
292 | # Default component |
---|
293 | my $def_component = @components ? $components [0] : ''; |
---|
294 | |
---|
295 | # List of e-mail addresses to always cc |
---|
296 | my $smtp_always_cc = @emails ? join (',', @emails) : ''; |
---|
297 | |
---|
298 | # List of "default" config, in [section, option, value] |
---|
299 | my @config = ( |
---|
300 | ['notification', 'smtp_always_cc' , $smtp_always_cc], |
---|
301 | ['project' , 'descr' , $descr], |
---|
302 | ['ticket' , 'default_component' , $def_component], |
---|
303 | ); |
---|
304 | |
---|
305 | for (@config) { |
---|
306 | my ($section, $option, $value) = @{ $_ }; |
---|
307 | |
---|
308 | # Add new section, if necessary |
---|
309 | $local_ini->AddSection ($section) |
---|
310 | if not $local_ini->SectionExists ($section); |
---|
311 | |
---|
312 | if (defined ($local_ini->val ($section, $option))) { |
---|
313 | # Modify existing option |
---|
314 | $local_ini->setval ($section, $option, $value); |
---|
315 | |
---|
316 | } else { |
---|
317 | # Add new option |
---|
318 | $local_ini->newval ($section, $option, $value); |
---|
319 | } |
---|
320 | } |
---|
321 | |
---|
322 | # Remove duplicated sections/options in the configuration file |
---|
323 | for my $section (($local_ini->Sections)) { |
---|
324 | # Remove comments |
---|
325 | $local_ini->DeleteSectionComment ($section); |
---|
326 | |
---|
327 | # Leave section in local configuration file if it does not exist in the |
---|
328 | # central configuration file |
---|
329 | next unless $central_ini->SectionExists ($section); |
---|
330 | |
---|
331 | for my $parameter (($local_ini->Parameters ($section))) { |
---|
332 | # Remove comments |
---|
333 | $local_ini->DeleteParameterComment ($section, $parameter); |
---|
334 | |
---|
335 | # Leave parameter in local configuration file if it does not exist in the |
---|
336 | # central configuration file |
---|
337 | my $central_value = $central_ini->val ($section, $parameter); |
---|
338 | next unless defined $central_value; |
---|
339 | |
---|
340 | # Remove local parameter if it is the same as the central one |
---|
341 | if ($central_value eq $local_ini->val ($section, $parameter)) { |
---|
342 | print 'Remove parameter: ', $parameter, ' in section: ', $section, "\n"; |
---|
343 | $local_ini->delval ($section, $parameter); |
---|
344 | } |
---|
345 | } |
---|
346 | |
---|
347 | # Remove section if it is empty |
---|
348 | if (not ($local_ini->Parameters ($section))) { |
---|
349 | print 'Remove section: ', $section, "\n"; |
---|
350 | $local_ini->DeleteSection ($section); |
---|
351 | } |
---|
352 | } |
---|
353 | |
---|
354 | # Rename original "trac.ini" to "trac.ini.orig" |
---|
355 | rename $local_file, $local_file . '.orig'; |
---|
356 | |
---|
357 | # Output modifications to "trac.ini" |
---|
358 | $local_ini->WriteConfig ($local_file); |
---|
359 | } |
---|
360 | |
---|
361 | # Finally... |
---|
362 | # ------------------------------------------------------------------------------ |
---|
363 | print $this, ': finished normally.', "\n"; |
---|
364 | exit; |
---|
365 | |
---|
366 | # ------------------------------------------------------------------------------ |
---|
367 | |
---|
368 | __END__ |
---|