Subversion Repositories DevTools

Rev

Rev 5848 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
229 dpurdie 1
#! perl
2
########################################################################
6177 dpurdie 3
# COPYRIGHT - VIX IP PTY LTD ("VIX"). ALL RIGHTS RESERVED.
229 dpurdie 4
#
5
# Module name   : jats.sh
6
# Module type   : Makefile system
7
# Compiler(s)   : n/a
8
# Environment(s): jats
9
#
10
# Description   : Metrics gathering utility
11
#                 This is a JATS command line utility that is designed to be
12
#                 used by the automated build environment to gather metrics
13
#
14
#                 The utilty should be called:
15
#                   1) After a sandbox has been populated, but before
16
#                      a 'build' has been performed. This allows basic
17
#                      information to be collected.
18
#
19
#                   2) After the build has been completed, but before the
20
#                      final package has been transferred to dpkg_archive
21
#                      This allows build information to be collected and
22
#                      possibly inserted into the descpkg file. Information
23
#                      is also prepared for transfer to the Release Manager.
24
#
25
#               All calls should be performed in the same directory
26
#               The utility will maintain state information in a file in the
27
#               'current' directory. This will be created by the first
28
#               invocation and used by later invocations.
29
#
30
#
31
# Implementation Notes:
32
#
33
#
34
#
35
# Usage:    jats_metrics
36
#
37
#......................................................................#
38
 
255 dpurdie 39
require 5.006_001;
229 dpurdie 40
use strict;
41
use warnings;
42
 
43
use JatsError;
44
use FileUtils;
45
use JatsSystem;
46
use JatsEnv;
47
use JatsProperties;
48
 
49
use Getopt::Long;
50
use Pod::Usage;                             # required for help support
51
use File::Find;
52
 
53
 
54
################################################################################
55
#   Option variables
56
#
57
 
58
my $VERSION = "1.0.0";                      # Update this
59
my $opt_verbose = 0;
60
my $opt_debug = 0;
61
my $opt_help = 0;
62
my $opt_manual;
63
my $opt_mode;
64
my $opt_datafile = 'jats_metrics.dat';
65
my $opt_root;
66
my $opt_outfile;
67
 
68
#   Globals
69
#
70
our $GBE_TOOLS;
71
our $GBE_PERL;
72
 
73
our $find_dirs;
74
our $find_files;
75
our $find_makefiles;
76
our $find_depth;
77
 
78
my  $joiner_char = ';';
79
 
80
#
81
#   Option parsing
82
#
83
my $result = GetOptions (
84
                "help+"         => \$opt_help,          # flag, multiple use allowed
85
                "manual"        => \$opt_manual,        # flag
86
                "verbose+"      => \$opt_verbose,       # flag
87
                "debug+"        => \$opt_debug,         # flag
88
                "mode=s"        => \$opt_mode,          # string
89
                "datafile=s"    => \$opt_datafile,      # string
90
                "outfile=s"     => \$opt_outfile,       # string
91
                "rootdir=s"     => \$opt_root,          # string
92
                );
93
 
94
#
95
#   Process help and manual options
96
#
97
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
98
pod2usage(-verbose => 1)  if ($opt_help == 2 );
99
pod2usage(-verbose => 2)  if ($opt_manual || ($opt_help > 2));
100
 
101
#
102
#   Configure the error reporting process now that we have the user options
103
#
104
ErrorConfig( 'name'    =>'METRICS',
105
             'verbose' => $opt_verbose,
106
             'debug'   => $opt_debug
107
              );
108
 
