App-Sqitch

 view release on metacpan or  search on metacpan

Changes  view on Meta::CPAN

       its Unicode improvements. Thanks to Mark Tyrrell for the report and
       @tiberiusferreira and Perl Monks `1nickt` and`InfiniteSilence` for the
       feedback (#825).

1.4.1  2024-02-04T16:35:32Z
     - Removed the quoting of the role and warehouse identifiers that was
       added to the Snowflake engine in v1.4.0. Turns out Snowflake allows a
       warehouse to be specified in a different database, in which case dots
       are valid in the name and should not be quoted! So users must properly
       quote when necessary, but added notes to `sqitchtutorial-snowflake.pod`
       on the need to use URI escapes for special characters. Thanks to
       Patrick Sabo for the find, and to @marc-marketparts for validating
       that URI encoding works.
     - Added notes on URL encoding database URLs to `sqitch-target.pod`, the
       main reference for database URLs in the Sqitch documentation.
     - Fixed the output of the list of changes to be deployed or reverted to
       actually require `--verbose` twice, as described in the v1.4.0 changes,
       and not just once. Thanks to Erik Wienhold for the PR (#785)!
     - Removed the duplicate change name from the output of the list of
       changes to be deployed or reverted with `-VV`. Thanks to Erik Wienhold
       for the PR (#787)!

lib/App/Sqitch/Command/config.pm  view on Meta::CPAN


=head1 Synopsis

  my $cmd = App::Sqitch::Command::config->new(\%params);
  $cmd->execute;

=head1 Description

You can query/set/replace/unset Sqitch options with this command. The name is
actually the section and the key separated by a dot, and the value will be
escaped.

=head1 Interface

=head2 Class Methods

=head3 C<options>

  my @opts = App::Sqitch::Command::config->options;

Returns a list of L<Getopt::Long> option specifications for the command-line

lib/App/Sqitch/Plan/Line.pm  view on Meta::CPAN

};

has plan => (
    is       => 'ro',
    isa      => Plan,
    weak_ref => 1,
    required => 1,
    handles  => [qw(sqitch project uri target)],
);

my %escape = (
    "\n" => '\\n',
    "\r" => '\\r',
    '\\' => '\\\\',
);

my %unescape = reverse %escape;

sub BUILDARGS {
    my $class = shift;
    my $p = @_ == 1 && ref $_[0] ? { %{ +shift } } : { @_ };
    if (my $note = $p->{note}) {
        # Trim and then encode newlines.
        $note =~ s/\A\s+//;
        $note =~ s/\s+\z//;
        $note =~ s/(\\[\\nr])/$unescape{$1}/g;
        $p->{note} = $note;
        $p->{rspace} //= ' ' if $note && $p->{name};
    }
    return $p;
}

sub request_note {
    my ( $self, %p ) = @_;
    my $note = $self->note // '';
    return $note if $note =~ /\S/;

lib/App/Sqitch/Plan/Line.pm  view on Meta::CPAN

}

sub format_content {
    my $self = shift;
    join '', $self->format_operator, $self->format_name;
}

sub format_note {
    my $note = shift->note;
    return '' unless length $note;
    $note =~ s/([\r\n\\])/$escape{$1}/g;
    return "# $note";
}

sub as_string {
    my $self = shift;
    return $self->lspace
         . $self->format_content
         . $self->rspace
         . $self->format_note;
}

lib/sqitch-config.pod  view on Meta::CPAN

  sqitch config [<file-option>] --unset-all name [value_regex]
  sqitch config [<file-option>] --rename-section old_name new_name
  sqitch config [<file-option>] --remove-section name
  sqitch config [<file-option>] -l | --list
  sqitch config [<file-option>] -e | --edit

=head1 Description

You can query/set/replace/unset Sqitch options with this command. The name is
actually the section and the key separated by a dot, and the value will be
escaped.

Multiple lines can be added to an option by using the C<--add> option. If you
want to update or unset an option which can occur on multiple lines, a Perl
regular expression C<value_regex> needs to be given. Only the existing values
that match the regex will be updated or unset. If you want to handle lines
that do not match the regex, just prepend a single C<!> (exclamation point) in
front (see L<Examples>).

The C<type> specifier can be C<--int>, C<--num>, or C<--bool>, to ensure that
the variable(s) are of the given type and convert the value to the canonical

lib/sqitch-config.pod  view on Meta::CPAN

If you like to live dangerously, you can replace all C<core.fuzzle.clack> with a
new one with

  % sqitch config --replace-all core.fuzzle.clack funk

However, if you only want to replace lines that don't match C<bar>, prepend
the matching regular expression with an exclamation point (C<!>), like so:

  % sqitch config --replace-all core.fuzzle.clack yow '!bar'

To match only values with an exclamation mark, you have to escape it:

  % sqitch config section.key '[!]'

To add a new setting without altering any of the existing ones, use:

  % sqitch config --add core.fuzzle.set widget=fred

=head1 Configuration File

The sqitch configuration file contains a number of variables that affect the

lib/sqitch-config.pod  view on Meta::CPAN

which means that there must be a section header before the first setting of a
variable.

Sections can be further divided into subsections. To begin a subsection put
its name in double quotes, separated by space from the section name, in the
section header, like in the example below:

     [section "subsection"]

Subsection names are case sensitive and can contain any characters except
newline (double quote and backslash have to be escaped as C<\"> and C<\\>,
respectively). Section headers cannot span multiple lines. Variables may
belong directly to a section or to a given subsection. You can have
C<[section]> if you have C<[section "subsection"]>, but you don't need to.

All the other lines (and the remainder of the line after the section header)
are recognized as setting variables, in the form C<name = value>. If there is
no equal sign on the line, the entire line is taken as name and the variable
is recognized as boolean C<true>. The variable names are case-insensitive,
allow only alphanumeric characters and C<->, and must start with an alphabetic
character. There can be more than one value for a given variable; we say then

lib/sqitch-config.pod  view on Meta::CPAN

The values following the equals sign in variable assignments are either
strings, integers, numbers, or booleans. Boolean values may be given as
yes/no, 1/0, true/false or on/off. Case is not significant in boolean values,
when converting value to the canonical form using the C<--bool> type
specifier; C<sqitch config> will ensure that the output is "true" or "false".

String values may be entirely or partially enclosed in double quotes. You need
to enclose variable values in double quotes if you want to preserve leading or
trailing whitespace, or if the variable value contains comment characters
(i.e. it contains C<#> or C<;>). Double quote and backslash characters in
variable values must be escaped: use C<\"> for C<"> and C<\\> for C<\>.

The following escape sequences (beside C<\"> and C<\\>) are recognized: C<\n>
for newline character (NL), C<\t> for horizontal tabulation (HT, TAB) and
C<\b> for backspace (BS). No other character escape sequence or octal
character sequence is valid.

Variable values ending in a C<\> are continued on the next line in the
customary UNIX fashion.

Some variables may require a special value format.

=head2 Example

  # Core variables

t/blank.t  view on Meta::CPAN

    rspace  => "\t",
    note   => 'blah blah blah',
), 'Create tag with more stuff';

is $blank->as_string, "  \t# blah blah blah",
    'It should stringify correctly';

ok $blank = $CLASS->new(plan => $plan, note => "foo\nbar\nbaz\\\n"),
    'Create a blank with newlines and backslashes in the note';
is $blank->note, "foo\nbar\nbaz\\",
    'The newlines and backslashe should not be escaped';

is $blank->format_note, '# foo\\nbar\\nbaz\\\\',
    'The newlines and backslahs should be escaped by format_note';

ok $blank = $CLASS->new(plan => $plan, note => "foo\\nbar\\nbaz\\\\\\n"),
    'Create a blank with escapes';
is $blank->note, "foo\nbar\nbaz\\\n", 'Note shoud be unescaped';

for my $spec (
    ["\n\n\nfoo" => 'foo', 'Leading newlines' ],
    ["\r\r\rfoo" => 'foo', 'Leading line feeds' ],
    ["foo\n\n\n" => 'foo', 'Trailing newlines' ],
    ["foo\r\r\r" => 'foo', 'trailing line feeds' ],
    ["\r\n\r\n\r\nfoo\n\nbar\r" => "foo\n\nbar", 'Leading and trailing vertical space' ],
    ["\n\n\n  foo \n" => 'foo', 'Leading and trailing newlines and spaces' ],
) {
    is $CLASS->new(

t/exasol.t  view on Meta::CPAN

throws_ok { $exa->_cid } qr/OW/,
    '_cid should rethrow unexpected DB error';
$mock_exa->unmock('dbh');

##############################################################################
# Test _file_for_script().
can_ok $exa, '_file_for_script';
is $exa->_file_for_script(Path::Class::file 'foo'), 'foo',
    'File without special characters should be used directly';
is $exa->_file_for_script(Path::Class::file '"foo"'), '""foo""',
    'Double quotes should be SQL-escaped';

# Get the temp dir used by the engine.
ok my $tmpdir = $exa->tmpdir, 'Get temp dir';
isa_ok $tmpdir, 'Path::Class::Dir', 'Temp dir';

# Make sure a file with @ is aliased.
my $file = $tmpdir->file('foo@bar.sql');
$file->touch; # File must exist, because on Windows it gets copied.
is $exa->_file_for_script($file), $tmpdir->file('foo_bar.sql'),
    'File with special char should be aliased';

t/exasol.t  view on Meta::CPAN

    throws_ok { $exa->_file_for_script($file) } 'App::Sqitch::X',
        'Should get an error on failure to delete the alias';
    is $@->ident, 'exasol', 'File deletion error ident should be "exasol"';
    is $@->message, __x(
        'Cannot remove {file}: {error}',
        file  => $tmpdir->file('foo_bar.sql'),
        error => $!,
    ), 'File deletion error message should be correct';
}

# Make sure double-quotes are escaped.
WIN32: {
    $file = $tmpdir->file('"foo$bar".sql');
    my $mock_file = Test::MockModule->new(ref $file);
    # Windows doesn't like the quotation marks, so prevent it from writing.
    $mock_file->mock(copy_to => 1) if App::Sqitch::ISWIN;
    is $exa->_file_for_script($file), $tmpdir->file('""foo_bar"".sql'),
        'File with special char and quotes should be aliased';
}

##############################################################################
# Test file and handle running.
my @run;
$mock_exa->mock(_capture => sub {shift; @run = @_ });
ok $exa->run_file('foo/bar.sql'), 'Run foo/bar.sql';
is_deeply \@run, ['@"foo/bar.sql"'],
    'File should be passed to capture()';

ok $exa->run_file('foo/"bar".sql'), 'Run foo/"bar".sql';
is_deeply \@run, ['@"foo/""bar"".sql"'],
    'Double quotes in file passed to capture() should be escaped';

ok $exa->run_handle('FH'), 'Spool a "file handle"';
my $handles = shift @spool;
is_deeply \@spool, [$exa->exaplus],
    'exaplus command should be passed to spool()';
isa_ok $handles, 'ARRAY', 'Array ove handles should be passed to spool';
$fh = $handles->[0];
is join('', <$fh>), $exa->_script, 'First file handle should be script';
is $handles->[1], 'FH', 'Second should be the passed handle';

t/mysql.t  view on Meta::CPAN


ok $mysql->_spool('FH'), 'Call _spool';
is_deeply \@spool, [['FH'], $mysql->mysql],
    'Command should be passed to spool()';
$mysql->set_variables(foo => 'bar', '"that"' => "'this'");
ok $mysql->_spool('FH'), 'Call _spool with variables';
ok my $fh = shift @{ $spool[0] }, 'Get variables file handle';
is_deeply \@spool, [['FH'], $mysql->mysql],
    'Command should be passed to spool() after variables handle';
is join("\n", <$fh>), qq{SET \@"""that""" = '''this''', \@"foo" = 'bar';\n},
    'Variables should have been escaped and set';
$mysql->clear_variables;

ok $mysql->_capture(qw(foo bar baz)), 'Call _capture';
is_deeply \@capture, [$mysql->mysql, qw(foo bar baz)],
    'Command should be passed to capture()';

# Without password.
$target = App::Sqitch::Target->new( sqitch => $sqitch );
ok $mysql = $CLASS->new(sqitch => $sqitch, target => $target),
    'Create a mysql with sqitch with no pw';

t/mysql.t  view on Meta::CPAN


ok $mysql->run_file('foo/bar.sql'), 'Run foo/bar.sql with vars';
is_deeply \@run, [$mysql->mysql, '--execute', "${set}source foo/bar.sql"],
    'Variabls and file should be passed to run()';
@run = ();

ok $mysql->run_handle('FH'), 'Spool a "file handle"';
ok $fh = shift @{ $spool[0] }, 'Get variables file handle';
is_deeply \@spool, [['FH'], $mysql->mysql],
    'File handle should be passed to spool() after variables handle';
is join("\n", <$fh>), $set, 'Variables should have been escaped and set';
@spool = ();

ok $mysql->run_verify('foo/bar.sql'), 'Verbosely verify foo/bar.sql with vars';
is_deeply \@run, [$mysql->mysql, '--execute', "${set}source foo/bar.sql"],
    'Variables and verify file should be passed to run()';
@run = ();

# Reset verbosity to send verify to spool.
$mock_sqitch->unmock('verbosity');
ok $mysql->run_verify('foo/bar.sql'), 'Verify foo/bar.sql with vars';

t/oracle.t  view on Meta::CPAN

        $ora->_capture('whatever'),
    } 'App::Sqitch::X', '_capture should die when sqlplus dies';
}, qr/^OMGWTF/, 'STDERR should be emitted by _capture';

##############################################################################
# Test _file_for_script().
can_ok $ora, '_file_for_script';
is $ora->_file_for_script(Path::Class::file 'foo'), 'foo',
    'File without special characters should be used directly';
is $ora->_file_for_script(Path::Class::file '"foo"'), '""foo""',
    'Double quotes should be SQL-escaped';

# Get the temp dir used by the engine.
ok my $tmpdir = $ora->tmpdir, 'Get temp dir';
isa_ok $tmpdir, 'Path::Class::Dir', 'Temp dir';

# Make sure a file with @ is aliased.
my $file = $tmpdir->file('foo@bar.sql');
$file->touch; # File must exist, because on Windows it gets copied.
is $ora->_file_for_script($file), $tmpdir->file('foo_bar.sql'),
    'File with special char should be aliased';

t/oracle.t  view on Meta::CPAN

    throws_ok { $ora->_file_for_script($file) } 'App::Sqitch::X',
        'Should get an error on failure to delete the alias';
    is $@->ident, 'oracle', 'File deletion error ident should be "oracle"';
    is $@->message, __x(
        'Cannot remove {file}: {error}',
        file  => $tmpdir->file('foo_bar.sql'),
        error => $!,
    ), 'File deletion error message should be correct';
}

# Make sure double-quotes are escaped.
WIN32: {
    $file = $tmpdir->file('"foo$bar".sql');
    my $mock_file = Test::MockModule->new(ref $file);
    # Windows doesn't like the quotation marks, so prevent it from writing.
    $mock_file->mock(copy_to => 1) if App::Sqitch::ISWIN;
    is $ora->_file_for_script($file), $tmpdir->file('""foo_bar"".sql'),
        'File with special char and quotes should be aliased';
}

##############################################################################

t/oracle.t  view on Meta::CPAN

##############################################################################
# Test file and handle running.
my @run;
$mock_ora->mock(_run => sub {shift; @run = @_ });
ok $ora->run_file('foo/bar.sql'), 'Run foo/bar.sql';
is_deeply \@run, ['@"foo/bar.sql"'],
    'File should be passed to run()';

ok $ora->run_file('foo/"bar".sql'), 'Run foo/"bar".sql';
is_deeply \@run, ['@"foo/""bar"".sql"'],
    'Double quotes in file passed to run() should be escaped';

ok $ora->run_handle('FH'), 'Spool a "file handle"';
my $handles = shift @spool;
is_deeply \@spool, [$ora->sqlplus],
    'sqlplus command should be passed to spool()';
isa_ok $handles, 'ARRAY', 'Array ove handles should be passed to spool';
$fh = $handles->[0];
is join('', <$fh>), $ora->_script, 'First file handle should be script';
is $handles->[1], 'FH', 'Second should be the passed handle';



( run in 0.310 second using v1.01-cache-2.11-cpan-5467b0d2c73 )