source: OFFICIAL/FCM_V1.3/lib/Fcm/Dest.pm

Last change on this file was 1, checked in by fcm, 15 years ago

creation de larborescence

File size: 25.4 KB
Line 
1#!/usr/bin/perl
2# ------------------------------------------------------------------------------
3# NAME
4#   Fcm::Dest
5#
6# DESCRIPTION
7#   This class contains methods to set up a destination location of an FCM
8#   extract/build.
9#
10# COPYRIGHT
11#   (C) Crown copyright Met Office. All rights reserved.
12#   For further details please refer to the file COPYRIGHT.txt
13#   which you should have received as part of this distribution.
14# ------------------------------------------------------------------------------
15
16package Fcm::Dest;
17@ISA = qw(Fcm::Base);
18
19# Standard pragma
20use warnings;
21use strict;
22
23# Standard modules
24use Carp;
25use Cwd;
26use File::Basename;
27use File::Find;
28use File::Path;
29use File::Spec;
30use Sys::Hostname;
31
32# In-house modules
33use Fcm::Base;
34use Fcm::CfgLine;
35use Fcm::Util;
36
37# Useful variables
38# ------------------------------------------------------------------------------
39# List of configuration files
40our @cfgfiles = (
41  'bldcfg',     # default location of the build configuration file
42  'extcfg',     # default location of the extract configuration file
43);
44
45# List of cache and configuration files, according to the dest type
46our @cfgfiles_type = (
47  'cache',     # default location of the cache file
48  'cfg',       # default location of the configuration file
49  'parsedcfg', # default location of the as-parsed configuration file
50);
51
52# List of lock files
53our @lockfiles = (
54  'bldlock',    # the build lock file
55  'extlock',    # the extract lock file
56);
57
58# List of misc files
59our @miscfiles_bld = (
60  'bldrunenvsh', # the build run environment shell script
61  'bldmakefile', # the build Makefile
62);
63
64# List of sub-directories created by extract
65our @subdirs_ext = (
66  'cfgdir',     # sub-directory for configuration files
67  'srcdir',     # sub-directory for source tree
68);
69
70# List of sub-directories that can be archived by "tar" at end of build
71our @subdirs_tar = (
72  'donedir',    # sub-directory for "done" files
73  'flagsdir',   # sub-directory for "flags" files
74  'incdir',     # sub-directory for include files
75  'ppsrcdir',   # sub-directory for pre-process source tree
76  'objdir',     # sub-directory for object files
77);
78
79# List of sub-directories created by build
80our @subdirs_bld = (
81  'bindir',     # sub-directory for executables
82  'etcdir',     # sub-directory for miscellaneous files
83  'libdir',     # sub-directory for object libraries
84  'tmpdir',     # sub-directory for temporary build files
85  @subdirs_tar, # -see above-
86);
87
88# List of sub-directories under rootdir
89our @subdirs = (
90  'cachedir',   # sub-directory for caches
91  @subdirs_ext, # -see above-
92  @subdirs_bld, # -see above-
93);
94
95# List of inherited search paths
96# "rootdir" + all @subdirs, with "XXXdir" replaced with "XXXpath"
97our @paths = ('rootpath');
98for (@subdirs) {
99  (my $name = $_) =~ s/dir$/path/;
100  push @paths, $name;
101}
102
103# List of normal properties
104my @scalar_properties = (
105  'dest0',      # the original destination (if current destination is a mirror)
106  'inherit',    # list of inherited Fcm::Dest objects
107  'logname',    # remote login name
108  'lockfile',   # lock file
109  'machine',    # remote machine
110  'mirror_cmd', # mirror command to use
111  'rootdir',    # destination root directory
112  'type',       # destination type, "bld" (default) or "ext"
113);
114
115# ------------------------------------------------------------------------------
116# SYNOPSIS
117#   $obj = Fcm::Dest->new (%args);
118#
119# DESCRIPTION
120#   This method constructs a new instance of the Fcm::Dest class. See above for
121#   allowed list of properties. (KEYS should be in uppercase.)
122# ------------------------------------------------------------------------------
123
124sub new {
125  my $this  = shift;
126  my %args  = @_;
127  my $class = ref $this || $this;
128
129  my $self = Fcm::Base->new (%args);
130
131  bless $self, $class;
132
133  for (@scalar_properties) {
134    $self->{$_} = exists $args{uc ($_)} ? $args{uc ($_)} : undef;
135  }
136
137  for (@subdirs, @paths, @lockfiles, @cfgfiles) {
138    $self->{$_} = undef;
139  }
140
141  return $self;
142}
143
144# ------------------------------------------------------------------------------
145# SYNOPSIS
146#   $self->DESTROY;
147#
148# DESCRIPTION
149#   This method is called automatically when the Fcm::Dest object is
150#   destroyed.
151# ------------------------------------------------------------------------------
152
153sub DESTROY {
154  my $self = shift;
155
156  # Remove the lockfile if it is set
157  unlink $self->lockfile if $self->lockfile and -w $self->lockfile;
158
159  return;
160}
161
162# ------------------------------------------------------------------------------
163# SYNOPSIS
164#   $value = $obj->X;
165#   $obj->X ($value);
166#
167# DESCRIPTION
168#   Details of these properties are explained in @scalar_properties.
169# ------------------------------------------------------------------------------
170
171for my $name (@scalar_properties) {
172  no strict 'refs';
173
174  *$name = sub {
175    my $self = shift;
176
177    # Set property to specified value
178    if (@_) {
179      $self->{$name} = $_[0];
180
181      if ($name eq 'rootdir') {
182        # If root is changed, reset locations derived from it
183        for (@cfgfiles, @lockfiles, @miscfiles_bld, @subdirs) {
184          $self->{$_} = undef;
185        }
186
187      } elsif ($name eq 'inherit') {
188        # If list of inherited destinations has changed, reset search paths
189        for (@paths) {
190          $self->{$_} = undef;
191        }
192      }
193    }
194
195    # Default value for property
196    if (not defined $self->{$name}) {
197      if ($name eq 'inherit') {
198        # Set to reference to empty array
199        $self->{$name} = [];
200
201      } elsif ($name eq 'logname') {
202        # Attempt to get logname from the current logname
203        $self->{$name} = $self->config->user_id;
204
205      } elsif ($name eq 'machine') {
206        # Use current hostname
207        $self->{$name} = &hostname();
208
209      } elsif ($name eq 'mirror_cmd') {
210        # Use default mirror command from config setting
211        $self->{$name} = $self->setting (qw/TOOL MIRROR/);
212
213      } elsif ($name eq 'type') {
214        # Default to build destination
215        $self->{$name} = 'bld';
216      }
217    }
218
219    return $self->{$name};
220  }
221}
222
223# ------------------------------------------------------------------------------
224# SYNOPSIS
225#   $value = $obj->X;
226#
227# DESCRIPTION
228#   This method returns X, where X is a location derived from rootdir, and can
229#   be one of:
230#     bindir, bldcfg, blddir, bldlock, bldrunenv, cache, cachedir, cfg, cfgdir,
231#     donedir, etcdir, extcfg, extlock, flagsdir, incdir, libdir, parsedcfg,
232#     ppsrcdir, objdir, or tmpdir.
233#
234#   Details of these properties are explained earlier.
235# ------------------------------------------------------------------------------
236
237for my $name (@cfgfiles, @cfgfiles_type, @lockfiles, @miscfiles_bld, @subdirs) {
238  no strict 'refs';
239
240  *$name = sub {
241    my $self = shift;
242
243    # If variable not set, derive it from rootdir
244    if ($self->rootdir and not defined $self->{$name}) {
245      if ($name eq 'cache') {
246        # Cache file under root/.cache
247        $self->{$name} =  File::Spec->catfile (
248          $self->cachedir, $self->setting ('CACHE'),
249        );
250
251      } elsif ($name eq 'cfg') {
252        # Configuration file of current type
253        my $method = $self->type . 'cfg';
254        $self->{$name} = $self->$method;
255
256      } elsif (grep {$name eq $_} @cfgfiles) {
257        # Configuration files under the root/cfg
258        (my $label = uc ($name)) =~ s/CFG//;
259        $self->{$name} = File::Spec->catfile (
260          $self->cfgdir, $self->setting ('CFG_NAME', $label),
261        );
262
263      } elsif (grep {$name eq $_} @lockfiles) {
264        # Lock file
265        $self->{$name} = File::Spec->catfile (
266          $self->rootdir, $self->setting ('LOCK', uc ($name)),
267        );
268
269      } elsif (grep {$name eq $_} @miscfiles_bld) {
270        # Misc file
271        $self->{$name} = File::Spec->catfile (
272          $self->rootdir, $self->setting ('BLD_MISC', uc ($name)),
273        );
274
275      } elsif ($name eq 'parsedcfg') {
276        # As-parsed configuration file of current type
277        $self->{$name} = File::Spec->catfile (
278          dirname ($self->cfg),
279          $self->setting (qw/CFG_NAME PARSED/) . basename ($self->cfg),
280        )
281
282      } elsif (grep {$name eq $_} @subdirs) {
283        # Sub-directories under the root
284        (my $label = uc ($name)) =~ s/DIR//;
285        $self->{$name} = File::Spec->catfile (
286          $self->rootdir,
287          $self->setting ('DIR', $label),
288          ($name eq 'cachedir' ? '.' . $self->type : ()),
289        );
290      }
291    }
292
293    return $self->{$name};
294  }
295}
296
297# ------------------------------------------------------------------------------
298# SYNOPSIS
299#   $value = $obj->X;
300#
301# DESCRIPTION
302#   This method returns X, an array containing the search path of a destination
303#   directory, which can be one of:
304#     binpath, bldpath, cachepath, cfgpath, donepath, etcpath, flagspath,
305#     incpath, libpath, ppsrcpath, objpath, rootpath, srcpath, or tmppath,
306#
307#   Details of these properties are explained earlier.
308# ------------------------------------------------------------------------------
309
310for my $name (@paths) {
311  no strict 'refs';
312
313  *$name = sub {
314    my $self = shift;
315
316    (my $dir = $name) =~ s/path/dir/;
317
318    if ($self->$dir and not defined $self->{$name}) {
319      my @path = ();
320
321      # Recursively inherit the search path
322      for my $d (@{ $self->inherit }) {
323        unshift @path, $d->$dir;
324      }
325
326      # Place the path of the current build in the front
327      unshift @path, $self->$dir;
328
329      $self->{$name} = \@path;
330    }
331
332    return $self->{$name};
333  }
334}
335
336# ------------------------------------------------------------------------------
337# SYNOPSIS
338#   $rc = $obj->archive ();
339#
340# DESCRIPTION
341#   This method creates TAR archives for selected sub-directories.
342# ------------------------------------------------------------------------------
343
344sub archive {
345  my $self = shift;
346
347  # Save current directory
348  my $cwd = cwd ();
349
350  my $tar      = $self->setting (qw/OUTFILE_EXT TAR/);
351  my $verbose  = $self->verbose;
352
353  for my $name (@subdirs_tar) {
354    my $dir = $self->$name;
355
356    # Ignore unless sub-directory exists
357    next unless -d $dir;
358
359    # Change to container directory
360    my $base = basename ($dir);
361    print 'cd ', dirname ($dir), "\n" if $verbose > 2;
362    chdir dirname ($dir);
363
364    # Run "tar" command
365    my $rc = &run_command (
366      [qw/tar -czf/, $base . $tar, $base],
367      PRINT => $verbose > 1, ERROR => 'warn',
368    );
369
370    # Remove sub-directory
371    &run_command ([qw/rm -rf/, $base], PRINT => $verbose > 1) if not $rc;
372  }
373
374  # Change back to "current" directory
375  print 'cd ', $cwd, "\n" if $verbose > 2;
376  chdir $cwd;
377
378  return 1;
379}
380
381# ------------------------------------------------------------------------------
382# SYNOPSIS
383#   $authority = $obj->authority();
384#
385# DESCRIPTION
386#   Returns LOGNAME@MACHINE for this destination if LOGNAME is defined and not
387#   the same as the user ID of the current process. Returns MACHINE if LOGNAME
388#   is the same as the user ID of the current process, but MACHINE is not the
389#   same as the current hostname. Returns an empty string if LOGNAME and
390#   MACHINE are not defined or are the same as in the current process.
391# ------------------------------------------------------------------------------
392
393sub authority {
394  my $self = shift;
395  my $return = '';
396
397  if ($self->logname ne $self->config->user_id) {
398    $return = $self->logname . '@' . $self->machine;
399
400  } elsif ($self->machine ne &hostname()) {
401    $return = $self->machine;
402  }
403
404  return $return;
405}
406
407# ------------------------------------------------------------------------------
408# SYNOPSIS
409#   $rc = $obj->clean ([ITEM => <list>,] [MODE => 'ALL|CONTENT|EMPTY',]);
410#
411# DESCRIPTION
412#   This method removes files/directories from the destination. If ITEM is set,
413#   it must be a reference to a list of method names for files/directories to
414#   be removed. Otherwise, the list is determined by the destination type. If
415#   MODE is ALL, all directories/files created by the extract/build are
416#   removed. If MODE is CONTENT, only contents within sub-directories are
417#   removed. If MODE is EMPTY (default), only empty sub-directories are
418#   removed.
419# ------------------------------------------------------------------------------
420
421sub clean {
422  my ($self, %args) = @_;
423
424  my $mode = exists $args{MODE} ? $args{MODE} : 'EMPTY';
425  my $rc   = 1;
426
427  my @files;
428  if (exists $args{ITEM} and $args{ITEM}) {
429    # Remove only selected directories
430    @files = @{ $args{ITEM} };
431
432  } else {
433    # Remove cachedir and read-write sub-directories for extract or build
434    @files = (
435      'cachedir',
436      ($self->type eq 'ext' ? @subdirs_ext : (@subdirs_bld, @miscfiles_bld)),
437    );
438  }
439
440  for my $name (@files) {
441    my $item     = $self->$name;
442    my $clean_ok = 1;
443
444    my @files;
445    if (-d $item and $mode ne 'ALL') {
446      # Read contents in directory
447      opendir DIR, $item;
448      @files = grep !/^\.\.?$/, readdir DIR;
449      closedir DIR;
450
451      # OK to remove if it is empty
452      $clean_ok = not @files;
453
454    } elsif (-f $item and $mode ne 'ALL') {
455      $clean_ok = 0;
456    }
457
458    # Remove only if it is OK to do so
459    next unless $clean_ok;
460
461    # If $item exists and writable by the user, remove it
462    if (-w $item) {
463      if (-d $item and $mode eq 'CONTENT') {
464        print 'Remove contents in : ', $item, "\n"
465          if $self->verbose > 1;
466
467        for my $file (@files) {
468          rmtree (File::Spec->catfile ($item, $file));
469        }
470
471      } else {
472        print 'Remove: ', $item, "\n" if $self->verbose > 1;
473        rmtree $item;
474      }
475    }
476
477    # If $item still exists, issue warning
478    if (-e $item and not $mode eq 'CONTENT') {
479      w_report 'ERROR: ', $item, ': cannot remove.';
480      $rc = 0;
481    }
482  }
483
484  return $rc;
485}
486
487# ------------------------------------------------------------------------------
488# SYNOPSIS
489#   $rc = $obj->create ([DIR => <dir-list>,]);
490#
491# DESCRIPTION
492#   This method creates the directories of a destination. If DIR is set, it
493#   must be a reference to a list of sub-directories to be created.  Otherwise,
494#   the sub-directory list is determined by the destination type. It returns
495#   true if the destination is created or if it exists and is writable.
496# ------------------------------------------------------------------------------
497
498sub create {
499  my ($self, %args) = @_;
500
501  my $rc = 1;
502
503  my @dirs;
504  if (exists $args{DIR} and $args{DIR}) {
505    # Create only selected sub-directories
506    @dirs = @{ $args{DIR} };
507
508  } else {
509    # Create rootdir, cachedir and read-write sub-directories for extract/build
510    @dirs = (
511      qw/rootdir cachedir/,
512      ($self->type eq 'ext' ? @subdirs_ext : @subdirs_bld),
513    );
514  }
515
516  for my $name (@dirs) {
517    my $dir = $self->$name;
518
519    # Create directory if it does not already exist
520    if (not -d $dir) {
521      print 'Make directory: ', $dir, "\n" if $self->verbose > 1;
522      mkpath $dir;
523    }
524
525    # Check whether directory exists and is writable
526    unless (-d $dir and -w $dir) {
527      w_report 'ERROR: ', $dir, ': cannot write to destination.';
528      $rc = 0;
529    }
530  }
531
532  return $rc;
533}
534
535# ------------------------------------------------------------------------------
536# SYNOPSIS
537#   $rc = $obj->create_bldrunenvsh ();
538#
539# DESCRIPTION
540#   This method creates the runtime environment script for the build.
541# ------------------------------------------------------------------------------
542
543sub create_bldrunenvsh {
544  my $self = shift;
545
546  # Path to executable files and directory for misc files
547  my @binpath = grep {-d} @{ $self->binpath };
548  my $etc_dir  = -d $self->etcdir ? $self->etcdir : undef;
549
550  # Create a runtime environment script if necessary
551  if (@binpath or $etc_dir) {
552    my $file = $self->bldrunenvsh;
553
554    open FILE, '>', $file or croak $file, ': cannot open (', $!, '), abort';
555    print FILE '#!', $self->setting(qw/TOOL SHELL/), "\n";
556    print FILE 'PATH=', join (':', (@binpath, '$PATH')), "\n" if @binpath;
557    print FILE 'FCM_ETCDIR=', $self->etcdir, "\n" if $etc_dir;
558    print FILE 'export PATH FCM_ETCDIR';
559    close FILE or croak $file, ': cannot close (', $!, '), abort';
560
561    # Create symbolic links fcm_env.ksh and bin/fcm_env.ksh for backward
562    # compatibility
563    my $old_runenv = 'fcm_env.ksh';
564    my @symlinks = (
565      File::Spec->catfile ($self->rootdir, $old_runenv),
566      (-d $self->bindir ? File::Spec->catfile ($self->bindir, $old_runenv) : ()),
567    );
568
569    for my $link (@symlinks) {
570      # Remove old link if necessary
571      if (-l $link) {
572        unlink $link if readlink ($link) ne $file;
573
574      } elsif (-e $link) {
575        unlink $link;
576      }
577
578      # Create the new link
579      symlink $file, $link if not -l $link;
580    }
581
582    # Information on the location/usage of the runtime environment script
583    if ($self->verbose > 1 and $file) {
584      print '# ', '-' x 78, "\n";
585      print '# To use this build, source the following shell script:', "\n";
586      print '. ', $file, "\n";
587      print '# ', '-' x 78, "\n";
588    }
589  }
590
591  return 1;
592}
593
594# ------------------------------------------------------------------------------
595# SYNOPSIS
596#   $rc = $obj->dearchive ();
597#
598# DESCRIPTION
599#   This method extracts from TAR archives for selected sub-directories.
600# ------------------------------------------------------------------------------
601
602sub dearchive {
603  my $self = shift;
604
605  my $tar     = $self->setting (qw/OUTFILE_EXT TAR/);
606  my $verbose = $self->verbose;
607
608  # Extract archives if necessary
609  for my $name (@subdirs_tar) {
610    my $tar_file = $self->$name . $tar;
611
612    # Check whether tar archive exists for the named sub-directory
613    next unless -f $tar_file;
614
615    # If so, extract the archive and remove it afterwards
616    &run_command ([qw/tar -xzf/, $tar_file], PRINT => $verbose > 1);
617    &run_command ([qw/rm -f/, $tar_file], PRINT => $verbose > 1);
618  }
619
620  return 1;
621}
622
623# ------------------------------------------------------------------------------
624# SYNOPSIS
625#   $name = $obj->get_pkgname_of_path ($path);
626#
627# DESCRIPTION
628#   This method returns the package name of $path if $path is in (a relative
629#   path of) $self->srcdir, or undef otherwise.
630# ------------------------------------------------------------------------------
631
632sub get_pkgname_of_path {
633  my ($self, $path) = @_;
634
635  my $relpath = File::Spec->abs2rel ($path, $self->srcdir);
636  my $name = $relpath ? [File::Spec->splitdir ($relpath)] : undef;
637
638  return $name;
639}
640
641# ------------------------------------------------------------------------------
642# SYNOPSIS
643#   %src = $obj->get_source_files ();
644#
645# DESCRIPTION
646#   This method returns a hash (keys = package names, values = file names)
647#   under $self->srcdir.
648# ------------------------------------------------------------------------------
649
650sub get_source_files {
651  my $self = shift;
652
653  my %src;
654  if ($self->srcdir and -d $self->srcdir) {
655    &find (sub {
656      return if /^\./;                    # ignore system/hidden file
657      return if -d $File::Find::name;     # ignore directory
658      return if not -r $File::Find::name; # ignore unreadable files
659
660      my $name = join (
661        '__', @{ $self->get_pkgname_of_path ($File::Find::name) },
662      );
663      $src{$name} = $File::Find::name;
664    }, $self->srcdir);
665  }
666
667  return \%src;
668}
669
670# ------------------------------------------------------------------------------
671# SYNOPSIS
672#   $rc = $obj->mirror (\@items);
673#
674# DESCRIPTION
675#   This method mirrors @items (list of method names for directories or files)
676#   from $dest0 (which must be an instance of Fcm::Dest for a local
677#   destination) to this destination.
678# ------------------------------------------------------------------------------
679
680sub mirror {
681  my ($self, $items) = @_;
682
683  my $rc = 1;
684
685  if ($self->authority or $self->dest0->rootdir ne $self->rootdir) {
686    # Diagnostic
687    if ($self->verbose) {
688      print 'Destination: ' . ($self->authority ? $self->authority . ':' : '') .
689            $self->rootdir . "\n";
690    }
691
692    # Check whether mirror command is implemented
693    my $method = '_mirror_with_' . $self->mirror_cmd;
694    if ($self->can ($method)) {
695      $rc = $self->$method ($self->dest0, $items);
696
697    } else {
698      # Unknown mirroring tool
699      w_report $self->mirror_cmd, ': unknown mirroring tool, abort.';
700      $rc = 0;
701    }
702  }
703
704  return $rc;
705}
706
707# ------------------------------------------------------------------------------
708# SYNOPSIS
709#   $rc = $self->_mirror_with_rdist ($dest0, \@items);
710#
711# DESCRIPTION
712#   This internal method implements $self->mirror with "rdist".
713# ------------------------------------------------------------------------------
714
715sub _mirror_with_rdist {
716  my ($self, $dest0, $items) = @_;
717
718  my $rhost = $self->authority ? $self->authority : &hostname();
719
720  # Print distfile content to temporary file
721  my @distfile = ();
722  for my $label (@$items) {
723    push @distfile, '( ' . $dest0->$label . ' ) -> ' . $rhost . "\n";
724    push @distfile, '  install ' . $self->$label . ';' . "\n";
725  }
726
727  # Set up mirroring command (use "rdist" at the moment)
728  my $command = 'rdist -R';
729  $command   .= ' -q' unless $self->verbose > 1;
730  $command   .= ' -f - 1>/dev/null';
731
732  # Diagnostic
733  my $croak = 'Cannot execute "' . $command . '"';
734  if ($self->verbose > 2) {
735    print timestamp_command ($command, 'Start');
736    print '  ', $_ for (@distfile);
737  }
738
739  # Execute the mirroring command
740  open COMMAND, '|-', $command or croak $croak, ' (', $!, '), abort';
741  for my $line (@distfile) {
742    print COMMAND $line;
743  }
744  close COMMAND or croak $croak, ' (', $?, '), abort';
745
746  # Diagnostic
747  print timestamp_command ($command, 'End  ') if $self->verbose > 2;
748
749  return 1;
750}
751
752# ------------------------------------------------------------------------------
753# SYNOPSIS
754#   $rc = $self->_mirror_with_rsync ($dest0, \@items);
755#
756# DESCRIPTION
757#   This internal method implements $self->mirror with "rsync".
758# ------------------------------------------------------------------------------
759
760sub _mirror_with_rsync {
761  my ($self, $dest0, $items) = @_;
762
763  my $rsh   = $self->setting (qw/TOOL REMOTE_SHELL/);
764  my $rhost = $self->authority ? $self->authority . ':' : '';
765
766  for my $label (@$items) {
767    # Create container directory, as rsync does not do it automatically
768    my $dir = dirname $self->$label;
769
770    if ($self->authority) {
771      # Create container directory using remote shell
772      &run_command (
773        [$rsh, $self->machine, '-n', '-l', $self->logname, qw/mkdir -p/, $dir],
774        TIME => $self->verbose > 2
775      );
776
777    } else {
778      mkpath $dir;
779    }
780
781    # Build the rsync command
782    my @command = (
783      qw/rsync -a --exclude='.*' --delete-excluded --timeout=900/,
784      '--rsh=' . $rsh,
785      ($self->verbose > 2 ? '-v' : ()),
786      $dest0->$label, $rhost . $dir,
787    );
788
789    # Execute command
790    &run_command (\@command, TIME => $self->verbose > 2);
791  }
792
793  return 1;
794}
795
796# ------------------------------------------------------------------------------
797# SYNOPSIS
798#   $rc = $obj->set_lock ();
799#
800# DESCRIPTION
801#   This method sets a lock in the current destination.
802# ------------------------------------------------------------------------------
803
804sub set_lock {
805  my $self = shift;
806
807  $self->lockfile ();
808
809  if ($self->type eq 'ext' and not $self->dest0) {
810    # Only set an extract lock for the local destination
811    $self->lockfile ($self->extlock);
812
813  } elsif ($self->type eq 'bld') {
814    # Set a build lock
815    $self->lockfile ($self->bldlock);
816  }
817
818  return &touch_file ($self->lockfile) if $self->lockfile;
819}
820
821# ------------------------------------------------------------------------------
822# SYNOPSIS
823#   @cfglines = $obj->to_cfglines ([$index]);
824#
825# DESCRIPTION
826#   This method returns a list of configuration lines for the current
827#   destination. If it is set, $index is the index number of the current
828#   destination.
829# ------------------------------------------------------------------------------
830
831sub to_cfglines {
832  my ($self, $index) = @_;
833
834  my @return = ();
835
836  my $dest_label = $self->cfglabel ($self->dest0 ? 'RDEST' : 'DEST');
837
838  push @return, Fcm::CfgLine->new (
839    label => $dest_label . ($index ? $Fcm::Config::DELIMITER . $index : ''),
840    value => $self->rootdir,
841  );
842
843  if ($self->dest0) {
844    my @names = ();
845    push @names, 'logname'
846      if $self->logname ne $self->config->user_id;
847    push @names, 'mirror_cmd'
848      if $self->mirror_cmd ne $self->setting (qw/TOOL MIRROR/);
849    push @names, 'machine'
850      if $self->machine ne &hostname ();
851
852    for my $name (@names) {
853      my $sub_label = $Fcm::Config::DELIMITER . uc ($name)
854                      . ($index ? $Fcm::Config::DELIMITER . $index : '');
855      push @return, Fcm::CfgLine->new (
856        label => $dest_label . $sub_label, value => $self->$name,
857      );
858    }
859  }
860
861  return @return;
862}
863
864# ------------------------------------------------------------------------------
865# SYNOPSIS
866#   $string = $obj->write_rules ();
867#
868# DESCRIPTION
869#   This method returns a string containing Makefile variable declarations for
870#   directories and search paths in this destination.
871# ------------------------------------------------------------------------------
872
873sub write_rules {
874  my $self   = shift;
875  my $return = '';
876
877  # FCM_*DIR*
878  for my $i (0 .. @{ $self->inherit }) {
879    for my $name (@paths) {
880      (my $label = $name) =~ s/path$/dir/;
881      my $dir = $name eq 'rootpath' ? $self->$name->[$i] : File::Spec->catfile (
882        '$(FCM_ROOTDIR' . ($i ? $i : '') . ')',
883        File::Spec->abs2rel ($self->$name->[$i], $self->rootpath->[$i]),
884      );
885
886      $return .= ($i ? '' : 'export ') . 'FCM_' . uc ($label) . ($i ? $i : '') .
887                 ' := ' . $dir . "\n";
888    }
889  }
890
891  # FCM_*PATH
892  for my $name (@paths) {
893    (my $label = $name) =~ s/path$/dir/;
894
895    $return .= 'export FCM_' . uc ($name) . ' := ';
896    for my $i (0 .. @{ $self->$name } - 1) {
897      $return .= ($i ? ':' : '') . '$(FCM_' . uc ($label) . ($i ? $i : '') . ')';
898    }
899    $return .= "\n";
900  }
901
902  $return .= "\n";
903
904  return $return;
905}
906
907# ------------------------------------------------------------------------------
908
9091;
910
911__END__
Note: See TracBrowser for help on using the repository browser.