* Added a lot more testing.

* Created Get->uuid to generate random UUIDs via 'uuidgen'.
* Created Storage->read_mode that returns the standard 4-digit mode of a directory or file.
* Created System->stop_daemon to stop daemons.
* Altered Template->get to take fully defined path names.
* Altered Template->skin to use the 'set' parameter (as documented) instead of 'skin'. Also made it so that a skin could be set even if the skin directory doesn't exist via the new 'fatal' parameter.

Signed-off-by: Digimer <digimer@alteeve.ca>
main
Digimer 8 years ago
parent 367eb1a12f
commit 6b5185fe61
  1. 1
      AN/Tools.pm
  2. 327
      AN/Tools.t
  3. 16
      AN/Tools/Get.pm
  4. 103
      AN/Tools/Storage.pm
  5. 84
      AN/Tools/System.pm
  6. 50
      AN/Tools/Template.pm
  7. 13
      AN/Tools/Validate.pm
  8. 5
      AN/an-tools.xml

@ -600,6 +600,7 @@ sub _set_paths
'postgresql-setup' => "/usr/bin/postgresql-setup", 'postgresql-setup' => "/usr/bin/postgresql-setup",
su => "/usr/bin/su", su => "/usr/bin/su",
systemctl => "/usr/bin/systemctl", systemctl => "/usr/bin/systemctl",
uuidgen => "/usr/bin/uuidgen",
}, },
secure => { secure => {
postgres_pgpass => "/var/lib/pgsql/.pgpass", postgres_pgpass => "/var/lib/pgsql/.pgpass",

@ -228,71 +228,306 @@ $an->data->{switches}{v} = "#!set!#";
$an->Log->_adjust_log_level; $an->Log->_adjust_log_level;
is($an->Log->level, "1", "Verifying the log level was set back to '1' with Log->_adjust_log_leve() with 'v' switch set."); is($an->Log->level, "1", "Verifying the log level was set back to '1' with Log->_adjust_log_leve() with 'v' switch set.");
die;
### AN::Tools::Storage tests - These happen a little out of order. ### AN::Tools::Storage tests - These happen a little out of order.
# We need to pick a user name and group name to use for these tests. So we'll start by reading in passwd.
my $passwd = $an->Storage->read_file({file => "/etc/passwd"});
my $group = $an->Storage->read_file({file => "/etc/group"});
my $read_ok = 0;
my $use_user = "";
my $use_group = "";
foreach my $line (split/\n/, $passwd)
{
if ($line =~ /^root:/)
{
$read_ok = 1;
}
elsif ($line =~ /^(\w+):x:\d/)
{
$use_user = $1;
last;
}
}
foreach my $line (split/\n/, $group)
{
if ($line =~ /^root:/)
{
# skip
}
elsif ($line =~ /^(\w+):x:\d/)
{
$use_group = $1;
last;
}
}
# print "[ Debug ] - Using the user: [$use_user] and the group: [$use_group] for testing.\n";
is($read_ok, "1", "Verified that 'Storage->read_file' could read a file.");
# Write a file /tmp/foo # Write a file /tmp/foo
# my $body = "This is a test file created as part of the AN::Tools test suite.\nYou can safely delete it if you wish.\n";
my $test_file = "/tmp/an-tools.test";
die; if (-e $test_file)
{
### AN::Tools::System tests # remove the old test file.
# unlink $test_file or die "The test file: [$test_file] exists (from a previous run?) and can't be removed. The error was: $!\n";
}
die; $an->Storage->write_file({body => $body, file => $test_file, group => $use_group, user => $use_user, mode => "0666"});
my $write_ok = 0;
### AN::Tools::Template tests if (-e $test_file)
# {
$write_ok = 1;
die; }
is($write_ok, "1", "Verifying that 'Storage->write_file' could write a file (tested writing to: [$test_file]).");
### AN::Tools::Validate tests my $mode = $an->Storage->read_mode({target => $test_file});
# my ($uid, $gid) = (stat($test_file))[4,5];
my $file_user_name = getpwuid($uid);
die; my $file_group_name = getgrgid($gid);
#print "[ Debug ] - test_file: [$test_file], mode: [$mode], owning user: [$file_user_name ($uid)], owning group: [$file_group_name ($gid)]\n";
### AN::Tools::Words tests is($mode, "0666", "Verifying that 'Storage->write_file' set the mode correctly when writing a file.");
# is($file_user_name, $use_user, "Verifying that 'Storage->write_file' set the user name properly when the file was written.");
is($file_group_name, $use_group, "Verifying that 'Storage->write_file' set the group name properly when the file was written.");
die; # change_mode
$an->Storage->change_mode({target => $test_file, mode => "4755"});
$mode = $an->Storage->read_mode({target => $test_file});
is($mode, "4755", "Verifying that 'Storage->change_mode' was able to change the mode of the test file (including setting the setuid and setgid sticky bits).");
### AN::Tools::Storage methods $an->Storage->change_mode({target => $test_file, mode => "644"});
# Search directory tests $mode = $an->Storage->read_mode({target => $test_file});
is($mode, "0644", "Verifying that 'Storage->change_mode' was able to change the mode of the test file using three digits instead of four.");
# change_owner
$an->Storage->change_owner({target => $test_file, user => 0});
$file_user_name = "";
$file_group_name = "";
($uid, $gid) = (stat($test_file))[4,5];
$file_user_name = getpwuid($uid);
$file_group_name = getgrgid($gid);
is($file_user_name, "root", "Verifying that 'Storage->change_user', when passed only a user ID, changed the user.");
is($file_group_name, $use_group, "Verifying that 'Storage->change_user', when passed only a user ID, did not change the group.");
$an->Storage->change_owner({target => $test_file, user => $use_user});
$file_user_name = "";
$file_group_name = "";
($uid, $gid) = (stat($test_file))[4,5];
$file_user_name = getpwuid($uid);
$file_group_name = getgrgid($gid);
is($file_user_name, $use_user, "Verifying that 'Storage->change_user', when passed only a user name, changed the user.");
is($file_group_name, $use_group, "Verifying that 'Storage->change_user', when passed only a user ID, did not change the group.");
$an->Storage->change_owner({target => $test_file, group => 0});
$file_user_name = "";
$file_group_name = "";
($uid, $gid) = (stat($test_file))[4,5];
$file_user_name = getpwuid($uid);
$file_group_name = getgrgid($gid);
is($file_user_name, $use_user, "Verifying that 'Storage->change_user', when passed only a group ID, did not change the user.");
is($file_group_name, "root", "Verifying that 'Storage->change_user', when passed only a group ID, changed the group.");
$an->Storage->change_owner({target => $test_file, group => $use_group});
$file_user_name = "";
$file_group_name = "";
($uid, $gid) = (stat($test_file))[4,5];
$file_user_name = getpwuid($uid);
$file_group_name = getgrgid($gid);
is($file_user_name, $use_user, "Verifying that 'Storage->change_user', when passed only a group name, did not change the user.");
is($file_group_name, $use_group, "Verifying that 'Storage->change_user', when passed only a group name, changed the group.");
$an->Storage->change_owner({target => $test_file, user => "root", group => "root"});
$file_user_name = "";
$file_group_name = "";
($uid, $gid) = (stat($test_file))[4,5];
$file_user_name = getpwuid($uid);
$file_group_name = getgrgid($gid);
is($file_user_name, "root", "Verifying that 'Storage->change_user', when passed both a user and group name, changed the user.");
is($file_group_name, "root", "Verifying that 'Storage->change_user', when passed both a user and group name, changed the group.");
my $change_owner_rc = $an->Storage->change_owner({target => "", user => "root", group => "root"});
is($change_owner_rc, "1", "Verifying that 'Storage->change_user', when passed no target, returned '1'.");
$change_owner_rc = "";
$change_owner_rc = $an->Storage->change_owner({target => "/fake/file", user => "root", group => "root"});
is($change_owner_rc, "1", "Verifying that 'Storage->change_user', when passed a bad file, returned '1'.");
# copy_file
my $copy_file = "/tmp/an-tools.copy";
my $copied_ok = 0;
if (-e $copy_file)
{
unlink $copy_file or die "The test copy file: [$copy_file] exists (from a previous run?) and can't be removed. The error was: $!\n";
}
$an->Storage->copy_file({source => $test_file, target => $copy_file});
if (-e $copy_file)
{
$copied_ok = 1;
}
is($copied_ok, "1", "Verifying that 'Storage->copy_file' was able to copy the test file.");
my $copy_rc = $an->Storage->copy_file({target => $copy_file});
is($copy_rc, "1", "Verifying that 'Storage->copy_file' returned '1' when no source file was passed.");
$copy_rc = "";
$copy_rc = $an->Storage->copy_file({source => $test_file});
is($copy_rc, "2", "Verifying that 'Storage->copy_file' returned '2' when no target file was passed.");
$copy_rc = "";
$copy_rc = $an->Storage->copy_file({source => $test_file, target => $copy_file});
is($copy_rc, "3", "Verifying that 'Storage->copy_file' returned '3' when the target file already exists.");
$copy_rc = "";
$copy_rc = $an->Storage->copy_file({source => $test_file, target => $copy_file, overwrite => 1});
is($copy_rc, "0", "Verifying that 'Storage->copy_file' returned '0' when the target file already exists and overwrite was set.");
$copy_rc = "";
$copy_rc = $an->Storage->copy_file({source => "/fake/file", target => $copy_file});
is($copy_rc, "4", "Verifying that 'Storage->copy_file' returned '4' when the target file is passed but doesn't exist.");
# find
my $test_path = $an->Storage->find({ file => "AN/Tools.t" });
is($test_path, "/usr/share/perl5/AN/Tools.t", "Verifying that Storage->find successfully found 'AN/Tools.t'.");
my $bad_path = $an->Storage->find({ file => "AN/wa.t" });
is($bad_path, "#!not_found!#", "Verifying that Storage->find properly returned '#!not_found!#' for a non-existed file.");
# make_directory
my $test_directory = "/tmp/an-tools/test/directory";
if (-d $test_directory)
{
foreach my $this_directory ("/tmp/an-tools/test/directory", "/tmp/an-tools/test", "/tmp/an-tools")
{
rmdir $this_directory or die "Failed to remove the test directory: [$this_directory] (from a previous test?). The error was: $!\n";
}
}
# This uses an odd mode on purpose
$an->Storage->make_directory({directory => $test_directory, group => $use_group, user => $use_user, mode => "0757"});
my $created_directory = 0;
if (-d $test_directory)
{
$created_directory = 1;
}
is($created_directory, "1", "Verifying that 'Storage->create_directory' created a directory and its parents.");
my $directory_mode = $an->Storage->read_mode({target => $test_directory});
($uid, $gid) = (stat($test_directory))[4,5];
my $directory_user_name = getpwuid($uid);
my $directory_group_name = getgrgid($gid);
is($directory_mode, "0757", "Verifying that 'Storage->create_directory' created a directory with the requested mode.");
is($directory_user_name, $use_user, "Verifying that 'Storage->create_directory' created a directory with the requested owner.");
is($directory_group_name, $use_group, "Verifying that 'Storage->create_directory' created a directory with the requested group.");
# read_config
$an->data->{foo}{bar}{a} = "test";
is($an->Storage->read_config({ file => "AN/test.conf" }), 0, "Verifying that 'Storage->read_config' successfully found 'AN/test.conf'.");
is($an->Storage->read_config({ file => "" }), 1, "Verifying that 'Storage->read_config' returns '1' when called without a 'file' parameter being set.");
is($an->Storage->read_config({ file => "AN/moo.conf" }), 2, "Verifying that 'Storage->read_config' returns '2' when the non-existent 'AN/moo.conf' is passed.");
cmp_ok($an->data->{foo}{bar}{a}, 'eq', 'I am "a"', "Verifying that 'AN/test.conf's 'foo::bar::a' overwrote an earlier set value.");
cmp_ok($an->data->{foo}{bar}{b}, 'eq', 'I am "b", split with tabs and having trailing spaces.', "Verifying that 'AN/test.conf's 'foo::bar::b' has whitespaces removed as expected.");
cmp_ok($an->data->{foo}{baz}{1}, 'eq', 'This is \'1\' with no spaces', "Verifying that 'AN/test.conf's 'foo::baz::1' parsed without spaces around '='.");
cmp_ok($an->data->{foo}{baz}{2}, 'eq', 'I had a $dollar = sign and split with tabs.', "Verifying that 'AN/test.conf's 'foo::baz::2' had no trouble with a '\$' and '=' characters in the string.");
# read_file was tested earlier.
# read_mode was tested earlier.
# search_directories
my $array1 = $an->Storage->search_directories; my $array1 = $an->Storage->search_directories;
my $a1_count = @{$array1}; my $a1_count = @{$array1};
cmp_ok($a1_count, '>', 0, "Verifying that Storage->search_directories has at least one entry. Found: [$a1_count] directories."); cmp_ok($a1_count, '>', 0, "Verifying that Storage->search_directories has at least one entry. Found: [$a1_count] directories.");
$an->Storage->search_directories({directories => "/root,/usr/bin,/some/fake/directory"}); $an->Storage->search_directories({directories => "/root,/usr/bin,/some/fake/directory"});
my $array2 = $an->Storage->search_directories; my $array2 = $an->Storage->search_directories;
my $a2_count = @{$array2}; my $a2_count = @{$array2};
cmp_ok($a2_count, '==', 2, "Verifying that Storage->search_directories now has 2 entries from a passed in CSV, testing that the list changed and a fake directory was dropped."); cmp_ok($a2_count, '==', 2, "Verifying that Storage->search_directories now has 2 entries from a passed in CSV, testing that the list changed and a fake directory was dropped.");
$an->Storage->search_directories({directories => ["/usr/bin", "/tmp", "/home"] }); $an->Storage->search_directories({directories => ["/usr/bin", "/tmp", "/home"] });
my $array3 = $an->Storage->search_directories; my $array3 = $an->Storage->search_directories;
my $a3_count = @{$array3}; my $a3_count = @{$array3};
cmp_ok($a3_count, '==', 3, "Verifying that Storage->search_directories now has 3 entries from a passed in array reference, verifying that the list changed again."); cmp_ok($a3_count, '==', 3, "Verifying that Storage->search_directories now has 3 entries from a passed in array reference, verifying that the list changed again.");
$an->Storage->search_directories({directories => "invalid" }); $an->Storage->search_directories({directories => "invalid" });
my $array4 = $an->Storage->search_directories; my $array4 = $an->Storage->search_directories;
my $a4_count = @{$array4}; my $a4_count = @{$array4};
cmp_ok($a4_count, '==', $a1_count, "Verifying that Storage->search_directories has the original number of directories: [$a4_count] after being called with an invalid 'directories' parameter, showing that it reset properly."); cmp_ok($a4_count, '==', $a1_count, "Verifying that Storage->search_directories has the original number of directories: [$a4_count] after being called with an invalid 'directories' parameter, showing that it reset properly.");
# write_file was tested earlier
# Cleanup.
unlink $test_file;
unlink $copy_file;
foreach my $this_directory ("/tmp/an-tools/test/directory", "/tmp/an-tools/test", "/tmp/an-tools")
{
rmdir $this_directory or die "Failed to remove the test directory: [$this_directory] (from a previous test?). The error was: $!\n";
}
### AN::Tools::System tests
# call was tested during the Log->entry test and will be tested further below.
# Daemon tests require that we create a test daemon and a unit for it...
my $test_daemon_file = "/tmp/an-tools-test.daemon";
my $test_daemon_body = q|#!/usr/bin/perl
# This is a test daemon created for the AN::Tools test suite. It can safely be deleted.
use strict;
use warnings;
use AN::Tools;
my $an = AN::Tools->new();
$an->Log->entry({level => 1, priority => "info", raw => "AN::Tools Test daemon started."});
while(1)
{
sleep 2;
$an->Log->entry({level => 1, priority => "info", raw => "AN::Tools Test daemon looped..."});
}
exit;
|;
$an->Storage->write_file({body => $test_daemon_body, file => $test_daemon_file, group => "root", user => "root", mode => "755", overwrite => 1});
my $test_service_name = "an-tools-test.service";
my $test_service_file = "/usr/lib/systemd/system/".$test_service_name;
my $test_service_body = "[Unit]
Description=Test daemon used by AN::Tools test suite. It can safely be ignored/deleted.
[Service]
Type=simple
ExecStart=$test_daemon_file
ExecStop=/bin/kill -WINCH \${MAINPID}
";
$an->Storage->write_file({body => $test_service_body, file => $test_service_file, group => "root", user => "root", mode => "644", overwrite => 1});
$an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." daemon-reload"});
$an->System->stop_daemon({daemon => $test_service_name}); # Just in case...
# check_daemon
my $test_daemon_rc = $an->System->check_daemon({daemon => $test_service_name});
is($test_daemon_rc, "0", "Verifying that 'System->check_daemon' was able to confirm that the test service: [".$test_service_name."] was stopped.");
$test_daemon_rc = "";
$test_daemon_rc = $an->System->start_daemon({daemon => $test_service_name});
is($test_daemon_rc, "0", "Verifying that 'System->start_daemon' was able to start the test service: [".$test_service_name."].");
$test_daemon_rc = "";
$test_daemon_rc = $an->System->check_daemon({daemon => $test_service_name});
is($test_daemon_rc, "1", "Verifying that 'System->check_daemon' was able to confirm that the test service: [".$test_service_name."] is now running.");
$test_daemon_rc = "";
$test_daemon_rc = $an->System->stop_daemon({daemon => $test_service_name});
is($test_daemon_rc, "0", "Verifying that 'System->stop_daemon' was able to stop the test service: [".$test_service_name."].");
$test_daemon_rc = "";
$test_daemon_rc = $an->System->check_daemon({daemon => $test_service_name});
is($test_daemon_rc, "0", "Verifying that 'System->check_daemon' was able to confirm that the test service: [".$test_service_name."] was stopped.");
# Cleanup
unlink $test_service_file;
unlink $test_daemon_file;
$an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." daemon-reload"});
### AN::Tools::Template tests
# We're going to need a fake template file to test.
my $test_template_file = "/tmp/an-tools.html";
my $test_template_body = '<!-- start test1 -->
This is test template #1.
<!-- end test1 -->
<!-- start test2 -->
This is test template #2. It has a replacement: [#!variable!test!#].
<!-- end test2 -->
';
$an->Storage->write_file({body => $test_template_body, file => $test_template_file, mode => "644", overwrite => 1});
# get
my $test1_template = $an->Template->get({file => $test_template_file, name => "test1"});
is($test1_template, "This is test template #1.\n", "Verifying that 'Template->get' was able to read a test template.");
my $test2_template = $an->Template->get({file => $test_template_file, name => "test2", variables => { test => "boo!" }});
is($test2_template, "This is test template #2. It has a replacement: [boo!].\n", "Verifying that 'Template->get' was able to read a test template with a variable insertion.");
is($an->Template->skin, "alteeve", "Verifying that 'Template->skin' is initially set to 'alteeve'.");
$an->Template->skin({fatal => 0, set => "test"}); # We disable fatal because there may be no skin directory yet.
is($an->Template->skin, "test", "Verifying that 'Template->skin' was changed to 'test'.");
$an->Template->skin({fatal => 0, set => "alteeve"});
is($an->Template->skin, "alteeve", "Verifying that 'Template->skin' was changed back to 'alteeve'.");
# Clean up
unlink $test_template_file;
### AN::Tools::Validate tests
# is_ipv4
is($an->Validate->is_ipv4({ip => "0.0.0.0"}), "1", "Verifying that 'Validate->is_ipv4' recognizes '0.0.0.0' as a valid IP address.");
is($an->Validate->is_ipv4({ip => "255.255.255.255"}), "1", "Verifying that 'Validate->is_ipv4' recognizes '255.255.255.255' as a valid IP address.");
is($an->Validate->is_ipv4({ip => "256.255.255.255"}), "0", "Verifying that 'Validate->is_ipv4' recognizes '256.255.255.255' as an invalid IP address.");
is($an->Validate->is_ipv4({ip => "alteeve.com"}), "0", "Verifying that 'Validate->is_ipv4' recognizes 'alteeve.com' as an invalid IP address.");
is($an->Validate->is_ipv4({ip => "::1"}), "0", "Verifying that 'Validate->is_ipv4' recognizes '::1' as an invalid IP address.");
my $test_uuid = $an->Get->uuid;
die;
### AN::Tools::Words tests
#
die;
my $test_path = $an->Storage->find({ file => "AN/Tools.t" });
is($test_path, "/usr/share/perl5/AN/Tools.t", "Verifying that Storage->find successfully found 'AN/Tools.t'.");
my $bad_path = $an->Storage->find({ file => "AN/wa.t" });
is($bad_path, "#!not_found!#", "Verifying that Storage->find properly returned '#!not_found!#' for a non-existed file.");
# Config file read tests.
$an->data->{foo}{bar}{a} = "test";
is($an->Storage->read_config({ file => "AN/test.conf" }), 0, "Verifying that 'Storage->read_config' successfully found 'AN/test.conf'.");
is($an->Storage->read_config({ file => "" }), 1, "Verifying that 'Storage->read_config' returns '1' when called without a 'file' parameter being set.");
is($an->Storage->read_config({ file => "AN/moo.conf" }), 2, "Verifying that 'Storage->read_config' returns '2' when the non-existent 'AN/moo.conf' is passed.");
cmp_ok($an->data->{foo}{bar}{a}, 'eq', 'I am "a"', "Verifying that 'AN/test.conf's 'foo::bar::a' overwrote an earlier set value.");
cmp_ok($an->data->{foo}{bar}{b}, 'eq', 'I am "b", split with tabs and having trailing spaces.', "Verifying that 'AN/test.conf's 'foo::bar::b' has whitespaces removed as expected.");
cmp_ok($an->data->{foo}{baz}{1}, 'eq', 'This is \'1\' with no spaces', "Verifying that 'AN/test.conf's 'foo::baz::1' parsed without spaces around '='.");
cmp_ok($an->data->{foo}{baz}{2}, 'eq', 'I had a $dollar = sign and split with tabs.', "Verifying that 'AN/test.conf's 'foo::baz::2' had no trouble with a '\$' and '=' characters in the string.");
### AN::Tools::Words methods ### AN::Tools::Words methods
# Make sure we can read words files # Make sure we can read words files

