use
5.010;
use
constant
extra_target_keys
=>
qw(target)
;
our
$VERSION
=
'0.9998'
;
has
verbose
=> (
is
=>
'ro'
,
isa
=> Int,
default
=> 0,
);
sub
options {
qw(verbose|v+)
}
sub
_chk_engine($) {
my
$engine
=
shift
;
hurl
engine
=> __x(
'Unknown engine "{engine}"'
,
engine
=>
$engine
)
unless
first {
$engine
eq
$_
} App::Sqitch::Command::ENGINES;
}
sub
configure {
my
(
$class
,
$config
,
$options
) =
@_
;
return
{
verbose
=>
$options
->{verbose} }
if
exists
$options
->{verbose};
return
{};
}
sub
execute {
my
(
$self
,
$action
) = (
shift
,
shift
);
$action
||=
'list'
;
$action
=~ s/-/_/g;
my
$meth
=
$self
->can(
$action
) or
$self
->usage(__x(
'Unknown action "{action}"'
,
action
=>
$action
,
));
return
$self
->
$meth
(
@_
);
}
sub
list {
my
$self
=
shift
;
my
$sqitch
=
$self
->sqitch;
my
$rx
=
join
'|'
=> App::Sqitch::Command::ENGINES;
my
%engines
=
$sqitch
->config->get_regexp(
key
=>
qr/^engine[.](?:$rx)[.]target$/
);
my
$format
=
$self
->verbose ?
"%1\$s\t%2\$s"
:
'%1$s'
;
for
my
$key
(
sort
keys
%engines
) {
my
(
$engine
) =
$key
=~ /engine[.]([^.]+)/;
$sqitch
->emit(
sprintf
$format
,
$engine
,
$engines
{
$key
})
}
return
$self
;
}
sub
_target {
my
(
$self
,
$engine
,
$name
) =
@_
;
my
$target
=
$self
->properties->{target} ||
$name
||
return
;
if
(
$target
=~ /:/) {
my
$uri
= URI::db->new(
$target
,
'db:'
);
hurl
engine
=> __x(
'Cannot assign URI using engine "{new}" to engine "{old}"'
,
new
=>
$uri
->canonical_engine,
old
=>
$engine
,
)
if
$uri
->canonical_engine ne
$engine
;
return
$uri
->as_string;
}
return
$target
if
$self
->sqitch->config->get(
key
=>
"target.$target.uri"
);
hurl
engine
=> __x(
'Unknown target "{target}"'
,
target
=>
$target
);
}
sub
add {
my
(
$self
,
$engine
,
$target
) =
@_
;
$self
->usage
unless
$engine
;
_chk_engine
$engine
;
my
$key
=
"engine.$engine"
;
my
$config
=
$self
->sqitch->config;
hurl
engine
=> __x(
'Engine "{engine}" already exists'
,
engine
=>
$engine
)
if
$config
->get(
key
=>
"$key.target"
);
my
@vars
= ({
key
=>
"$key.target"
,
value
=>
$self
->_target(
$engine
,
$target
) ||
"db:$engine:"
,
});
my
$props
=
$self
->properties;
while
(
my
(
$prop
,
$val
) =
each
%{
$props
} ) {
push
@vars
=> {
key
=>
"$key.$prop"
,
value
=>
$val
,
}
if
$prop
ne
'target'
;
}
$config
->group_set(
$config
->local_file, \
@vars
);
$target
=
$self
->config_target(
name
=>
$target
,
engine
=>
$engine
,
);
$self
->write_plan(
target
=>
$target
);
$self
->make_directories_for(
$target
);
}
sub
alter {
my
(
$self
,
$engine
) =
@_
;
$self
->usage
unless
$engine
;
_chk_engine
$engine
;
my
$key
=
"engine.$engine"
;
my
$config
=
$self
->sqitch->config;
my
$props
=
$self
->properties;
hurl
engine
=> __x(
'Missing Engine "{engine}"; use "{command}" to add it'
,
engine
=>
$engine
,
command
=>
"add $engine "
. (
$props
->{target} ||
"db:$engine:"
),
)
unless
$config
->get(
key
=>
"engine.$engine.target"
);
my
@vars
;
while
(
my
(
$prop
,
$val
) =
each
%{
$props
} ) {
if
(
$prop
eq
'target'
) {
$val
=
$self
->_target(
$engine
,
$val
) or hurl
engine
=> __(
'Cannot unset an engine target'
);
}
push
@vars
=> {
key
=>
"$key.$prop"
,
value
=>
$val
,
};
}
$config
->group_set(
$config
->local_file, \
@vars
);
$self
->make_directories_for(
$self
->config_target(
engine
=>
$engine
) );
}
sub
_set {
my
(
$self
,
$key
,
$engine
,
$value
) =
@_
;
(
my
$action
=
$key
) =~ s/_/-/g;
$self
->usage
unless
$engine
&&
$value
;
(
my
$opt
=
$key
) =~ s/_/-/g;
$self
->sqitch->
warn
(__x(
qq{ The "{old}
" action is deprecated;\n Instead
use
"{new}"
.},
old
=>
"set-$action $engine $value"
,
new
=>
"alter $engine --$opt $value"
,
));
_chk_engine
$engine
;
my
$config
=
$self
->sqitch->config;
hurl
engine
=> __x(
'Unknown engine "{engine}"'
,
engine
=>
$engine
)
unless
$config
->get(
key
=>
"engine.$engine.target"
);
$config
->set(
key
=>
"engine.$engine.$key"
,
value
=>
$value
,
filename
=>
$config
->local_file,
);
return
$self
;
}
my
%normalizer_for
= (
top_dir
=>
sub
{
$_
[0] ? dir(
$_
[0])->cleanup :
undef
},
plan_file
=>
sub
{
$_
[0] ? file(
$_
[0])->cleanup :
undef
},
client
=>
sub
{
$_
[0] },
target
=>
sub
{
my
$target
=
shift
or
return
undef
;
return
URI::db->new(
$target
,
'db:'
)->as_string
if
$target
=~ /:/;
my
$config
=
shift
;
return
$target
if
$config
->get(
key
=>
"target.$target.uri"
);
hurl
engine
=> __x(
'Unknown target "{target}"'
,
target
=>
$target
);
},
);
$normalizer_for
{
"$_\_dir"
} =
$normalizer_for
{
"reworked_$_\_dir"
} =
$normalizer_for
{top_dir}
for
qw(deploy revert verify)
;
$normalizer_for
{reworked_dir} =
$normalizer_for
{top_dir};
$normalizer_for
{
$_
} =
$normalizer_for
{client}
for
qw(registry extension)
;
sub
set_target {
my
(
$self
,
$engine
,
$target
) =
@_
;
$self
->_set(
'target'
,
$engine
,
$normalizer_for
{target}->(
$target
,
$self
->sqitch->config,
) );
}
sub
set_registry {
shift
->_set(
'registry'
,
@_
) }
sub
set_client {
shift
->_set(
'client'
,
@_
) }
sub
set_extension {
shift
->_set(
'extension'
,
@_
) }
sub
_set_dir {
my
(
$self
,
$key
,
$engine
,
$dir
) =
@_
;
$self
->_set(
$key
,
$engine
,
$normalizer_for
{top_dir}->(
$dir
) );
}
sub
set_top_dir {
shift
->_set_dir(
'top_dir'
,
@_
) }
sub
set_deploy_dir {
shift
->_set_dir(
'deploy_dir'
,
@_
) }
sub
set_revert_dir {
shift
->_set_dir(
'revert_dir'
,
@_
) }
sub
set_verify_dir {
shift
->_set_dir(
'verify_dir'
,
@_
) }
sub
set_plan_file {
my
(
$self
,
$engine
,
$file
) =
@_
;
$self
->_set(
'plan_file'
,
$engine
,
$normalizer_for
{plan_file}->(
$file
) );
}
sub
rm {
shift
->remove(
@_
) }
sub
remove {
my
(
$self
,
$engine
) =
@_
;
$self
->usage
unless
$engine
;
my
$config
=
$self
->sqitch->config;
try
{
$config
->rename_section(
from
=>
"engine.$engine"
,
filename
=>
$config
->local_file,
);
}
catch
{
die
$_
unless
/No such section/;
hurl
engine
=> __x(
'Unknown engine "{engine}"'
,
engine
=>
$engine
,
);
};
return
$self
;
}
sub
show {
my
(
$self
,
@names
) =
@_
;
return
$self
->list
unless
@names
;
my
$sqitch
=
$self
->sqitch;
my
$config
=
$sqitch
->config;
my
%label_for
= (
target
=> __
'Target'
,
registry
=> __
'Registry'
,
client
=> __
'Client'
,
top_dir
=> __
'Top Directory'
,
plan_file
=> __
'Plan File'
,
extension
=> __
'Extension'
,
revert
=>
' '
. __
'Revert'
,
deploy
=>
' '
. __
'Deploy'
,
verify
=>
' '
. __
'Verify'
,
reworked
=>
' '
. __
'Reworked'
,
);
my
$len
= max
map
{
length
}
values
%label_for
;
$_
.=
': '
.
' '
x (
$len
-
length
$_
)
for
values
%label_for
;
$label_for
{script_dirs} = __(
'Script Directories'
) .
':'
;
$label_for
{reworked_dirs} = __(
'Reworked Script Directories'
) .
':'
;
for
my
$engine
(
@names
) {
my
$target
= App::Sqitch::Target->new(
sqitch
=>
$sqitch
,
name
=>
$config
->get(
key
=>
"engine.$engine.target"
) ||
"db:$engine"
,
);
$self
->emit(
"* $engine"
);
$self
->emit(
' '
,
$label_for
{target},
$target
->target);
$self
->emit(
' '
,
$label_for
{registry},
$target
->registry);
$self
->emit(
' '
,
$label_for
{client},
$target
->client);
$self
->emit(
' '
,
$label_for
{top_dir},
$target
->top_dir);
$self
->emit(
' '
,
$label_for
{plan_file},
$target
->plan_file);
$self
->emit(
' '
,
$label_for
{extension},
$target
->extension);
$self
->emit(
' '
,
$label_for
{script_dirs});
$self
->emit(
' '
,
$label_for
{deploy},
$target
->deploy_dir);
$self
->emit(
' '
,
$label_for
{revert},
$target
->revert_dir);
$self
->emit(
' '
,
$label_for
{verify},
$target
->verify_dir);
$self
->emit(
' '
,
$label_for
{reworked_dirs});
$self
->emit(
' '
,
$label_for
{reworked},
$target
->reworked_dir);
$self
->emit(
' '
,
$label_for
{deploy},
$target
->reworked_deploy_dir);
$self
->emit(
' '
,
$label_for
{revert},
$target
->reworked_revert_dir);
$self
->emit(
' '
,
$label_for
{verify},
$target
->reworked_verify_dir);
}
return
$self
;
}
sub
update_config {
my
$self
=
shift
;
my
$sqitch
=
$self
->sqitch;
my
$config
=
$sqitch
->config;
my
$local_file
=
$config
->local_file;
for
my
$file
(
$local_file
,
$config
->user_file,
$config
->system_file,
) {
$sqitch
->emit(__x(
'Loading {file}'
,
file
=>
$file
));
local
$ENV
{SQITCH_CONFIG} =
'/dev/null/not.conf'
;
local
$ENV
{SQITCH_USER_CONFIG} =
'/dev/null/not.user'
;
local
$ENV
{SQITCH_SYSTEM_CONFIG} =
'/dev/null/not.sys'
;
my
$c
= App::Sqitch::Config->new;
$c
->load_file(
$file
);
my
%engines
;
for
my
$ekey
(App::Sqitch::Command::ENGINES) {
my
$sect
=
$c
->get_section(
section
=>
"core.$ekey"
);
if
(%{
$sect
}) {
if
(%{
$c
->get_section(
section
=>
"engine.$ekey"
) }) {
$sqitch
->
warn
(
' - '
. __x(
"Deprecated {section} found in {file}; to remove it, run\n {sqitch} config --file {file} --remove-section {section}"
,
section
=>
"core.$ekey"
,
file
=>
$file
,
sqitch
=> $0,
));
next
;
}
$engines
{
$ekey
} =
$sect
;
}
}
unless
(
%engines
) {
$sqitch
->emit(__
' - No engines to update'
);
next
;
}
unless
(-w
$file
) {
$sqitch
->
warn
(
' - '
. __x(
'Cannot update {file}. Please make it writable'
,
file
=>
$file
,
));
next
;
}
for
my
$ekey
(
sort
keys
%engines
) {
my
$old
=
$engines
{
$ekey
};
my
@new
;
if
(
my
$target
=
delete
$old
->{target} ) {
push
@new
=> {
key
=>
"engine.$ekey.target"
,
value
=>
$target
,
};
delete
$old
->{
$_
}
for
qw(host port username password db_name)
;
}
elsif
(
$file
eq
$local_file
) {
my
$uri
= URI::db->new(
"db:$ekey:"
);
for
my
$spec
(
[
host
=>
'host'
],
[
port
=>
'port'
],
[
username
=>
'user'
],
[
password
=>
'password'
],
[
db_name
=>
'dbname'
],
) {
my
(
$key
,
$meth
) = @{
$spec
};
my
$val
=
delete
$old
->{
$key
} or
next
;
$uri
->
$meth
(
$val
);
}
push
@new
=> {
key
=>
"engine.$ekey.target"
,
value
=>
$uri
->as_string,
};
}
else
{
delete
$old
->{
$_
}
for
qw(host port username password db_name)
;
}
push
@new
=>
map
{{
key
=>
"engine.$ekey.$_"
,
value
=>
$old
->{
$_
},
}}
keys
%{
$old
};
$config
->group_set(
$file
, \
@new
);
$sqitch
->emit(
' - '
. __x(
"Migrated {old} to {new}; To remove {old}, run\n {sqitch} config --file {file} --remove-section {old}"
,
old
=>
"core.$ekey"
,
new
=>
"engine.$ekey"
,
sqitch
=> $0,
file
=>
$file
,
));
}
}
return
$self
;
}
1;