Subversion Repositories DevTools

Rev

Rev 6762 | Rev 6923 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
4625 dpurdie 1
########################################################################
2
# Copyright (c) VIX TECHNOLOGY (AUST) LTD
3
#
4
# Module name   : process_release_notes.pl
5
# Module type   : JATS Utility
6
# Compiler(s)   : Perl
7
# Environment(s): jats
8
#
9
# Description   : Poll RM and generate Release Notes as required
10
#                 Must run on the same machine as the package archive
11
#                 It directly manipulates the target package
12
#                 Requires access to the machines sudo mechism
13
#
14
# Usage         : See POD at the end of this file
15
#
16
#......................................................................#
17
 
18
require 5.008_002;
19
 
20
use strict;
21
use warnings;
22
use JatsError;
23
use JatsSystem;
24
use Getopt::Long;
25
use Pod::Usage;                             # required for help support
26
use File::Temp qw/ tempfile tempdir /;
27
use LWP::UserAgent;
28
use HTTP::Request::Common 'POST';
29
use Fcntl ':flock';
30
use FindBin;                                # Determine the current directory
31
 
32
use JatsEnv;
33
use JatsRmApi;
34
use FileUtils;
35
 
36
use DBI;
37
 
38
my $VERSION = "1.0.0";                      # Update this
39
my $GBE_DPKG = $ENV{GBE_DPKG};              # Sanitised by Jats
4698 dpurdie 40
my $GBE_RM_URL = $ENV{GBE_RM_URL};
4625 dpurdie 41
my $RM_DB;
42
my $tempdir;
43
my $sudoUtilsDir = '/home/releasem/sbin';
44
my $lockFile = '/tmp/JATSRN_LOCK';
6762 dpurdie 45
my $lockFile1 = '/tmp/JATSRN_LOCK1';
4625 dpurdie 46
my $scriptDir = "$FindBin::Bin";
6758 dpurdie 47
my $maxRunTime = 5 * 60;                        # Seconds. Time to first warning
48
my $maxRunTime1 = 5 * 60;                       # Seconds. Time to following warnings
4625 dpurdie 49
 
50
#
51
#   Options
52
#
53
my $opt_verbose = 0;
54
my $opt_help = 0;
55
my $opt_age = 2;
56
my $opt_keepTemp = 0;
57
my $opt_status = 0;
58
my $opt_pvid;
59
 
60
#
61
#   Package information
62
#
63
my @Packages;
5586 dpurdie 64
my @packageItems = qw( PV_ID -LINK_PV_ID RTAG_ID NAME VERSION PKG_ID PROJ_ID RNINFO BUILD_TYPE BS_ID);
4625 dpurdie 65
my %rmConfig;
66
 
67
#-------------------------------------------------------------------------------
68
# Function        : Main Entry
69
#
70
# Description     :
71
#
72
# Inputs          :
73
#
74
# Returns         :
75
#
76
my $result = GetOptions (
77
                'help+'         => \$opt_help,          # flag, multiple use allowed
78
                'manual:3'      => \$opt_help,          # flag
79
                'verbose:+'     => \$opt_verbose,       # flag
80
                'age:i'         => \$opt_age,           # Number
81
                'keeptemp!'     => \$opt_keepTemp,      # flag
82
                'status+'       => \$opt_status,        # flag
83
                'pvid:i'        => \$opt_pvid,          # Number
84
                );
85
 
86
#
87
#   Process help and manual options
88
#
89
pod2usage(-verbose => 0, -message => "Version: $VERSION")  if ($opt_help == 1  || ! $result);
90
pod2usage(-verbose => 1)  if ($opt_help == 2);
91
pod2usage(-verbose => 2)  if ($opt_help > 2);
92
 
93
ErrorConfig( 'name'    =>'RelNotes', 
94
             'verbose' => $opt_verbose );
95
$opt_verbose-- if ($opt_verbose > 0);
96
#
97
#   Sanity Test
98
#
99
Error("Not running on a Unix System") unless ($ENV{GBE_UNIX});
100
Error("Sudo Utils not found: $sudoUtilsDir") unless ( -d $sudoUtilsDir);
101
Warning("Not running as a sutable user" ) unless ($ENV{USER} eq 'buildadm' || $ENV{USER} eq 'releasem');
102
EnvImport ('GBE_PERL');
103
 