@ -15,6 +15,7 @@ my $THIS_FILE = "Get.pm";
# host_uuid # host_uuid
# network_details # network_details
# switches # switches
# uuid
=pod =pod
@ -360,6 +361,21 @@ sub switches
return(0); return(0);
} }
=head2 uuid
This method returns a new UUID (using 'uuidgen' from the system). It takes no parameters.
=cut
sub uuid
{
my $self = shift;
my $an = $self->parent;
my $uuid = $an->System->call({shell_call => $an->data->{path}{exe}{uuidgen}});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { uuid => $uuid }});
return($uuid);
}
# =head3 # =head3
# #

@ -18,6 +18,7 @@ my $THIS_FILE = "Storage.pm";
# make_directory # make_directory
# read_config # read_config
# read_file # read_file
# read_mode
# search_directories # search_directories
# write_file # write_file
@ -152,7 +153,7 @@ This changes the owner and/or group of a file or directory.
$an->Storage->change_owner({target => "/tmp/foo", mode => "0644"}); $an->Storage->change_owner({target => "/tmp/foo", mode => "0644"});
If it fails to write the file, an alert will be logged. If it fails to write the file, an alert will be logged and 'C<< 1 >>' will be returned. Otherwise, 'C<< 0 >>' will be returned.
Parameters; Parameters;
@ -178,7 +179,8 @@ sub change_owner
my $target = defined $parameter->{target} ? $parameter->{target} : ""; my $target = defined $parameter->{target} ? $parameter->{target} : "";
my $group = defined $parameter->{group} ? $parameter->{group} : ""; my $group = defined $parameter->{group} ? $parameter->{group} : "";
my $user = defined $parameter->{user} ? $parameter->{user} : ""; my $user = defined $parameter->{user} ? $parameter->{user} : "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { my $debug = 3;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
target => $target, target => $target,
group => $group, group => $group,
user => $user, user => $user,
@ -187,16 +189,11 @@ sub change_owner
# Make sure the user and group and just one digit or word. # Make sure the user and group and just one digit or word.
$user =~ s/^(\S+)\s.*$/$1/; $user =~ s/^(\S+)\s.*$/$1/;
$group =~ s/^(\S+)\s.*$/$1/; $group =~ s/^(\S+)\s.*$/$1/;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
group => $group, group => $group,
user => $user, user => $user,
}}); }});
# If the group is a series of digits, remove all but the first.
if (defined $group)
{
}
my $string = ""; my $string = "";
my $error = 0; my $error = 0;
if (not $target) if (not $target)
@ -205,31 +202,42 @@ sub change_owner
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0039"}); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0039"});
$error = 1; $error = 1;
} }
if (not -e $target)
{
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "alert", key => "log_0051", variables => {target => $target }});
$error = 1;
}
if (defined $user) $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { user => $user }});
if ($user ne "")
{ {
$string = $user; $string = $user;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { string => $string }});
} }
if (defined $group)
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { group => $group }});
if ($group ne "")
{ {
$string .= ":".$group; $string .= ":".$group;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { string => $string }});
} }
if ((not $error) && ($string)) $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { error => $error, string => $string }});
if ((not $error) && ($string ne ""))
{ {
my $shell_call = $an->data->{path}{exe}{'chown'}." $string $target"; my $shell_call = $an->data->{path}{exe}{'chown'}." $string $target";
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0011", variables => { shell_call => $shell_call }}); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0011", variables => { shell_call => $shell_call }});
open (my $file_handle, $shell_call." 2>&1 |") or $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0014", variables => { shell_call => $shell_call, error => $! }}); open (my $file_handle, $shell_call." 2>&1 |") or $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0014", variables => { shell_call => $shell_call, error => $! }});
while(<$file_handle>) while(<$file_handle>)
{ {
chomp; chomp;
my $line = $_; my $line = $_;
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0017", variables => { line => $line }}); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0017", variables => { line => $line }});
} }
close $file_handle; close $file_handle;
} }
return(0); return($error);
} }
=head2 copy_file =head2 copy_file
@ -249,7 +257,7 @@ If this is not passed and the target exists, this module will return 'C<< 3 >>'.
=head3 source (required) =head3 source (required)
This is the source file. if it doesn't exist, this method will return 'C<< 1 >>'. This is the source file. If it isn't specified, 'C<< 1 >>' will be returned. If it doesn't exist, this method will return 'C<< 4 >>'.
=head3 target (required) =head3 target (required)
@ -279,6 +287,11 @@ sub copy_file
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0044"}); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0044"});
return(1); return(1);
} }
elsif (not -e $source)
{
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0052", variables => { source => $source }});
return(4);
}
if (not $target) if (not $target)
{ {
# No target passed. # No target passed.
@ -668,6 +681,62 @@ sub read_file
return($body); return($body);
} }
=head2 read_mode
This reads a file or directory's mode (sticky-bit and ownership) and returns the mode as a four-digit string (ie: 'c<< 0644 >>', 'C<< 4755 >>', etc.
my $mode = $an->Storage->read_mode({file => "/tmp/foo"});
If it fails to find the file, or the file is not readable, 'C<< 0 >>' is returned.
Parameters;
=head3 file (required)
This is the name of the file or directory to check the mode of.
=cut
sub read_mode
{
my $self = shift;
my $parameter = shift;
my $an = $self->parent;
my $debug = 1;
my $target = defined $parameter->{target} ? $parameter->{target} : "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { target => $target }});
if (not $target)
{
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0050"});
return(1);
}
# Read the mode and convert it to digits.
my $mode = (stat($target))[2];
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mode => $mode }});
# Return the full mode, unless it is a directory or file. In those cases, return the last four digits.
my $say_mode = $mode;
if (-d $target)
{
# Directory - five digits
$say_mode = sprintf("%04o", $mode);
$say_mode =~ s/^\d(\d\d\d\d)$/$1/;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { say_mode => $say_mode }});
}
elsif (-f $target)
{
# File - six digits
$say_mode = sprintf("%04o", $mode);
$say_mode =~ s/^\d\d(\d\d\d\d)$/$1/;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { say_mode => $say_mode }});
}
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { mode => $mode, say_mode => $say_mode }});
return($say_mode);
}
=head2 search_directories =head2 search_directories
This method returns an array reference of directories to search within for files and directories. This method returns an array reference of directories to search within for files and directories.

