Last active
March 7, 2018 07:56
-
-
Save byrnedo/7ac5e461ba0866299fdd94899bebdbd9 to your computer and use it in GitHub Desktop.
Stand in to merge docker compose file merging (docker stack deploy doesn't do the magic yet), does the 'extends' replacement and the env var replacement.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
# | |
#==================================================== | |
# | |
# Stand in for docker-compose 'extends' and env replacement | |
# ( currently not implemented for `docker stack deploy -f` ) | |
# | |
#==================================================== | |
use strict; | |
use warnings; | |
use YAML::Syck qw(LoadFile Dump); | |
use File::Spec; | |
use File::Basename; | |
use Hash::Merge qw(merge); | |
use Data::Dumper; | |
use Cwd qw(abs_path); | |
$YAML::Syck::SingleQuote = 1; | |
Hash::Merge::specify_behavior( | |
{ | |
'SCALAR' => { | |
'SCALAR' => sub { $_[0] }, | |
'ARRAY' => sub { $_[0] }, | |
'HASH' => sub { $_[0] }, | |
}, | |
'ARRAY' => { | |
'SCALAR' => sub { [ @{ $_[0] }, $_[1] ] }, | |
'ARRAY' => sub { [ @{ $_[1] }, @{ $_[0] } ] }, | |
'HASH' => sub { [ @{ $_[0] }, values %{ $_[1] } ] }, | |
}, | |
'HASH' => { | |
'SCALAR' => sub { $_[0] }, | |
'ARRAY' => sub { $_[0] }, | |
'HASH' => sub { Hash::Merge::_merge_hashes( $_[0], $_[1] ) }, | |
}, | |
}, | |
'COMPOSE' | |
); | |
Hash::Merge::set_behavior('COMPOSE'); | |
my @confFileList = map{ [$_, LoadFile($_)] }@ARGV; | |
sub parseExtends{ | |
my $service = $_[0]; | |
my $serviceMap = $_[1]; | |
my $dir = $_[2]; | |
my $extends = $service->{extends}; | |
if ( exists($extends->{service})) | |
{ | |
my $serviceToMerge = $extends->{service}; | |
my $extendedServiceDef; | |
if (exists($extends->{'file'})) { | |
$extendedServiceDef = getExtendedService($extends->{file}, $extends->{service}, $dir); | |
} else { | |
$extendedServiceDef = $serviceMap->{$extends->{service}}; | |
} | |
delete $service->{extends}; | |
my $newHash = merge( $service, $extendedServiceDef); | |
$service = $newHash; | |
} | |
return $service; | |
} | |
#==================================================== | |
# | |
# Get the hash map for the service def in anotherfile | |
# | |
# TODO - recursive call if this extends | |
#==================================================== | |
sub getExtendedService{ | |
my $file = $_[0]; | |
my $serviceToMerge = $_[1]; | |
my $basePath = $_[2]; | |
my $resolvedFile = $file;#File::Spec->catfile($basePath, $file); | |
my $loaded = LoadFile($resolvedFile); | |
my $serviceMap = $loaded->{services}; | |
if (exists $serviceMap->{$serviceToMerge}->{extends}) { | |
$serviceMap->{$serviceToMerge} = parseExtends($serviceMap->{$serviceToMerge}, $serviceMap, dirname($resolvedFile)); | |
} | |
return formatPathArgs($serviceMap->{$serviceToMerge}, dirname($file)); | |
} | |
sub stripDotDot { | |
my @arr; | |
my $c = 0; | |
for (File::Spec->splitdir($_[0])) | |
{ | |
if ($_ ne ".." && $c ne 0) { | |
push @arr, $_ | |
} | |
else { | |
pop @arr | |
} | |
$c ++; | |
} | |
return File::Spec->catfile(@arr); | |
} | |
sub formatPathArgs { | |
my $service = $_[0]; | |
return $service; | |
#my $dir =$_[1]; | |
##======================== | |
## Loop through and replace list of | |
## vars that are dir paths on host | |
## ======================= | |
#for my $varName ('env_file') { | |
#if (exists $service->{$varName} ) { | |
#if(ref($service->{$varName}) eq 'ARRAY') { | |
#my @envFileList = $service->{$varName}; | |
#for my $i (0 .. $#{ $service->{$varName} }){ | |
#my $f = $service->{$varName}->[$i]; | |
#my $p = $dir . '/' . $f; | |
#$service->{$varName}->[$i] = $p; | |
#} | |
#} else { | |
#my $p = $dir . '/' . $service->{$varName}; | |
#$service->{$varName} = $p; | |
#} | |
#} | |
#} | |
#return $service; | |
} | |
sub replaceEnvs { | |
my $data = $_[0]; | |
#TODO add in fallback parsing ${SOME_ENV:-fallback_value} | |
$data =~ s{(\$)?\$+(\w+)}{(defined $1) ? "$1$2" : (exists $ENV{$2}) ? $ENV{$2} : q//}ge; | |
$data =~ s{(\$)?\$+\{(\w+)\}}{(defined $1) ? "$1$2" : (exists $ENV{$2}) ? $ENV{$2} : q//}ge; | |
return $data; | |
} | |
for my $fileHashPair (@confFileList) { | |
my $fileName = @$fileHashPair[0]; | |
my($vol,$dir,$file) = File::Spec->splitpath($fileName); | |
my $confMapRef = @$fileHashPair[1]; | |
my $services = $confMapRef->{services}; | |
for my $k (keys %$services) | |
{ | |
my $service =$services->{$k}; | |
if (exists $service->{extends}) { | |
$confMapRef->{services}->{$k} = parseExtends($service, $confMapRef->{services}, $dir); | |
} | |
$confMapRef->{services}->{$k} = formatPathArgs($confMapRef->{services}->{$k}, dirname($fileName)); | |
} | |
} | |
my $totalConfMapRef = merge(reverse map{ @$_[1] }@confFileList); | |
my $newYaml = Dump($totalConfMapRef); | |
print "version: '3.4'\n"; | |
my $c = 0; | |
for (split /^/, $newYaml) { | |
if ($_ !~ /^(")?version(")?:.*/ && $c != 0) { | |
#$_ = replaceEnvs($_); | |
print $_; | |
} | |
$c ++; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment