You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ngcpcfg/helper/instances-info

196 lines
4.7 KiB

#!/usr/bin/perl -CSD
# Purpose: format yaml instances file for bash script
################################################################################
use strict;
use warnings;
use YAML::XS;
use Getopt::Long qw(:config posix_default bundling_values no_ignorecase);
use Time::Piece;
use Data::Dumper;
use File::Spec;
use Storable qw(dclone);
my $DEBUG = $ENV{DEBUG} || 0;
my $HNAME = $ENV{HNAME} // '';
my $TIME_FORMAT = $ENV{TIME_FORMAT} // '%F %T';
$TIME_FORMAT =~ s/^\+//;
my $NETWORK_CONFIG = $ENV{NETWORK_CONFIG};
my $TEMPLATE_INSTANCES = $ENV{TEMPLATE_INSTANCES};
sub usage {
print <<HELP;
Usage: $0 [<option>...] <input>...
Options:
-h, --help This help message.
HELP
}
my %options = ( help => sub { usage(); exit 0; }, );
error("NETWORK_CONFIG is not defined") unless $NETWORK_CONFIG;
GetOptions( \%options, 'help|?', );
my $yaml = YAML::XS::LoadFile($NETWORK_CONFIG);
my $templ = YAML::XS::LoadFile($TEMPLATE_INSTANCES);
sub output_prefix {
my $t = Time::Piece->new;
my $timestamp = $t->strftime($TIME_FORMAT);
return "$timestamp $HNAME";
}
sub error {
my $prefix = output_prefix();
die "$prefix: Error: @_\n";
}
sub debug {
return unless $DEBUG;
my $prefix = output_prefix();
warn "$prefix: DEBUG @_\n";
}
my $instances = {};
my $dirs = {};
sub prefix_root {
my $path = shift;
return $path =~ s/^([^\/].*)/\/$1/r;
}
sub split_path {
my $input = shift;
my $val = ();
foreach(split /\//, $input){
error("relative paths are not supported, ${input}") if ($_ =~ '^\.\.?$');
if( defined $_ && !($_ =~ /^$/ )) {
push @{$val}, $_;
}
}
return $val;
}
sub show_match {
my $path;
my ($bpath, $spath, $suffix) = @_;
if(defined $spath) {
$path = $spath;
} else {
$path = $bpath;
}
foreach my $info (sort { $a->{name} cmp $b->{name} } @{$dirs->{$path}}) {
my $dest;
if(defined $spath && defined $suffix) {
$dest = $info->{dest}."/${suffix}";
} else {
$dest = $info->{dest};
}
print "$bpath:$dest:".$info->{name}."\n";
}
}
sub prepare_info {
return 0 unless defined $yaml->{instances};
foreach my $instance (sort { $a->{name} cmp $b->{name} } @{$yaml->{instances}}) {
$instances->{ $instance->{label} } //= ();
push @{ $instances->{ $instance->{label} } }, $instance->{name};
}
foreach my $def (sort { $a->{orig} cmp $b->{orig} } @{$templ->{sources}}) {
my $inst = $instances->{ $def->{label} };
next unless $inst;
my $orig = prefix_root $def->{orig};
$dirs->{$orig} = ();
foreach ( sort @{$inst} ) {
my $dest = $def->{dest} =~ s/^(.*)\$\{INSTANCE_NAME\}(.*)$/$1$_$2/rg;
push @{ $dirs->{$orig} }, { name => $_, dest => prefix_root $dest};
}
}
#debug("info:".Dumper({instances => $instances, dirs => $dirs}));
return 1;
}
sub match_source {
my ($build_path, $matched) = @_;
my $abs_path = File::Spec->rel2abs($build_path);
my $sbuild = split_path $abs_path;
my $size_build = $#{$sbuild};
my $search = keys %{$dirs};
debug("search ${build_path}");
foreach my $index (0 .. $size_build) {
my $b_part = @{$sbuild}[$index];
debug("index:${index} b_part:${b_part} b:".join '/', @{$sbuild}[0..$index]);
foreach my $source_path (sort keys %{$dirs}) {
next if defined $matched->{$source_path};
my $sorig = split_path $source_path;
my $size_orig = $#{$sorig};
my $i_part = defined(@{$sorig}[$index]) ? @{$sorig}[$index] : '';
my $equal = defined($i_part) ? $b_part eq $i_part : 0;
if (not $equal) {
$search--;
$matched->{$source_path} = 0;
debug("!! fail to match ${search} ${source_path}");
} elsif ($index eq $size_build) {
$search--;
$matched->{$source_path} = {build => $source_path, suffix=> undef};
debug(" match ${search} ${source_path}");
} elsif ($index eq $size_orig) {
$search--;
my $temp = join '/', @{$sbuild}[$index+1..$size_build];
$matched->{$source_path} = {
build => "${source_path}/$temp",
suffix => $temp,
};
debug(" match ${search} ${source_path}");
} else {
debug(" index:$index size_build:${size_build} size_orig:${size_orig} ${source_path}");
}
}
debug("***");
# nothing else to match
last unless $search;
}
# clean the non-matches for next round
foreach (sort keys %{$matched}) {
if ($matched->{$_}) {
show_match $matched->{$_}->{build}, $_, $matched->{$_}->{suffix};
} else {
delete($matched->{$_});
}
}
}
exit unless prepare_info;
if (@ARGV == 0) {
foreach (sort keys %{$dirs}) {
show_match $_;
}
} else {
my $matched;
foreach my $build (sort @ARGV) {
match_source $build, $matched;
}
}
exit;