@ -14,6 +14,7 @@ my $THIS_FILE = "System.pm";
# call # call
# check_daemon # check_daemon
# start_daemon # start_daemon
# stop_daemon
=pod =pod
@ -102,7 +103,7 @@ sub call
my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : ""; my $shell_call = defined $parameter->{shell_call} ? $parameter->{shell_call} : "";
my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0; my $secure = defined $parameter->{secure} ? $parameter->{secure} : 0;
my $source = defined $parameter->{source} ? $parameter->{source} : $THIS_FILE; my $source = defined $parameter->{source} ? $parameter->{source} : $THIS_FILE;
$an->Log->variables({source => $source, line => $line, level => 2, secure => $secure, list => { shell_call => $shell_call }}); $an->Log->variables({source => $source, line => $line, level => 3, secure => $secure, list => { shell_call => $shell_call }});
my $output = "#!error!#"; my $output = "#!error!#";
if (not $shell_call) if (not $shell_call)
@ -151,24 +152,30 @@ sub check_daemon
my $parameter = shift; my $parameter = shift;
my $an = $self->parent; my $an = $self->parent;
my $return = 2; my $return = 2;
my $daemon = defined $parameter->{daemon} ? $parameter->{daemon} : ""; my $daemon = defined $parameter->{daemon} ? $parameter->{daemon} : "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { daemon => $daemon }}); my $say_daemon = $daemon =~ /\.service$/ ? $daemon : $daemon.".service";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { daemon => $daemon, say_daemon => $say_daemon }});
my $output = $an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." status ".$daemon.".service; ".$an->data->{path}{exe}{'echo'}." return_code:\$?"}); my $output = $an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." status ".$say_daemon."; ".$an->data->{path}{exe}{'echo'}." return_code:\$?"});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output }});
foreach my $line (split/\n/, $output) foreach my $line (split/\n/, $output)
{ {
if ($line =~ /return_code:(\d+)/) if ($line =~ /return_code:(\d+)/)
{ {
my $return_code = $1; my $return_code = $1;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { return_code => $return_code }});
if ($return_code eq "3") if ($return_code eq "3")
{ {
# Stopped
$return = 0; $return = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
} }
elsif ($return_code eq "0") elsif ($return_code eq "0")
{ {
# Running
$return = 1; $return = 1;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
} }
} }
} }
@ -179,7 +186,9 @@ sub check_daemon
=head2 start_daemon =head2 start_daemon
This method starts a daemon. This method starts a daemon. The return code from the start request will be returned.
If the return code for the start command wasn't read, C<< undef >> is returned.
Parameters; Parameters;
@ -194,29 +203,62 @@ sub start_daemon
my $parameter = shift; my $parameter = shift;
my $an = $self->parent; my $an = $self->parent;
my $return = 2; my $return = undef;
my $daemon = defined $parameter->{daemon} ? $parameter->{daemon} : ""; my $daemon = defined $parameter->{daemon} ? $parameter->{daemon} : "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { daemon => $daemon }}); my $say_daemon = $daemon =~ /\.service$/ ? $daemon : $daemon.".service";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { daemon => $daemon, say_daemon => $say_daemon }});
my $output = $an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." start ".$daemon.".service; ".$an->data->{path}{exe}{'echo'}." return_code:\$?"}); my $output = $an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." start ".$say_daemon."; ".$an->data->{path}{exe}{'echo'}." return_code:\$?"});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { output => $output }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output }});
foreach my $line (split/\n/, $output) foreach my $line (split/\n/, $output)
{ {
if ($line =~ /return_code:(\d+)/) if ($line =~ /return_code:(\d+)/)
{ {
my $return_code = $1; $return = $1;
if ($return_code eq "3") $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
{
$return = 0;
}
elsif ($return_code eq "0")
{
$return = 1;
}
} }
} }
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 2, list => { 'return' => $return }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
return($return);
}
=head2 stop_daemon
This method stops a daemon. The return code from the stop request will be returned.
If the return code for the stop command wasn't read, C<< undef >> is returned.
Parameters;
=head3 daemon (required)
This is the name of the daemon to stop.
=cut
sub stop_daemon
{
my $self = shift;
my $parameter = shift;
my $an = $self->parent;
my $return = undef;
my $daemon = defined $parameter->{daemon} ? $parameter->{daemon} : "";
my $say_daemon = $daemon =~ /\.service$/ ? $daemon : $daemon.".service";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { daemon => $daemon, say_daemon => $say_daemon }});
my $output = $an->System->call({shell_call => $an->data->{path}{exe}{systemctl}." stop ".$say_daemon."; ".$an->data->{path}{exe}{'echo'}." return_code:\$?"});
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { output => $output }});
foreach my $line (split/\n/, $output)
{
if ($line =~ /return_code:(\d+)/)
{
$return = $1;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
}
}
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'return' => $return }});
return($return); return($return);
} }