104
#
105
#   Ensure only one instance is running
106
#   PerlMonks say to use $0 as the lock file, but that did not work.
6754 dpurdie 107
#       Perhaps the file was open in an editor
108
#       Solution: Create my own file
109
#   Generate an error if the script has been running for too long    
4625 dpurdie 110
#
6758 dpurdie 111
makeFile($lockFile);
112
makeFile($lockFile1) unless -f $lockFile1;
4625 dpurdie 113
 
114
open (my $self, '<', $lockFile) || Error("Couldn't open self: $!");
6754 dpurdie 115
unless ( flock ($self, (LOCK_EX | LOCK_NB)) ){
6758 dpurdie 116
 
117
    my $runTime = getFileTime($lockFile);
118
    my $runTime1 = getFileTime($lockFile1);
119
 
120
    if ( $runTime > $maxRunTime && $runTime1 >= $maxRunTime1) {
121
        unlink $lockFile1;
122
        makeFile($lockFile1);
6754 dpurdie 123
        Error("Script has been running for too long.: $runTime(s)");
124
    }
125
    exit(1);
126
}
4625 dpurdie 127
 
128
#
129
#   Init parameters
130
#
131
$tempdir = tempdir('/tmp/JATSRN_XXXXXX',CLEANUP => !$opt_keepTemp);
132
Warning("Need to remove tempdir: " . DisplayPath($tempdir)) if $opt_keepTemp;
133
Verbose("Tempdir:" , DisplayPath($tempdir));
134
Verbose("scriptDir:" , DisplayPath($scriptDir));
135
 
136
#   Force GBE_ABT. Currently the Release Manager proxy password only works
137
#   When used in this mode
138
$ENV{GBE_ABT} = 1 unless defined $ENV{GBE_ABT};
139
 
140
#
141
#   User RW password, if provided
142
#
143
$ENV{GBE_RM_USERNAME} = $ENV{GBE_RM_USERNAME_RW} if (exists $ENV{GBE_RM_USERNAME_RW});
144
$ENV{GBE_RM_PASSWORD} = $ENV{GBE_RM_PASSWORD_RW} if (exists $ENV{GBE_RM_PASSWORD_RW});
145
 
146
if ($ENV{GBE_ABT} && $ENV{GBE_RM_USERNAME} && $ENV{GBE_RM_USERNAME} !~ m~]$~ )
147
{
148
    Verbose("Access RM database as proxy user");
149
    $ENV{GBE_RM_USERNAME} = $ENV{GBE_RM_USERNAME} . '[release_manager]'; 
150
}
151
 
152
#
153
#   Interogate the RM database and locate packages that need to be processed
154
#
155
$opt_pvid ? LocatePackagesByPvid() : LocatePackages();
156
Verbose("Package to process:" . scalar @Packages);
157
#DebugDumpData("Packages", \@Packages);
158
 
159
#
160
#   Process each found entry
161
#
162
foreach my $entry ( @Packages)
163
{
164
    GenerateReleaseNote( $entry);
165
}
166
 
167
unlink $lockFile;
6758 dpurdie 168
unlink $lockFile1;
4625 dpurdie 169
exit 0;
170
 
171
#-------------------------------------------------------------------------------
172
# Function        : LocatePackages 
173
#
174
# Description     : Locate packages in need of Release Notes
5586 dpurdie 175
#                   The hard part is handling patches
176
#                   The sql will
177
#                       1) Locate packages that may need a release note
178
#                       2) Trace back to the most likly Release that the pakage is in
179
#                          For patches - it may be in many released
180
#                                        Use the latest
4625 dpurdie 181
#
182
# Inputs          : None
183
#
184
# Returns         : Nothing
185
#                   Populates the @Packages array
186
#
187
sub LocatePackages
188
{
189
    my $m_sqlstr =
5586 dpurdie 190
        "select * from (
191
          select aa.*, 
192
              rc.RTAG_ID,
193
              pkg.PKG_NAME, 
194
              pv.PKG_VERSION, 
195
              pv.pkg_id,
196
              rt.PROJ_ID, 
197
              pv.release_notes_info,
198
              pv.build_type,
199
              pv.BS_ID,
200
              TRUNC(sysdate - pv.modified_stamp ) AS age,
201
              row_number() OVER (PARTITION BY aa.pv_id, pkg.pkg_name, pv.pkg_version ORDER BY rc.rtag_id desc) rn
202
          from (
203
            SELECT pv.pv_id, NVL( pp.PV_ID, pv.pv_id) as LINK_PV_ID
204
              FROM release_manager.package_versions pv, release_manager.PACKAGE_PATCHES pp
205
              WHERE (release_notes_info IS NULL
206
              OR (release_notes_info LIKE 'MSG:%'
207
              AND release_notes_info != 'MSG:5' ))
208
              AND pv.dlocked          = 'Y'
209
              AND pv.modified_stamp   > (sysdate - $opt_age)
210
              AND pv.pv_id = pp.PATCH_ID(+)
211
              ) aa,
212
              release_manager.package_versions pv, 
213
              release_manager.packages pkg, 
214
              release_manager.RELEASE_CONTENT rc, 
215
              release_manager.RELEASE_TAGS rt
216
              where aa.PV_ID = pv.PV_ID
217
              AND pv.PKG_ID = pkg.PKG_ID
218
              and RC.pv_id = aa.LINK_PV_ID
219
              AND rt.RTAG_ID = rc.RTAG_ID
220
        ) where RN = 1";
