App-JESP
view release on metacpan
or search on metacpan
LICENSE
view on Meta::CPAN
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 | requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
|
README.md
view on Meta::CPAN
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | jesp
Or use from your own program (in Perl): my $jesp = App::JESP->new({
interactive => 0,
home => 'path/to/jesphome' ,
dsn => ...,
username => ...,
password => ...
});
$jesp ->install();
$jesp ->deploy();
All JESP configuration must live in a JESP home directory.
This home directory must contain a plan.json file, containing the patching
|
lib/App/JESP.pm
view on Meta::CPAN
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | has 'dsn' => ( is => 'ro' , isa => 'Str' , required => 1 );
has 'username' => ( is => 'ro' , isa => 'Maybe[Str]' , required => 1);
has 'password' => ( is => 'ro' , isa => 'Maybe[Str]' , required => 1);
has 'home' => ( is => 'ro' , isa => 'Str' , required => 1 );
has 'prefix' => ( is => 'ro' , isa => 'Str' , default => 'jesp_' );
has 'driver_class' => ( is => 'ro' , isa => 'Str' , lazy_build => 1);
has 'get_dbh' => ( is => 'ro' , isa => 'CodeRef' , default => sub {
my ( $self ) = @_ ;
return sub {
return DBI-> connect ( $self ->dsn(), $self ->username(), $self ->password(),
{ RaiseError => 1,
PrintError => 0,
AutoCommit => 1,
});
};
});
has 'dbix_simple' => ( is => 'ro' , isa => 'DBIx::Simple' , lazy_build => 1);
has 'patches_table_name' => ( is => 'ro' , isa => 'Str' , lazy_build => 1);
has 'meta_patches' => ( is => 'ro' , isa => 'ArrayRef[HashRef]' ,
|
lib/App/JESP.pm
view on Meta::CPAN
302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | jesp
Or use from your own program (in Perl): my $jesp = App::JESP->new({
interactive => 0,
home => 'path/to/jesphome' ,
dsn => ...,
username => ...,
password => ...
});
$jesp ->install();
$jesp ->deploy();
|
lib/App/JESP/Cmd/CommandJESP.pm
view on Meta::CPAN
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | . "\nExamples:\n"
. "\n dbi:mysql:database=testdb;host=localhost;port=3306"
. "\n dbi:SQLite:dbname=demo/test.db"
. "\n dbi:Pg:dbname=testdb;host=localhost;port=5432"
. "\n"
],
[ 'username=s' =>
"The username to connect to the DB" , { default => undef } ],
[ 'password=s' =>
"The password to connect to the DB" , { default => undef } ],
[ 'prefix=s' =>
"The prefix for all jesp metatables. Defaults to 'jesp_'" ],
$class ->options( $app ),
)
}
|
lib/App/JESP/Cmd/CommandJESP.pm
view on Meta::CPAN
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 | my ( $self , $opts , $args ) = @_ ;
unless ( $opts ->dsn() ){ die "Missing 'dsn' option. Run with -h\n" ; }
unless ( $opts ->home() ){ die "Missing 'home' option. Run with -h\n" ; }
$log ->debug( "Building App::JESP instance" );
my $jesp = App::JESP->new({
dsn => $opts ->dsn(),
home => $opts ->home(),
( $opts ->username() ? ( username => $opts ->username() ) : ( username => undef ) ),
( $opts ->password() ? ( password => $opts ->password() ) : ( password => undef ) ),
});
$log ->debug( "App::JESP instance built" );
$self ->{__jesp} = $jesp ;
$self ->validate( $opts , $args );
}
|
lib/App/JESP/Driver.pm
view on Meta::CPAN
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 | my @stderr ;
my $on_stderr = sub {
$log -> warn ( @_ );
push @stderr , @_ ;
};
my $properties = {};
my ( $scheme , $driver , $attr_string , $attr_hash , $driver_dsn ) = DBI->parse_dsn( $self ->jesp()->dsn() );
ref ( $self )->_OdbcParse( $driver_dsn , $properties , [] );
$properties ->{user} ||= $self ->jesp()->username();
$properties ->{password} ||= $self ->jesp()->password();
$properties = {
%$properties ,
%{ defined ( $attr_hash ) ? $attr_hash : {} },
dsn => $self ->jesp()->dsn(),
scheme => $scheme ,
driver => $driver ,
driver_dsn => $driver_dsn ,
attr_string => $attr_string ,
};
my %EXTRA_ENV = ();
|
lib/App/JESP/Driver/mysql.pm
view on Meta::CPAN
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 | my @cmd = ( $mysql );
my $properties = {};
{
eval "require DBD::mysql" or die "Please install DBD::mysql for this to work\n" ;
my ( $scheme , $driver , $attr_string , $attr_hash , $driver_dsn ) = DBI->parse_dsn( $self ->jesp()->dsn() );
DBD::mysql->_OdbcParse( $driver_dsn , $properties , [] );
$properties ->{user} ||= $self ->jesp()->username();
$properties ->{password} ||= $self ->jesp()->password();
$log ->trace( 'mysql properties: ' .Dumper( $properties ));
}
push @cmd , '-B' ;
if ( my $user = $properties ->{user} ){
push @cmd , ( '-u' , String::ShellQuote::shell_quote( $user ));
}
if ( my $database = $properties ->{database} ){
push @cmd , ( '-D' , String::ShellQuote::shell_quote( $database ));
}
if ( my $host = $properties ->{host} ){
push @cmd , ( '-h' , String::ShellQuote::shell_quote( $host ));
}
if ( my $port = $properties ->{port} ){
push @cmd , ( '-P' , String::ShellQuote::shell_quote( $port ));
}
if ( my $mysql_socket = $properties ->{mysql_socket} ){
push @cmd , ( '-S' , String::ShellQuote::shell_quote( $mysql_socket ));
}
if ( my $password = $properties ->{password} ){
push @cmd , ( '-p' .String::ShellQuote::shell_quote( $password ));
}
my $on_stdout = sub {
$log ->info( @_ );
};
my @stderr ;
my $on_stderr = sub {
$log -> warn ( @_ );
push @stderr , @_ ;
|
t/build.t
view on Meta::CPAN
1 2 3 4 5 6 7 8 9 10 11 12 13 | #! perl -w
ok( my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' , username => undef , password => undef , home => 'bla' }) );
ok( ! $jesp ->interactive(), "Ok interactive is false" );
is( $jesp ->prefix() , 'jesp_' );
ok( $jesp ->dbix_simple(), "Ok can get DBIx::Simple DB" );
done_testing();
|
t/colors.t
view on Meta::CPAN
1 2 3 4 5 6 7 8 9 10 11 12 | #! perl -w
ok( my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' , username => undef , password => undef , home => 'bla' , interactive => 1 }) );
is( $jesp ->colorizer()->colored( "Foo" , "blue" ) , Term::ANSIColor::colored( "Foo" , "blue" ) );
done_testing();
|
t/deploy.t
view on Meta::CPAN
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' ,
username => undef ,
password => undef ,
home => './t/home/'
});
throws_ok( sub { $jesp ->deploy() } , qr/ERROR querying meta/ );
$jesp ->install();
my $status = $jesp ->status();
is( scalar ( @{ $status ->{plan_patches}} ) , 4, "Ok 4 patches in plan" );
is( $jesp ->deploy(), 4, "Ok applied 4 patches" );
|
t/deploy_mysql.t
view on Meta::CPAN
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | my @mysqls = ( $mysqld );
if ( $ENV {EXTENDED_TESTING} ){
push @mysqls , Test::mysqld->new( my_cnf => { port => Net::EmptyPort::empty_port() } );
}
foreach my $mysql ( @mysqls ){
my $jesp = App::JESP->new({ dsn => $mysql ->dsn(),
password => '' ,
username => '' ,
home => './t/home_mysql/'
});
throws_ok( sub { $jesp ->deploy() } , qr/ERROR querying meta/ );
$jesp ->install();
is( $jesp ->deploy(), 2, "Ok applied 2 patches" );
is( $jesp ->deploy(), 0, "Ok applied 0 patches on the second call" );
|
t/deploy_mysqlpasswd.t
view on Meta::CPAN
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | my $dbh = DBI-> connect ( $mysql ->dsn() , '' , '' , { RaiseError => 1, AutoCommit => 1 });
$dbh -> do ( 'CREATE DATABASE grotest' );
$dbh -> do ( 'GRANT ALL ON grotest.* TO \'salengro\'@\'localhost\' IDENTIFIED BY \'mufflin!\'' );
my $dsn = $mysql ->dsn();
$dsn =~ s/dbname=test/dbname=grotest/;
$dsn =~ s/;user=root//;
my $jesp = App::JESP->new({ dsn => $dsn ,
password => 'mufflin!' ,
username => 'salengro' ,
home => './t/home_mysql/'
});
$jesp ->install();
is( $jesp ->deploy(), 2, "Ok applied 2 patches" );
is( $jesp ->deploy(), 0, "Ok applied 0 patches on the second call" );
done_testing();
|
t/deploy_pgsql.t
view on Meta::CPAN
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | plan skip_all => "Test::PostgreSQL is required for this test" if $@;
eval "use Net::EmptyPort" ;
plan skip_all => "Net::EmptyPort is required for this test" if $@;
}
my $pgsql = eval { Test::PostgreSQL->new({ port => Net::EmptyPort::empty_port() }) } or plan skip_all => $@. ' - ' . $Test::PostgreSQL::errstr ;
my $jesp = App::JESP->new({ dsn => $pgsql ->dsn(),
password => '' ,
username => 'postgres' ,
home => './t/home_pgsql/'
});
throws_ok( sub { $jesp ->deploy() } , qr/ERROR querying meta/ );
$jesp ->install();
is( $jesp ->deploy(), 2, "Ok applied 2 patches" );
is( $jesp ->deploy(), 0, "Ok applied 0 patches on the second call" );
|
t/deploy_script.t
view on Meta::CPAN
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | plan skip_all => 'No sqlite3 found' ;
}
delete $ENV {PATH};
$ENV {WHICH_SQLITE3} = $which_sqlite3 ;
my ( $fh , $dbname ) = File::Temp::tempfile( EXLOCK => 0 );
my $jesp = App::JESP->new({ dsn => "dbi:SQLite:dbname=$dbname" ,
username => undef ,
password => undef ,
home => './t/homescripts/'
});
$jesp ->install();
is( $jesp ->deploy(), 3, "Ok applied 3 patches" );
unlink $dbname ;
done_testing();
|
t/home_mysql/patches/sakila1.sql
view on Meta::CPAN
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 | CREATE TABLE staff (
staff_id TINYINT UNSIGNED NOT NULL AUTO_INCREMENT,
first_name VARCHAR(45) NOT NULL,
last_name VARCHAR(45) NOT NULL,
address_id SMALLINT UNSIGNED NOT NULL,
picture BLOB DEFAULT NULL,
email VARCHAR(50) DEFAULT NULL,
store_id TINYINT UNSIGNED NOT NULL,
active BOOLEAN NOT NULL DEFAULT TRUE,
username VARCHAR(16) NOT NULL,
password VARCHAR(40) BINARY DEFAULT NULL,
last_update TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (staff_id),
KEY idx_fk_store_id (store_id),
KEY idx_fk_address_id (address_id),
CONSTRAINT fk_staff_store FOREIGN KEY (store_id) REFERENCES store (store_id) ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT fk_staff_address FOREIGN KEY (address_id) REFERENCES address (address_id) ON DELETE RESTRICT ON UPDATE CASCADE
)ENGINE=InnoDB DEFAULT CHARSET=utf8;
--
-- Table structure for table `store`
|
t/home_pgsql/patches/pagila1.sql
view on Meta::CPAN
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 | CREATE TABLE staff (
staff_id integer DEFAULT nextval( 'staff_staff_id_seq' ::regclass) NOT NULL,
first_name character varying(45) NOT NULL,
last_name character varying(45) NOT NULL,
address_id smallint NOT NULL,
email character varying(50),
store_id smallint NOT NULL,
active boolean DEFAULT true NOT NULL,
username character varying(16) NOT NULL,
password character varying(40),
last_update timestamp without time zone DEFAULT now() NOT NULL,
picture bytea
);
ALTER TABLE public.staff OWNER TO postgres;
--
-- Name: store_store_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
|
t/install.t
view on Meta::CPAN
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #! perl -w
ok( my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' , username => undef , password => undef , home => 'bla' }) );
ok( $jesp ->install(), "Ok can install JESP in the given Database" );
my @installed_patches = $jesp ->dbix_simple()-> select ( $jesp ->patches_table_name() )->hashes();
is( scalar ( @installed_patches ) , 1 );
is( $installed_patches [0]->{id} , $jesp ->prefix(). 'meta_zero' , "Good zero name" );
ok( exists ( $installed_patches [0]->{applied_datetime} ) , "There is an applied time" );
push @{ $jesp ->meta_patches()},
|
t/install_dbs.t
view on Meta::CPAN
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | }
my @connection_params = ({ dsn => 'dbi:SQLite:dbname=:memory:' ,
username => undef ,
password => undef
});
my $mysql = Test::mysqld->new( my_cnf => {
'skip-networking' => '1' ,
socket => File::Spec->catfile( File::Spec->tmpdir() , 'socket-' .$$. '-testmysqld' )
});
if ( $mysql ){
push @connection_params , { dsn => $mysql ->dsn(),
password => '' ,
username => ''
};
} else {
diag( "Warning: could not build Test::mysqld " . $Test::mysqld::errstr );
}
my $pgsql = eval { Test::PostgreSQL->new(); };
if ( $pgsql ){
push @connection_params , { dsn => $pgsql ->dsn(),
password => undef ,
username => 'postgres'
};
} else {
diag( "Warning: could not build Test::PostgreSQL: " .$@. ' - ' . $Test::PostgreSQL::errstr );
}
foreach my $connect_params ( @connection_params ){
ok( my $jesp = App::JESP->new({ dsn => $connect_params ->{dsn},
username => $connect_params ->{username},
password => $connect_params ->{postgres},
home => 'bla'
}) );
ok( $jesp ->install(), "Ok can install JESP in the given Database" );
my @installed_patches = $jesp ->dbix_simple()-> select ( $jesp ->patches_table_name() )->hashes();
is( scalar ( @installed_patches ) , 1 );
is( $installed_patches [0]->{id} , $jesp ->prefix(). 'meta_zero' , "Good zero name" );
ok( exists ( $installed_patches [0]->{applied_datetime} ) , "There is an applied time" );
}
ok(1);
|
t/plan.t
view on Meta::CPAN
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | {
my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' ,
username => undef ,
password => undef ,
home => 'bla'
});
throws_ok( sub { my $plan = $jesp ->plan() } , qr/does not exists/ );
}
{
my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' ,
username => undef ,
password => undef ,
home => './t/home/'
});
ok( my $plan = $jesp ->plan() );
ok( my $patches = $plan ->patches() );
is( scalar ( @{ $patches } ) , 4 , "4 test patches" );
foreach my $patch ( @{ $patches } ){
ok( $patch ->sql() , "Ok got SQL" );
}
}
|
t/plan_script.t
view on Meta::CPAN
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | if ( $^O =~ /Win/ ){
plan skip_all => 'No script test on windows please' ;
}
{
my $jesp = App::JESP->new({ dsn => 'dbi:SQLite:dbname=:memory:' ,
username => undef ,
password => undef ,
home => './t/homescripts/'
});
ok( my $plan = $jesp ->plan() );
ok( my $patches = $plan ->patches() );
is( scalar ( @{ $patches } ) , 3 , "3 test patches" );
ok( ! $patches ->[2]->sql() , "No sql in patch 5" );
ok( $patches ->[2]->script_file(), "Patch 3 is a script" );
}
|