@ -109,6 +109,7 @@ sub get
my $parameter = shift; my $parameter = shift;
my $an = $self->parent; my $an = $self->parent;
my $debug = 1;
my $file = defined $parameter->{file} ? $parameter->{file} : ""; my $file = defined $parameter->{file} ? $parameter->{file} : "";
my $language = defined $parameter->{language} ? $parameter->{language} : $an->Words->language; my $language = defined $parameter->{language} ? $parameter->{language} : $an->Words->language;
my $name = defined $parameter->{name} ? $parameter->{name} : ""; my $name = defined $parameter->{name} ? $parameter->{name} : "";
@ -117,7 +118,7 @@ sub get
$skin = $an->data->{path}{directories}{skins}."/".$skin; $skin = $an->data->{path}{directories}{skins}."/".$skin;
my $template = ""; my $template = "";
my $source = ""; my $source = "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
file => $file, file => $file,
language => $language, language => $language,
name => $name, name => $name,
@ -134,8 +135,18 @@ sub get
else else
{ {
# Make sure the file exists. # Make sure the file exists.
$source = $skin."/".$file; if ($file =~ /^\//)
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { source => $source }}); {
# Fully defined path, don't alter it.
$source = $file;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source => $source }});
}
else
{
# Just a file name, prepend the skin path.
$source = $skin."/".$file;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source => $source }});
}
if (not -e $source) if (not -e $source)
{ {
@ -162,13 +173,13 @@ sub get
{ {
my $in_template = 0; my $in_template = 0;
my $shell_call = $source; my $shell_call = $source;
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0012", variables => { shell_call => $shell_call }}); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0012", variables => { shell_call => $shell_call }});
open (my $file_handle, "<", $shell_call) or $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0015", variables => { shell_call => $shell_call, error => $! }}); open (my $file_handle, "<", $shell_call) or $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 0, priority => "err", key => "log_0015", variables => { shell_call => $shell_call, error => $! }});
while(<$file_handle>) while(<$file_handle>)
{ {
chomp; chomp;
my $line = $_; my $line = $_;
$an->Log->entry({source => $THIS_FILE, line => __LINE__, level => 3, key => "log_0023", variables => { line => $line }}); $an->Log->entry({source => $THIS_FILE, line => __LINE__, level => $debug, key => "log_0023", variables => { line => $line }});
if ($line =~ /^<!-- start $name -->/) if ($line =~ /^<!-- start $name -->/)
{ {
$in_template = 1; $in_template = 1;
@ -188,14 +199,14 @@ sub get
} }
} }
close $file_handle; close $file_handle;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { template => $template }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { template => $template }});
# Now that I have the skin, inject my variables. We'll use Words->string() to do this for us. # Now that I have the skin, inject my variables. We'll use Words->string() to do this for us.
$template = $an->Words->string({ $template = $an->Words->string({
string => $template, string => $template,
variables => $variables, variables => $variables,
}); });
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { source => $source }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { source => $source }});
} }
return($template); return($template);
@ -215,6 +226,16 @@ Set the active skin to 'C<< foo >>'. Only pass the skin name, not the full path.
$an->Template->skin({set => "foo"}); $an->Template->skin({set => "foo"});
Parameters;
=head3 fatal (optional)
If passed along with C<< set >>, the skin will be set even if the skin directory does not exit.
=head3 set (optional)
If passed a string, that will become the new active skin. If the skin directory does not exist, however, and C<< fatal >> is not set, the request will be ignored.
=cut =cut
sub skin sub skin
{ {
@ -222,17 +243,19 @@ sub skin
my $parameter = shift; my $parameter = shift;
my $an = $self->parent; my $an = $self->parent;
my $set = defined $parameter->{skin} ? $parameter->{skin} : ""; my $debug = 3;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { file => $set }}); my $fatal = defined $parameter->{fatal} ? $parameter->{fatal} : 1;
my $set = defined $parameter->{set} ? $parameter->{set} : "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { fatal => $fatal, file => $set }});
if ($set) if ($set)
{ {
my $skin_directory = $an->data->{path}{directories}{skins}."/".$set; my $skin_directory = $an->data->{path}{directories}{skins}."/".$set;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { skin_directory => $skin_directory }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { skin_directory => $skin_directory }});
if (-d $skin_directory) if ((-d $skin_directory) or (not $fatal))
{ {
$self->{SKIN}{HTML} = $set; $self->{SKIN}{HTML} = $set;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }});
} }
else else
{ {
@ -240,11 +263,14 @@ sub skin
} }
} }
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }});
if (not $self->{SKIN}{HTML}) if (not $self->{SKIN}{HTML})
{ {
$self->{SKIN}{HTML} = $an->data->{defaults}{template}{html}; $self->{SKIN}{HTML} = $an->data->{defaults}{template}{html};
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML}, 'defaults::template::html' => $an->data->{defaults}{template}{html} }});
} }
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { 'SKIN::HTML' => $self->{SKIN}{HTML} }});
return($self->{SKIN}{HTML}); return($self->{SKIN}{HTML});
} }