4625 dpurdie 221
 
222
    populateArrayFromSql('LocatePackages', \@Packages, $m_sqlstr, \@packageItems);
223
#    DebugDumpData("Packages", \@Packages);
224
}
225
 
226
#-------------------------------------------------------------------------------
227
# Function        : LocatePackagesByPvid 
228
#
229
# Description     : Locate one package, as specified by its PVID
230
#                   This mode is only used in testing  
231
#
232
# Inputs          : Global: $opt_pvid 
233
#
234
# Returns         : Populate the @Packages array
235
#
236
sub LocatePackagesByPvid
237
{
5586 dpurdie 238
    #   Extract: PV_ID LINK_PV_ID RTAG_ID NAME VERSION PKG_ID PROJ_ID RNINFO AGE 
4625 dpurdie 239
    my $m_sqlstr = "
5586 dpurdie 240
                SELECT pv.pv_id,
241
                       pv.pv_id, 
4625 dpurdie 242
                       rc.rtag_id, 
243
                       pkg.pkg_name, 
244
                       pv.pkg_version, 
245
                       pv.pkg_id, 
246
                       rt.proj_id, 
4706 dpurdie 247
                       pv.release_notes_info,
248
                       pv.build_type,
249
                       pv.BS_ID
4625 dpurdie 250
                FROM release_manager.package_versions pv, 
251
                     release_manager.release_content rc, 
252
                     release_manager.packages pkg, 
253
                     release_manager.release_tags rt
254
                WHERE pv.pv_id = rc.pv_id
255
                AND pkg.pkg_id = pv.pkg_id
256
                AND rc.rtag_id = rt.rtag_id
257
                AND pv.pv_id = $opt_pvid
258
                ";
259
 
260
    populateArrayFromSql('LocatePackagesByPvid', \@Packages, $m_sqlstr, \@packageItems);
261
    #DebugDumpData("Packages", \@Packages);
262
}
263
 