109
#
110
#   Sanity test the user arguemnts
111
#
112
Error ("Too many command line arguments: @ARGV" )
113
    if ( $#ARGV >= 0 );
114
 
115
Error ("No mode specified. Use -mode='mode'")
116
    unless ( $opt_mode );
117
 
118
#
119
#   This program requires a 'mode' selector
120
#   Ensure that a suitable MODE has been used, then
121
#   Invoke a 'mode' subroutineto do the hard work
122
#
123
{
124
    my $mode_sub = "mode_$opt_mode";
125
    Error ("Unknown mode: $opt_mode") unless ( exists &$mode_sub );
126
 
127
    no strict 'refs';
128
    &$mode_sub();
129
}
130
exit 0;
131
 
132
#-------------------------------------------------------------------------------
133
# Function        : mode_init
134
#
135
# Description     : Perform the initial metrics collection process
136
#                   This must be called within a clean build area as
137
#                   it will gather metrics on files and folders.
138
#                   If there are build artifacts in the area, then these will
139
#                   be included in the metrics.
140
#
141
#                   The init phase will gather metrics on:
142
#                       SLOC
143
#                       Files and Folders
144
#                       ClearCase branches
145
#
146
#
147
# Inputs          : None. Parameters extracted from global option variables
148
#
149
# Returns         : Will not retuirn on error
150
#
151
sub mode_init
152
{
153
    my $data = JatsProperties::New();
154
 
155
    Message ("Initial Metrics Collection");
156
 
157
    #
158
    #   Validate required parameters
159
    #
160
    Error ("Root directory not specified") unless ( defined $opt_root );
161
    Error ("Root directory does not exist") unless ( -e $opt_root );
162
    Error ("Root directory is not a directory") unless ( -d $opt_root );
163
 
164
    Verbose ("Determine LOC");
165
    EnvImport( "GBE_TOOLS" );
5282 dpurdie 166
    my $cloc = "$GBE_TOOLS/cloc-1.65.pl";
229 dpurdie 167
    Error ("Cannot find cloc utility","Need: $cloc") unless ( -f $cloc );
168
 
169
    #
170
    #   Invoke a standard version of cloc
171
    #   Parse the text output.
172
    #       NOTE: It may be better to modify cloc to get the required data
173
    #
174
    EnvImport( "GBE_PERL" );
175
 
176
    open(CMD, "$GBE_PERL $cloc --no3 $opt_root 2>&1 |") || Error "Can't run command: cloc...", "Reason: $!";
177
    while (<CMD>)
178
    {
179
        #
180
        #   The command output contains both \r and \n terminators
181
        #   Just to be neat we will split the line again
182
        #
183
        foreach  ( split ('[\r\n]', $_ ) )
184
        {
185
            Verbose2 ( "cloc resp:" . $_);
186
            $data->setProperty('code.ignored', $1) if ( m~(\d+)\s+files ignored~ );
187
            if ( m~^SUM:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)~ )
188
            {
189
                $data->setProperty('code.files',   $1);
190
                $data->setProperty('lines.blank',   $2);
191
                $data->setProperty('lines.comment', $3);
192
                $data->setProperty('lines.code',    $4);
193
            }
194
        }
195
    }
196
    close(CMD);
197
    Verbose2 "Exit Status: $?";
198
    Error ("cloc program reported error: $?") if ($?);
199
 
200
    #
201
    #   Scan the complete directory tree looking for
202
    #       files
203
    #       directories
204
    #       makefiles.pl
205
    #
206
    Verbose ("Determine Files and Dirs");
207
    $find_dirs = 0;
208
    $find_files = 0;
209
    $find_makefiles = 0;
210
    $find_depth = 0;
211
 
212
    #
213
    #   Helper routine to count files and directories
214
    #   Used by File::Find:find
215
    #
216
    sub find_filecounter
217
    {
218
        if ( -d $_ ) {
219
            $find_dirs++;
220
            my @count = split ('[\\/]', $File::Find::dir );
221
            my $count = $#count + 1;
222
            $find_depth = $count if ( $count > $find_depth );
223
 
224
        } else {
225
            $find_files++;
226
        }
227
 
228
        if ( $_ =~ 'makefile.pl' ) {
229
            $find_makefiles++;
230
        } elsif ( $_ =~ m~\w+depends\.xml$~ ) {
231
            $find_makefiles++;
232
        }
233
    }
234
 
235
    #
236
    #       Under Unix we need to follow symbolic links, but Perl's
237
    #       Find:find does not work with -follow under windows if the source
238
    #       path contains a drive letter.
239
    #
240
    #       Solution. Only use follow under non-windows systems.
241
    #                 Works as Windows does not have symlinks (yet).
242
    #
243
    my $follow_opt =  ($ENV{GBE_UNIX}  > 0);
244
    File::Find::find( {wanted => \&find_filecounter, follow_fast => $follow_opt }, $opt_root );
245
 
246
 
247
    $data->setProperty('count.file', $find_files);
248
    $data->setProperty('count.dir',  $find_dirs);
249
    $data->setProperty('count.dirdepth',  $find_depth);
250
    $data->setProperty('count.makefile',  $find_makefiles);
251
 
5284 dpurdie 252
    #
5848 dpurdie 253
    #   Dirty test for Subversion or Git usage
5284 dpurdie 254
    #
5848 dpurdie 255
    if ( -d '.svn' || -d '.git' )
5284 dpurdie 256
    {
257
        Message('Subversion workspace');
258
    }
259
    else
260
    {
229 dpurdie 261
        #
4247 dpurdie 262
        #   Determine the number of clearcase branches used by files
263
        #   and folders in this view
229 dpurdie 264
        #
4247 dpurdie 265
        Verbose ("Determine ClearCase branches");
229 dpurdie 266
 
267
        #
5284 dpurdie 268
        #   Ensure that the 'cleartool' program can be located
269
        #
270
        Verbose2 ("Locate clearcase utility in users path");
271
        Error ("Cannot locate the 'cleartool' utility in the users PATH")
272
            unless ( LocateProgInPath('cleartool', '--All') );
229 dpurdie 273
 
5284 dpurdie 274
        my %branches;
275
        my $cmd = QuoteCommand (qw (cleartool ls -vob_only -visible -rec -short), $opt_root );
276
        Verbose2($cmd);
229 dpurdie 277
 
5284 dpurdie 278
        open(CMD, "$cmd 2>&1 |") || Error( "can't run command: $!");
279
        while (<CMD>)
280
        {
281
            chomp;
282
            tr~\\/~/~s;                 # Clean up and convert multiple / and \ -> /
4247 dpurdie 283
 
5284 dpurdie 284
            #
285
            #   If we are not within a VOB, then we will get errors
286
            #
287
            if ( m~cleartool: Error:~i )
288
            {
289
                Verbose ( $_ );
290
                next;
291
            }
4247 dpurdie 292
 
5284 dpurdie 293
            #
294
            #   Split the line into filename and branch
295
            #   Only want the last branch. DOn't need the version on the branch
296
            #
297
            m~([^/]+)\@\@.*/(.+)/\d+~;
298
            my $file = $1;
299
            my $branch = $2;
300
            Verbose2( "ct ls: " . $_ . ": $file,[$branch]");
4247 dpurdie 301
 
5284 dpurdie 302
            #
303
            #   Ignore build files
304
            #   Try to catch naughty users that put non-buildfiles onthe auto builder branch
305
            #
306
            next if ( $file eq 'build.pl' );
307
            next if ( $file =~ m~depends\.xml$~ );
4247 dpurdie 308
 
5284 dpurdie 309
            $branches{$branch} = 0
310
                unless ( exists $branches{$branch} );
311
            $branches{$branch}++;
312
        }
313
        close(CMD);
314
 
315
        my @blist = sort keys %branches;
316
        $data->setProperty('ccbranch.count',  1 + $#blist );
317
        $data->setProperty('ccbranch.list',  join (',', @blist) );
229 dpurdie 318
    }
319
 
320
    #
321
    #   All done
322
    #   Save the current set of metrics
323
    #
324
    $data->setProperty('done.init', 1);
325
    $data->Dump('Init') if ($opt_verbose);
326
    $data->store( $opt_datafile );
327
}
328
 
329
#-------------------------------------------------------------------------------
330
# Function        : mode_finish
331
#
332
# Description     : Perform the final metrics collection process
333
#                   This will populate a specified file with metrics data
334
#
335
# Inputs          : None. Parameters extracted from global option variables
336
#
337
#
338
# Returns         : Will not retuirn on error
339
#
340
sub mode_finish
341
{
342
    Message ("Finish Metrics Collection");
343
 
344
    #
345
    #   Read in the accumulated properties information
346
    #   The file must be present, in the default location, or the location
347
    #   specified by the user.
348
    #
349
    my $data = JatsProperties::New($opt_datafile);
350
 
351
    #
352
    #   Validate required parameters
353
    #
354
    Error ("Output file not specified") unless ( defined $opt_outfile );
355
    Error ("Output file exists and is a directory") if ( -d $opt_outfile );
356
 
357
    unlink $opt_outfile;
358
    Error ("Output file cannot ") if ( -e $opt_outfile );
359
 
360
    #
361
    #   Create a data blob that can be passed through to release manager
362
    #   Design notes:
363
    #       Will not be processed by anything other than Release Manager
364
    #       Data may conatin spaces and commas
365
    #       Data needs to be easy to parse at far end
366
    #
367
    $data->Dump('finish') if ($opt_verbose);
368
    $data->Dump() if ($opt_verbose);
369
 
261 dpurdie 370
    my $mdata = '';
229 dpurdie 371
    my $joiner = '';
261 dpurdie 372
 
229 dpurdie 373
    foreach my $name ( sort $data->enum() )
374
    {
375
        my $value = $data->getProperty($name);
376
 
377
        #
378
        #   Since the data fields will be seperated with a $joiner_char, we must
379
        #   make sure that we don't have the character within the data stream
380
        #
381
        Error ("Metric data  contains a '$joiner_char'",
382
               "Name: $name, Value: $value" ) if ( $value =~ m~$joiner_char~ );
383
 
261 dpurdie 384
        $mdata .= "$joiner$name=$value";
229 dpurdie 385
        $joiner = $joiner_char;
386
    }
261 dpurdie 387
 
388
    FileCreate ( $opt_outfile, $mdata );
229 dpurdie 389
}
390
 
391
 
392
#-------------------------------------------------------------------------------
393
#   Documentation
394
#
395
 
396
=pod
397
 
361 dpurdie 398
=for htmltoc    SYSUTIL::
399
 
229 dpurdie 400
=head1 NAME
401
 
402
jats_metrics - Gather and Process build metrics
403
 
404
=head1 SYNOPSIS
405
 
406
  jats etool jats_metrics [options]
407
 
408
 Options:
409
    -help               - brief help message
410
    -help -help         - Detailed help message
411
    -man                - Full documentation
412
    -verbose            - Verbose operation
413
    -mode=MODE          - Specifies mode of operation (Mandatoty)
414
    -datafile=path      - Path to the metrics data file
415
    -outfile=file       - Output file
416
    -rootdir=path       - Base of the package to process
417
 
418
 
419
=head1 OPTIONS
420
 
421
=over 8
422
 
423
=item B<-help>
424
 
425
Print a brief help message and exits.
426
 
427
=item B<-help -help>
428
 
429
Print a detailed help message with an explanation for each option.
430
 
431
=item B<-man>
432
 
433
Prints the manual page and exits.
434
 
435
=item B<-verbose>
436
 
437
Increases program output. This option may be specified mutiple times
438
 
439
 
440
=item B<-mode=MODE>
441
 
442
This mandatory parameter specifies the mode in which the metrix gathering
443
program will operate. MODE must be one of:
444
 
445
=over 8
446
 
361 dpurdie 447
=item *
229 dpurdie 448
 
361 dpurdie 449
init
229 dpurdie 450
 
361 dpurdie 451
=item *
452
 
453
finish
454
 
229 dpurdie 455
=back
456
 
457
=item B<-datafile=path>
458
 
459
This option allows the user to provide an alternate data file to be used by the
460
utilit. The default datafile is located in the current directory. Theis may be
461
reloacetd if required.
462
 
463
 
464
=item B<-outfile=xxx>
465
 
466
The name of the output file.
467
 
468
This option is mandatory for the 'finish' operation.
469
 
470
=item B<-rootdir=path>
471
 
472
This option specified the path to the base of the view to process. The path must
473
address a valid ClearCase view. Only files and directories below the root will
474
be considered.
475
 
476
This option is mandatory for the 'init' operation.
477
 
478
=back
479
 
480
=head1 DESCRIPTION
481
 
482
This JATS utility is used within the build system to perform a number of file
483
mertics gathering and processing operations. The utility performs one of the
484
sub-comamnds as specified by the B<-mode> option.
485
 
486
=cut
487