@ -94,8 +94,9 @@ sub is_ipv4
my $parameter = shift; my $parameter = shift;
my $an = $self->parent; my $an = $self->parent;
my $ip = defined $parameter->{ip} ? $parameter->{ip} : ""; my $debug = 3;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { ip => $ip }}); my $ip = defined $parameter->{ip} ? $parameter->{ip} : "";
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { ip => $ip }});
my $valid = 1; my $valid = 1;
if ($ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/) if ($ip =~ /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/)
@ -105,7 +106,7 @@ sub is_ipv4
my $second_octet = $2; my $second_octet = $2;
my $third_octet = $3; my $third_octet = $3;
my $fourth_octet = $4; my $fourth_octet = $4;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => {
first_octet => $first_octet, first_octet => $first_octet,
second_octet => $second_octet, second_octet => $second_octet,
third_octet => $third_octet, third_octet => $third_octet,
@ -119,17 +120,17 @@ sub is_ipv4
{ {
# One of the octets is out of range. # One of the octets is out of range.
$valid = 0; $valid = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { valid => $valid }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { valid => $valid }});
} }
} }
else else
{ {
# Not in the right format. # Not in the right format.
$valid = 0; $valid = 0;
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { valid => $valid }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { valid => $valid }});
} }
$an->Log->variables({source => $THIS_FILE, line => __LINE__, level => 3, list => { valid => $valid }}); $an->Log->variables({source => $THIS_FILE, line => __LINE__, level => $debug, list => { valid => $valid }});
return($valid); return($valid);
} }