264
#-------------------------------------------------------------------------------
265
# Function        : GenerateReleaseNote  
266
#
267
# Description     : Generate One Release Note
268
#                   Invoke several JATS utilities to do the hard work
269
#
270
# Inputs          : $entry          - Hash of useful infomation
271
#
272
# Returns         : Nothing
273
#                   Will exit on error
274
#
275
sub GenerateReleaseNote
276
{
277
    my ($entry) = @_;
278
    my $outfile;
279
    my $rv;
280
    my @args;
281
 
282
    #DebugDumpData("Entry", $entry);
283
    Message("-------------------- $entry->{NAME}, $entry->{VERSION}") if $opt_status || $opt_verbose;
284
 
285
    my $pkgBase = catdir($GBE_DPKG, $entry->{NAME}, $entry->{VERSION});
286
    Verbose("Processing: $pkgBase");
287
 
288
    #
4706 dpurdie 289
    #   Handle special class of packages
290
    #       Manually Built
291
    #       No Build Standard
292
    #       Not in dpkg_archive
293
    #   Example: unit_test_br_kcm_ct_saftp
294
    #   This type of package appears to be a place holder
295
    #   Still needs some level of processing
4625 dpurdie 296
    #
4706 dpurdie 297
    if ($entry->{BUILD_TYPE}  eq 'M' && $entry->{BS_ID} == 3 && ! -d $pkgBase)
298
    {
299
        Verbose ("Placeholder package detected");
300
        #DebugDumpData("Entry", $entry);
301
        updatePlaceHolderRmNoteInfo($entry);
302
        $rv = 0;
303
    }
304
    else
305
    {
306
        #
307
        #
308
        unless (-d $pkgBase) {
309
            Warning("Package not in archive: $pkgBase");
310
            return;
311
        }
4625 dpurdie 312
 
4706 dpurdie 313
        #
314
        #   Make the target Package Version Writable and Ensure that the doc directory
315
        #   exists. This is done via a script that is invoked with SUDO, partially to
316
        #   interwork with the existing system  
317
        #
318
        runSudoCommand('make_writable', 'dpkg_archive', $entry->{NAME},$entry->{VERSION});
319
        runSudoCommand('make_docFolder', 'dpkg_archive', $entry->{NAME},$entry->{VERSION}, 'doc');
4625 dpurdie 320
 
4706 dpurdie 321
        #
322
        #   Get the basic data required for the Release Note
323
        #   jats jats_get_releasenote_data.pl -pvid=1002782
324
        #
325
        $outfile = catdir($tempdir, join('_',$entry->{NAME},$entry->{VERSION})) . '.xml';
326
        $rv = localTool('jats_get_releasenote_data', '-verbose', $opt_verbose, '-pvid', $entry->{PV_ID}, '-outfile', $outfile );
327
 
328
        #
329
        #   Generate the actual release note and update the Release Manager
330
        #   jats jats_gen_releasenote.pl -releasenote=mcrdemo_1.2.3157.cr.xml -UpdateRmFiles
331
        unless ($rv)
332
        {
333
            $rv = localTool('jats_gen_releasenote.pl', '-verbose', $opt_verbose, '-UpdateRmFiles', '-releasenote', $outfile);
334
        }
335
 
336
        #
337
        #   Release note complete - or failed
338
        #       Make the target PackageVersion ReadOnly
339
        #       Signal End of Package Processing - which will trigger blat
340
        #
341
        #   Do this even if we have a Release Note Failure
342
        #
343
        runSudoCommand('make_readonly', 'dpkg_archive', $entry->{NAME},$entry->{VERSION});
4625 dpurdie 344
    }
345
 
346
    #    make_release_changed 
347
    #       archive=archive-path 
4632 dpurdie 348
    #       pkg_name="package-name" 
349
    #       pkg_version="package-version" 
4625 dpurdie 350
    #       rtag_id=release-tag-id 
351
    #       pkg_id=package-id 
352
    #       pv_id=package-version-id 
353
    #       proj_id=project-id 
354
    #       mode_id=change-mode-id (1 pkg added, 2 pkg removed, 3 pkg released)
355
    #
4632 dpurdie 356
    #   Note: The ReleasedPackagereport tool parses the make_released_changed entries
357
    #         It requires quotes on the pkg_name and pkg_version for correct parsing
358
    #
4625 dpurdie 359
    push @args, 'archive=dpkg_archive';
360
    push @args, 'mode_id=3';
4632 dpurdie 361
    push @args, 'pkg_name="'    . $entry->{NAME} . '"';
362
    push @args, 'pkg_version="' . $entry->{VERSION} . '"';
4625 dpurdie 363
    push @args, 'rtag_id='     . $entry->{RTAG_ID};
364
    push @args, 'pkg_id='      . $entry->{PKG_ID};
365
    push @args, 'pv_id='       . $entry->{PV_ID};
366
    push @args, 'proj_id='     . $entry->{PROJ_ID};
367
 
368
    runSudoCommand('make_release_changed', @args);
369
 
370
    #
371
    #   Email interested users
372
    #
373
    notifyInterestedUsers($entry);
374
 
375
    Error ("Did not generate Release Note: $entry->{NAME}, $entry->{VERSION}") if ($rv);
376
}
377
 
