MT#55289 Add set-value helper

Move perl code which actually modifies yml file to separate helper as
there is no sense to recreate it every call of 'ngcpcfg set'.

Change-Id: I08b10186b1aa127d4a2b81ef36b234dfdd46fc8e
mr11.1
Mykola Malkov 4 years ago
parent 14a6de3c8e
commit a2a91ee09b

@ -6,6 +6,7 @@ BASH_SCRIPTS = \
sbin/ngcpcfg
PERL_SCRIPTS = \
lib/NGCP/Template.pm \
helper/set-value \
helper/sort-yml \
helper/sync-db \
helper/tt2-process \

@ -8,6 +8,7 @@ helper/fileformat_version usr/share/ngcp-ngcpcfg/helper/
helper/instance-info usr/share/ngcp-ngcpcfg/helper/
helper/instances-info usr/share/ngcp-ngcpcfg/helper/
helper/restore-permissions usr/share/ngcp-ngcpcfg/helper/
helper/set-value usr/share/ngcp-ngcpcfg/helper/
helper/sort-yml usr/share/ngcp-ngcpcfg/helper/
helper/sync-db usr/share/ngcp-ngcpcfg/helper/
helper/tt2-process usr/share/ngcp-ngcpcfg/helper/

@ -0,0 +1,87 @@
#!/usr/bin/perl -wCSD
use strict;
use warnings;
use Safe;
use YAML::XS;
use Scalar::Util qw(looks_like_number);
my ($file, $option, $value) = @ARGV;
unless (defined($file)) {
print {*STDERR} ("1st parameter 'file' is not defined\n");
exit (1);
}
unless (defined($option)) {
print {*STDERR} ("2nd parameter 'option' is not defined\n");
exit (1);
}
unless (defined($value)) {
print {*STDERR} ("3rd parameter 'value' is not defined\n");
exit (1);
}
my $yaml = YAML::XS::LoadFile($file);
my $valref = \$yaml;
if ($value =~ /^['"]+.+['"]+$/) {
log_debug ('$value is already quoted.');
}
elsif (looks_like_number($value)) {
log_debug ('Not quoting $value for integers.');
}
elsif ($value =~ /^\[.+\]$/) {
log_debug ('Not quoting $value for arrays.');
}
elsif ($value =~ /^\{.+\}$/) {
log_debug ('Not quoting $value for hashes.');
}
else {
$value = "\"$value\"";
}
my $compartment = Safe->new();
$value = $compartment->reval($value);
for my $component (split(/\./, $option)) {
if (ref($valref) eq 'SCALAR' && defined(${$valref})) {
print {*STDERR} ("Key resolved to a SCALAR at '$component'; cannot continue.\n");
exit (1);
}
elsif (looks_like_number($component) && (! defined(${$valref}) || ref(${$valref}) eq 'ARRAY')) {
$valref = \${$valref}->[$component];
}
elsif ($component eq 'APPEND' && ref($$valref) eq 'ARRAY') {
$valref = \${$valref}->[$#{$$valref}+1];
}
elsif (! defined(${$valref}) || ref(${$valref}) eq 'HASH') {
$valref = \${$valref}->{$component};
}
else {
print {*STDERR} ("Key resolved to a " . ref(${$valref}) . " reference; refusing to overwrite.\n");
exit (1);
}
}
if (! defined(${$valref}) || ref($valref) eq 'SCALAR') {
${$valref} = $value;
}
elsif (ref(${$valref}) eq 'ARRAY' && ref($value) eq 'ARRAY') {
${$valref} = $value;
}
elsif (ref(${$valref}) eq 'HASH' && ref($value) eq 'HASH') {
${$valref} = $value;
}
else {
print {*STDERR} ("Key resolved to a " . ref(${$valref}) . " reference; refusing to overwrite.\n");
exit (1);
}
YAML::XS::DumpFile($file, $yaml);
sub log_debug {
my $message = shift;
if (defined($ENV{DEBUG})) {
print "$message\n";
}
}

@ -84,68 +84,8 @@ log_debug "Parsed value: ${value}"
[ -z "${value}" ] && ( log_error "missing value to set. Exiting." ; exit 1)
log_debug "Saving option '${option}' value '${value}' into '${file}'"
if [[ ${value} =~ ^\'.*\'$ ]] ; then
log_debug "\$value is already quoted."
elif [[ ${value} =~ ^[0-9]*$ ]] ; then
log_debug "Not quoting \$value for integers."
elif [[ ${value} =~ ^\[.*\]$ ]] ; then
log_debug "Not quoting \$value for arrays."
elif [[ ${value} =~ ^\{.*\}$ ]] ; then
log_debug "Not quoting \$value for hashes."
else
log_debug "Quoting \$value to prevent further Perl errors."
value="\"${value}\""
fi
tmp=$(mktemp -t ngcpcfg-set.XXXXXXXXXX)
log_debug "Temporary perl file: ${tmp}"
cat > "${tmp}" << EOF
use strict;
use warnings;
use YAML::XS;
my \$file="${file}";
my \$yaml = YAML::XS::LoadFile("\$file");
my \$valref = \\\$yaml;
for my \$component (split(/\\./, "${option}")) {
if (ref(\$valref) eq 'SCALAR' && defined(\$\$valref)) {
print STDERR ("Key resolved to a SCALAR at '\$component'; cannot continue.\n");
exit(1);
}
elsif (\$component =~ /^\\d+\$/ && (!defined(\$\$valref) || ref(\$\$valref) eq 'ARRAY')) {
\$valref = \\\$\$valref->[\$component];
}
elsif (\$component eq 'APPEND' && ref(\$\$valref) eq 'ARRAY') {
\$valref = \\\$\$valref->[\$#{\$\$valref}+1];
}
elsif (!defined(\$\$valref) || ref(\$\$valref) eq 'HASH') {
\$valref = \\\$\$valref->{\$component};
}
else {
print STDERR ("Key resolved to a " . ref(\$\$valref) . " reference; refusing to overwrite.\n");
exit(1);
}
}
if (!defined(\$\$valref) || ref(\$valref) eq 'SCALAR') {
\$\$valref = ${value};
}
elsif (ref(\$\$valref) eq 'ARRAY' && ref(${value}) eq 'ARRAY') {
\$\$valref = ${value};
}
elsif (ref(\$\$valref) eq 'HASH' && ref(${value}) eq 'HASH') {
\$\$valref = ${value};
}
else {
print STDERR ("Key resolved to a " . ref(\$\$valref) . " reference; refusing to overwrite.\n");
exit(1);
}
YAML::XS::DumpFile(\$file, \$yaml);
EOF
log_debug "perl -wCSD \"${tmp}\" || RC=$?"
perl -wCSD "${tmp}" || RC=$?
log_debug "${HELPER}/set-value '${file}' '${option}' '${value}' || RC=\$?"
"${HELPER}/set-value" "${file}" "${option}" "${value}" || RC=$?
if [ "${CREATEFILE}" = "yes" ]; then
chmod "${MODE}" "${file}"
@ -158,12 +98,6 @@ if [ "${RC}" = "0" ] && "${b_show_diff:-false}"; then
"${SCRIPTS}"/diff || true
fi
if [ -n "${DEBUG:-}" ] ; then
log_debug "Not removing temporary file ${tmp}"
else
rm -f "${tmp}"
fi
exit ${RC}
## END OF FILE #################################################################

@ -601,6 +601,28 @@ foo:
assert out.returncode == 1
@pytest.mark.tt_33030
def test_set_action_check_keyword(ngcpcfgcli, tmpdir):
tmpfile = tmpdir.join("tmpfile.txt")
tmpfile.write(
"""---
foo:
bar: no
"""
)
out = ngcpcfgcli("set", str(tmpfile), "foo.bar=yes")
assert (
tmpfile.read()
== """---
foo:
bar: yes
"""
)
assert "" in out.stdout
assert "" in out.stderr
assert out.returncode == 0
###############################################################
# ngcpcfg del
###############################################################

Loading…
Cancel
Save