@ -50,7 +50,7 @@ It also has replacement variables: [#!variable!first!#] and [#!variable!second!#
<key name="log_0028">Successfully read the words file: [#!variable!file!#].</key> <key name="log_0028">Successfully read the words file: [#!variable!file!#].</key>
<key name="log_0029"><![CDATA[[ Error ] - Storage->find() failed to find: [#!variable!file!#].]]></key> <key name="log_0029"><![CDATA[[ Error ] - Storage->find() failed to find: [#!variable!file!#].]]></key>
<key name="log_0030"><![CDATA[[ Warning ] - Template->skin() was asked to set the skin: [#!variable!set!#], but the source directory: [#!variable!skin_directory!#] doesn't exist. Ignoring.]]></key> <key name="log_0030"><![CDATA[[ Warning ] - Template->skin() was asked to set the skin: [#!variable!set!#], but the source directory: [#!variable!skin_directory!#] doesn't exist. Ignoring.]]></key>
<key name="log_0031"><![CDATA[[ Warning ] - Storage->search_directories() was passed the array: [#!variable!array!#], but it wasn't actually an array. Using \@INC + path::directories::tools + \$ENV{'PATH'} for the list of directories to search instead.]]></key> <key name="log_0031"><![CDATA[[ Warning ] - Storage->search_directories() was passed the array: [#!variable!array!#], but it wasn't actually an array. Using @INC + path::directories::tools + \$ENV{'PATH'} for the list of directories to search instead.]]></key>
<key name="log_0032"><![CDATA[[ Warning ] - Words->read()' called without a file name to read.]]></key> <key name="log_0032"><![CDATA[[ Warning ] - Words->read()' called without a file name to read.]]></key>
<key name="log_0033"><![CDATA[[ Warning ] - Words->read()' asked to read: [#!variable!file!#] which was not found.]]></key> <key name="log_0033"><![CDATA[[ Warning ] - Words->read()' asked to read: [#!variable!file!#] which was not found.]]></key>
<key name="log_0034"><![CDATA[[ Warning ] - AN::Tools::Words->read()' asked to read: [#!variable!file!#] which was not readable by: [#!variable!user!#] (uid/euid: [#!variable!uid!#]).]]></key> <key name="log_0034"><![CDATA[[ Warning ] - AN::Tools::Words->read()' asked to read: [#!variable!file!#] which was not readable by: [#!variable!user!#] (uid/euid: [#!variable!uid!#]).]]></key>
@ -69,6 +69,9 @@ It also has replacement variables: [#!variable!first!#] and [#!variable!second!#
<key name="log_0047"><![CDATA[[ Error ] - The module Log->level() was passed an invalid log level: [#!variable!set!#]. Only '0', '1', '2', '3' or '4' are valid.]]></key> <key name="log_0047"><![CDATA[[ Error ] - The module Log->level() was passed an invalid log level: [#!variable!set!#]. Only '0', '1', '2', '3' or '4' are valid.]]></key>
<key name="log_0048"><![CDATA[[ Warning ] - Testing of AN::Tools is beginning. This will generate warnings and alerts and are not a concern.]]></key> <key name="log_0048"><![CDATA[[ Warning ] - Testing of AN::Tools is beginning. This will generate warnings and alerts and are not a concern.]]></key>
<key name="log_0049"><![CDATA[[ Warning ] - Testing of AN::Tools is complete.]]></key> <key name="log_0049"><![CDATA[[ Warning ] - Testing of AN::Tools is complete.]]></key>
<key name="log_0050"><![CDATA[[ Error ] - The module Storage->read_mode() was called without a 'target' parameter, or the parameter was empty.]]></key>
<key name="log_0051"><![CDATA[[ Error ] - The module Storage->change_owner() was asked to change the ownership of: [#!variable!target!#] which doesn't exist.]]></key>
<key name="log_0052"><![CDATA[[ Error ] - The module Storage->copy_file() was called but the source file: [#!variable!source!#] doesn't exist.]]></key>
<!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. --> <!-- Test words. Do NOT change unless you update 't/Words.t' or tests will needlessly fail. -->
<key name="t_0000">Test</key> <key name="t_0000">Test</key>

Loading…
Cancel
Save