378
#-------------------------------------------------------------------------------
4706 dpurdie 379
# Function        : updatePlaceHolderRmNoteInfo 
380
#
381
# Description     : Insert Release Note Info into the Release Manager Database
382
#                   This has the side effect that RM will see the Release Note
383
#                   as being fully generated.
384
#
385
#                   Used only by special PlaceHolder packages
386
#
387
# Inputs          : $entry          - Hash of useful infomation
388
#
389
# Returns         : 
390
#
391
sub updatePlaceHolderRmNoteInfo
392
{
393
    my ($entry) = @_;
394
 
395
    executeRmQuery (
396
        'updateRmNoteInfo', 
397
        'update release_manager.package_versions set release_notes_info=\'MSG:5\' where pv_id=' . $entry->{PV_ID}
398
        );
399
}
400
 
401
#-------------------------------------------------------------------------------
4625 dpurdie 402
# Function        : localTool 
403
#
404
# Description     : Run a jats tool from the same directory as this script 
405
#
406
# Inputs          : $name           - Name of the script
407
#                   ...             - Arguments for the command
408
#
409
# Returns         : 
410
#
411
sub localTool
412
{
413
    my $cmd = shift;
414
    $cmd .= '.pl' unless ( $cmd =~ m~\.pl$~i );
415
    $cmd = catdir($scriptDir, $cmd);
416
    Error ("Command not found: $cmd") unless -f $cmd;
417
 
418
    return System ( '--NoShell', $::GBE_PERL, $cmd, @_ );
419
}
420
 
421
 
422
#-------------------------------------------------------------------------------
423
# Function        : notifyInterestedUsers  
424
#
425
# Description     : A user can register interest in a package (name) being built in a 
426
#                   specific Project 
427
#                   Perhaps this should be done by the build tool, but at the moment 
428
#                   this release note generation process is really a part of the build
429
#
430
#                   NOTE: Similar code exists in the RM web server to handle manually
431
#                         released packages.
432
#                   
433
# Inputs          : $entry          - Hash of useful infomation
434
#
435
# Returns         : 
436
#
437
sub notifyInterestedUsers
438
{
439
    my ($entry) = @_;
440
    my @userList;
441
 
442
    #
443
    #   Determine interested users
444
    #
445
    my $m_sqlstr = "SELECT U.user_email, prj.proj_name, rt.rtag_name, pkg.pkg_name, pv.pkg_version ,pv.pv_id, rt.rtag_id
4706 dpurdie 446
        FROM RELEASE_MANAGER.PACKAGE_INTEREST PI, 
447
             RELEASE_MANAGER.PACKAGES PKG, 
448
             RELEASE_MANAGER.PACKAGE_VERSIONS PV, 
449
             RELEASE_MANAGER.USERS U,
450
             RELEASE_MANAGER.RELEASE_TAGS RT, 
451
             RELEASE_MANAGER.PROJECTS PRJ 
4625 dpurdie 452
        WHERE PKG.PKG_ID = PI.PKG_ID 
453
          AND RT.RTAG_ID = $entry->{RTAG_ID}
454
          AND PV.PV_ID = $entry->{PV_ID}
455
          AND PV.PKG_ID = PKG.PKG_ID 
456
          AND PRJ.PROJ_ID = RT.PROJ_ID 
457
          AND PRJ.PROJ_ID = PI.PROJ_ID 
458
          AND U.USER_ID = PI.USER_ID";
459
 
460
    my @items = qw( USER_EMAIL PROJ_NAME RTAG_NAME PKG_NAME PKG_VERSION PV_ID RTAG_ID );
461
 
462
    populateArrayFromSql('notifyInterestedUsers', \@userList, $m_sqlstr, \@items);
463
 
464
    #
465
    #   Do we have something to do
466
    #
467
    return unless (@userList);
468
    #DebugDumpData("userList", \@userList);
469
 
470
    #   Ensure we have basic emailing information
471
    #
472
    getRmConfig();
473
 
474
    #
475
    #   Send Email to all the required users
476
    #   Note: This emailer requires a sendmail utility
477
    #
478
    foreach my $entry ( @userList)
479
    {
480
        #$entry->{USER_EMAIL} = 'dpurdie@vixtechnology.com';
481
        #Debug0("Sending email to David Purdie indead of real user");
482
 
4698 dpurdie 483
        my $rnUrl = $GBE_RM_URL . "/fixed_issues.asp?pv_id=$entry->{PV_ID}&rtag_id=$entry->{RTAG_ID}";
4625 dpurdie 484
        my $subject = "Package Release Notification: $entry->{PKG_NAME} $entry->{PKG_VERSION}";
4698 dpurdie 485
        my $content = "Version <a href='$rnUrl'>$entry->{PKG_VERSION}</a> of Package $entry->{PKG_NAME} in Project $entry->{PROJ_NAME} on Release Branch $entry->{RTAG_NAME} has been released.";
486
           $content .= "<p>Package Link: $rnUrl";
4625 dpurdie 487
           $content .= "<p>You have received this email as a result of your interest in this package. If you do not wish to receive further emails then remove your package interest from the notifications area in Release Manager.";
488
 
489
 
490
        my $req = POST( 'mailto:' . $entry->{USER_EMAIL},
491
            From         => $rmConfig{'BUILD FAILURE MAIL SENDER'},
492
            CC           => 'buildadm@vixtechnology.com',
493
            Date         => scalar localtime,
494
            Subject      => $subject,
495
            Content_Type => qq(text/html),
496
            Content      => $content,
497
        );
498
 
499
        my $response = LWP::UserAgent->new->request($req);
500
        if ($response->code != 202)
501
        {
502
            Warning("Email Send Error: $response->code");
503
            #DebugDumpData("Response", \$response);
504
        }
505
    }
506
}
507
 
508
 
509
#-------------------------------------------------------------------------------
510
# Function        : getRmConfig 
511
#
512
# Description     : Get Basic config from Release Manager
513
#                   Only do it once
514
#
515
#                   Just need:
516
#                       'BUILD FAILURE MAIL SENDER'
517
#                       'MAIL SERVER'
518
#
519
# Inputs          : None
520
#
521
# Returns         : Populates a global hash
522
#
523
sub getRmConfig
524
{
525
    return if keys(%rmConfig) > 0;
526
    my $m_sqlstr = "SELECT * from BUILD_SERVICE_CONFIG";
527
 
528
    performSqlQueryCallback('getRmConfig', 
529
                            $m_sqlstr, 
530
                            sub { 
531
                                my ($pRow) = @_;
532
                                $rmConfig{ $pRow->[0] } = $pRow->[1];
533
                                }
534
                            );
535
#DebugDumpData("rmConfig", \%rmConfig);
536
}
537
 
538
 
539
#-------------------------------------------------------------------------------
540
# Function        : runSudoCommand 
541
#
542
# Description     : Run a Unix command as root via the sodo system
543
#                   Requires that target commands be available
544
#                   Requires sudo to be configured to allow this user to run them
545
#
546
# Notes           : The sudoers file on the archive server needs to be configured to allow:
547
#                       This user to run programs from /home/releasem/sbin without a password
548
#                       The users sudo credentials must not timeout (or be used)
549
#
550
# Inputs          : prog            - Command to run
551
#                   arguments       - Command arguments
552
#
553
# Returns         : Nothing 
554
#
555
sub runSudoCommand
556
{
557
    my ($prog, @arguments) = @_;
558
    my $cmd;
559
    my $rv;
560
 
561
    #
562
    #   Construct command
563
    #
564
    $cmd = catdir($sudoUtilsDir, $prog);
565
    $rv = System('--NoShell','sudo','-n', $cmd, @arguments);
566
    Warning("SudoCmd Result: $prog: $rv") if ($rv);
567
}
568
 
569
#-------------------------------------------------------------------------------
570
# Function        : performSqlQueryCallback 
571
#
572
# Description     : Perform a general Sql query and invoke a user function for
573
#                   each row of results
574
#
575
# Inputs          : $fname                  - Name of query for error reporting
576
#                   $m_sqlstr               - Query string
577
#                   $f_process              - Function called for each row in the result
578
#                                             Use closure to have callback modify other data
579
#
580
# Returns         : Number of rows found
581
#
582
sub performSqlQueryCallback
583
{
584
    my ($fname, $m_sqlstr, $f_process ) = @_;
585
    my $found = 0;
586
 
587
    #
588
    #   Connect to the database - once
589
    #
590
    connectRM(\$RM_DB, $opt_verbose) unless $RM_DB;
591
 
592
    $m_sqlstr =~ s~\s+~ ~g;
593
    Verbose3("SQL:", $m_sqlstr);
594
    my $sth = $RM_DB->prepare($m_sqlstr);
595
    if ( defined($sth) )
596
    {
597
        if ( $sth->execute( ) )
598
        {
599
            if ( $sth->rows )
600
            {
601
                while ( my @row = $sth->fetchrow_array )
602
                {
603
                    $found++;
604
                    &$f_process(\@row);
605
                }
606
            }
607
            $sth->finish();
608
        }
609
        else
610
        {
611
            Error("$fname:Execute failure: $m_sqlstr", $sth->errstr() );
612
        }
613
    }
614
    else
615
    {
616
        Error("$fname:Prepare failure" );
617
    }
618
 
619
    unless ( $found )
620
    {
621
        Verbose("$fname:No data found");
622
    }
623
    return $found;
624
}
625
 
626
#-------------------------------------------------------------------------------
627
# Function        : populateArrayFromSql 
628
#
629
# Description     : Issue an SQL query and push the results into an array of hashes
630
#                   where each row from the query is a hash and the entire result is an 
631
#                   array 
632
#
633
# Inputs          :     name                - For error reporting
634
#                       pArray              - Ref to the output array
635
#                       sql                 - Sql to process
5586 dpurdie 636
#                       pItems              - Array of items to extract
4625 dpurdie 637
#                                             Must match the SQL SELECT arguments
638
#                                             Item names starting with '-' do not end up in the
639
#                                             generated XML
640
# Returns         : 
641
#
642
sub populateArrayFromSql
643
{
644
    my ($fname, $pArray, $m_sqlstr, $pItems) = @_;
645
 
646
    performSqlQueryCallback($fname, 
647
                            $m_sqlstr, 
648
                            sub { 
649
                                my ($pRow) = @_;
650
                                my %entry;
651
                                push @{$pArray}, populateHash( \%entry, $pRow, $pItems);
652
                                }
653
                            );
654
#DebugDumpData("populateArrayFromSql", $pArray);
655
}
656
 
657
#-------------------------------------------------------------------------------
658
# Function        : populateHash 
659
#
660
# Description     : Put an array of data items into a hash
661
#
662
# Inputs          : pHash           - ref to output hash
663
#                   pRow            - Ref to the row data 
664
#                   pItems          - Ref to an hash array of entry names
665
#
666
# Returns         : pHash
667
#
668
sub populateHash
669
{
670
    my ($pHash, $pRow, $pItems) = @_;
671
 
672
    foreach my $item ( @{$pItems} ) {
673
        my $data = shift @{$pRow};
674
 
675
        if (defined $data)
676
        {
677
            $data =~ s~^\s+~~;
678
            $data =~ s~\s+$~~;
679
 
680
            #
681
            #   Store in hash
682
            #
683
            $pHash->{$item} = $data;
684
        }
685
    }
686
    return $pHash;
687
}
688
 
689
#-------------------------------------------------------------------------------
4706 dpurdie 690
# Function        : executeRmQuery 
691
#
692
# Description     : Execute a simple RM query. One that does not expect any return data
693
#
694
# Inputs          : $fname           - OprName, for error reporting
695
#                   $m_sqlstr        - SQL String
696
#
697
# Returns         : Will exit on error
698
#
699
sub executeRmQuery
700
{
701
    my ($fname, $m_sqlstr) = @_;
702
 
703
    #
704
    #   Connect to the Database - once
705
    #
706
    connectRM(\$RM_DB, 0) unless $RM_DB;
707
 
708
    Verbose2('ExecuteQuery:', $fname);
709
    #
710
    #   Create the full SQL statement
711
    #
712
    my $sth = $RM_DB->prepare($m_sqlstr);
713
    if ( defined($sth) )
714
    {
715
        if ( $sth->execute() )
716
        {
717
            $sth->finish();
718
        }
719
        else
720
        {
721
            Error("$fname: Execute failure: $m_sqlstr", $sth->errstr() );
722
        }
723
    }
724
    else
725
    {
726
        Error("$fname: Prepare failure");
727
    }
728
}
729
 
730
#-------------------------------------------------------------------------------
6766 dpurdie 731
# Function        : getFileTime  
732
#
733
# Description     : Get the timestamp from a file 
734
#
735
# Inputs          : Path to the file
736
#
737
# Returns         : Time since the file was created in seconds 
738
#
739
 
740
sub getFileTime
741
{
742
    my ($fname, $idx) = @_;
743
    my $stamp = (stat($fname))[8];
744
    if (defined $stamp) {
745
        $stamp = time() - $stamp;
746
    } else {
747
        $stamp = 0;
748
    }
749
    return $stamp;
750
}
751
 
752
#-------------------------------------------------------------------------------
753
# Function        : makeFile 
754
#
755
# Description     : Create a file
756
#
757
# Inputs          : Path to the file 
758
#
759
# Returns         : 
760
#
761
 
762
sub makeFile
763
{
764
    my ($name) = @_;
765
    my $fh;
766
    open( $fh, '>',$name);
767
    print $fh '';
768
    close $fh;
769
}
770
 
771
#-------------------------------------------------------------------------------
4625 dpurdie 772
#   Documentation
773
#
774
 
775
=pod
776
 
777
=for htmltoc    SYSUTIL::
778
 
779
=head1 NAME
780
 
781
process_release_notes - Create Release Notes for newly created packages
782
 
783
=head1 SYNOPSIS
784
 
785
 jats process_release_notes [options]
786
 
787
 Options:
788
    -help              - Brief help message
789
    -help -help        - Detailed help message
790
    -man               - Full documentation
791
    -verbose           - Display additional progress messages
792
    -pvid=nn           - PVID of package to process(test mode)
793
    -age=nn            - Examine packages created in last n days
794
    -keeptemp          - Keep the temp workspace
795
    -status            - Display status
796
 
797
=head1 OPTIONS
798
 
799
=over 8
800
 
801
=item B<-help>
802
 
803
Print a brief help message and exits.
804
 
805
=item B<-help -help>
806
 
807
Print a detailed help message with an explanation for each option.
808
 
809
=item B<-man>
810
 
811
Prints the manual page and exits.
812
 
813
=item B<-pvid=nn>
814
 
815
This option bypasses the normal mechanism of determining packages to be processed and 
816
will process just the specified package. This is normally only used to test the operation 
817
of the subsystem.
818
 
819
=item B<-age=nn>
820
 
821
This option control the period of time period used in determing which packages to process. 
822
 
823
The number is in days. The default value is 2 days.
824
 
825
=item B<-keeptemp>
826
 
827
If this option is specified, then the temporary directory created in the processing will be 
828
retained. The user is responsible for deleting the directory.
829
 
830
This option is normally only used in testing.
831
 
832
=item B<-status>
833
 
834
When set, this option will cause the program to display the package name and version of each
835
package being processed.
836
 
837
=back
838
 
839
=head1 DESCRIPTION
840
 
841
This utility program is apart of the Package Release process. It is an interim solution.
842
 
843
The script is designed to be run as a cron jon on the dpkg_archive server.
844
 
845
It will scan the Release Manager database for packages that have been release, but do 
846
not yet have release notes. For each package it will then generate a Release Note by: 
847
 
848
=over 4
849
 
850
=item *
851
 
852
Invoke jats_get_releasenote_data to:
853
 
854
Extract relevent information from
855
 
856
=over 4
857
 
858
=item *
859
 
860
The Release Manager database
861
 
862
=item *
863
 
864
the ClearQuest database (now conatined within the Release Manager database)
865
 
866
=item *
867
 
868
the Jira Issue server 
869
 
870
=back
871
 
872
and create and XML file.
873
 
874
=item *
875
 
876
Invoke jats_gen_releasenote to:
877
 
878
=over 4
879
 
880
=item *
881
 
882
Process the the XML file created above, and package list info found within the new package. 
883
 
884
If no package informationis found then the utility will create a package list, but this is 
885
much slower than having it created by the package builder.
886
 
887
=item *
888
 
889
Create an XML file containing all the package information
890
 
891
=item *
892
 
893
Create an HTML based Release Note, from the XML file. This file could also be used to create a Release note in another format if required. 
894
 
895
=item *
896
 
897
Transfer these two files into the package in dpkg_archive
898
 
899
=item *
900
 
901
Insert the packages file list into the Release Manager database.
902
 
903
=back
904
 
905
=item *
906
 
907
Make the package read-only. This will trigger any post-install processing of the 
908
package. This is only required for packages that form a part of the build system.
909
 
910
=item *
911
 
912
Flag that the package has been released. This may tigger the BLAT package file transfer process 
913
and the package will be transferred to remote sites.
914
 
915
=item *
916
 
917
Determine the users that have registered interest in being informed when the package is released. 
918
It will then email these users.
919
 
920
=back
921
 
922
=head1 EXAMPLE
923
 
924
=head2 process_release_notes
925
 
926
This will perform a single scan of the Release Manager database and generate Release Notes as required.
927
 
928
=cut
929