use
Carp
qw(croak cluck)
;
our
@ISA
=
qw(Exporter)
;
our
@EXPORT_OK
=
qw(
add_bugtracker
add_repository
changes
changes_bump
changes_date
ci_badges
ci_github
config
config_file
copyright_info
copyright_bump
cpan_upload
git_add
git_commit
git_clone
git_pull
git_push
git_ignore
git_release
git_repo
git_status_differs
git_tag
init
make_dist
make_distclean
make_manifest
make_test
manifest_skip
manifest_t
move_distribution_files
remove_unwanted_files
version_bump
version_incr
version_info
)
;
our
@EXPORT_PRIVATE
=
qw(
_dist_dir_re
_validate_git
)
;
our
%EXPORT_TAGS
= (
all
=> [
@EXPORT_OK
],
private
=> _export_private(),
);
our
$VERSION
=
'1.13'
;
CONFIG_FILE
=>
'dist-mgr.json'
,
GITHUB_CI_FILE
=>
'github_ci_default.yml'
,
GITHUB_CI_PATH
=>
'.github/workflows/'
,
CHANGES_FILE
=>
'Changes'
,
CHANGES_ORIG_SHA
=>
'97624d56464d7254ef5577e4a0c8a098d6c6d9e6'
,
FSTYPE_IS_DIR
=> 1,
FSTYPE_IS_FILE
=> 2,
DEFAULT_DIR
=>
'lib/'
,
DEFAULT_POD_DIR
=>
'.'
,
MAKE
=> $^O =~ /win32/i ?
'gmake'
:
'make'
,
};
sub
add_bugtracker {
my
(
$author
,
$repo
,
$makefile
) =
@_
;
if
(!
defined
$author
|| !
defined
$repo
) {
croak(
"Usage: add_bugtracker(\$author, \$repository_name)\n"
);
}
$makefile
//=
'Makefile.PL'
;
_makefile_insert_bugtracker(
$author
,
$repo
,
$makefile
);
}
sub
add_repository {
my
(
$author
,
$repo
,
$makefile
) =
@_
;
if
(!
defined
$author
|| !
defined
$repo
) {
croak(
"Usage: add_repository(\$author, \$repository_name)\n"
);
}
$makefile
//=
'Makefile.PL'
;
_makefile_insert_repository(
$author
,
$repo
,
$makefile
);
}
sub
changes {
my
(
$module
,
$file
) =
@_
;
croak(
"changes() needs a module parameter"
)
if
!
defined
$module
;
$file
//=
'Changes'
;
my
@contents
;
my
$changes_date_count
= 0;
if
(-e
$file
) {
my
(
$contents
,
$tie
) = _changes_tie(
$file
);
$changes_date_count
=
grep
/\d{4}-\d{2}-\d{2}/,
$contents
;
untie
$tie
;
}
if
(! -e
$file
|| !
$changes_date_count
) {
my
@contents
= _changes_file(
$module
);
_changes_write_file(
$file
, \
@contents
);
}
return
@contents
;
}
sub
changes_bump {
my
(
$version
,
$file
) =
@_
;
croak(
"changes_bump() requires a version sent in"
)
if
!
defined
$version
;
_validate_version(
$version
);
$file
//=
'Changes'
;
my
(
$contents
,
$tie
) = _changes_tie(
$file
);
for
(0..
$#$contents
) {
if
(
$contents
->[
$_
] =~ /^\d+\.\d+\s+/) {
$contents
->[
$_
-1] =
"\n$version UNREL\n -\n\n"
;
last
;
}
}
untie
$tie
;
}
sub
changes_date {
my
(
$file
) =
@_
;
$file
//=
'Changes'
;
my
(
$contents
,
$tie
) = _changes_tie(
$file
);
my
(
$d
,
$m
,
$y
) = (
localtime
)[3, 4, 5];
$y
+= 1900;
$m
+= 1;
$m
=
"0$m"
if
length
$m
== 1;
$d
=
"0$d"
if
length
$d
== 1;
for
(0..
$#$contents
) {
if
(
$contents
->[
$_
] =~ /^(.*)\s+UNREL/) {
$contents
->[
$_
] =
"$1 $y-$m-$d"
;
last
;
}
}
untie
$tie
;
}
sub
ci_badges {
if
(
scalar
@_
< 2) {
croak(
"ci_badges() needs \$author and \$repo sent in"
);
}
my
(
$author
,
$repo
,
$fs_entry
) =
@_
;
$fs_entry
//= DEFAULT_DIR;
my
$exit
= 0;
for
(_module_find_files(
$fs_entry
)) {
$exit
= -1
if
_module_insert_ci_badges(
$author
,
$repo
,
$_
) == -1;
}
return
$exit
;
}
sub
ci_github {
my
(
$os
) =
@_
;
if
(
defined
$os
&&
ref
$os
ne
'ARRAY'
) {
croak(
"\$os parameter to ci_github() must be an array ref"
);
}
if
(-e
'MANIFEST.SKIP'
) {
open
my
$fh
,
'<'
,
'MANIFEST.SKIP'
or croak(
"Can't open MANIFEST.SKIP for reading"
);
my
@makefile_skip_contents
= <
$fh
>;
if
(
grep
!m|\.github$|,
@makefile_skip_contents
) {
close
$fh
;
open
my
$wfh
,
'>>'
,
'MANIFEST.SKIP'
or croak(
"Can't open MANIFEST.SKIP for writing"
);
print
$wfh
'^\.github/'
;
}
}
else
{
open
my
$wfh
,
'>>'
,
'MANIFEST.SKIP'
or croak(
"Can't open MANIFEST.SKIP for writing"
);
print
$wfh
'^\.github/'
;
}
my
@contents
= _ci_github_file(
$os
);
_ci_github_write_file(\
@contents
);
return
@contents
;
}
sub
config {
my
(
$args
,
$file
) =
@_
;
if
(!
defined
$args
) {
croak(
"config() requires \$args hash reference parameter"
);
}
elsif
(
ref
$args
ne
'HASH'
) {
croak(
"\$args parameter must be a hash reference."
);
}
$file
= config_file()
if
!
defined
$file
;
my
$conf
;
if
(-e
$file
&& -f
$file
) {
{
local
$/;
open
my
$fh
,
'<'
,
$file
or croak
"Can't open config file $file: $!"
;
my
$json
= <
$fh
>;
$conf
= decode_json
$json
;
for
(
keys
%{
$conf
}) {
delete
$conf
->{
$_
}
if
$conf
->{
$_
} eq
''
;
}
}
}
else
{
_config_file_write(
$file
, _config_file());
print
"\nGenerated new configuration file: $file\n"
;
}
%{
$args
} = (%{
$args
}, %{
$conf
})
if
$conf
;
return
$args
;
}
sub
config_file {
my
$file
= $^O =~ /win32/i
?
"$ENV{USERPROFILE}/${\CONFIG_FILE}"
:
"$ENV{HOME}/${\CONFIG_FILE}"
;
return
$file
;
}
sub
copyright_bump {
my
(
$fs_entry
) =
@_
;
$fs_entry
//= DEFAULT_POD_DIR;
_validate_fs_entry(
$fs_entry
);
my
(
$year
) = (
localtime
)[5];
$year
+= 1900;
my
@pod_files
= _pod_find_files(
$fs_entry
);
my
%info
;
for
my
$pod_file
(
@pod_files
) {
my
(
$contents
,
$tie
) = _pod_tie(
$pod_file
);
for
(0 ..
$#$contents
) {
if
(
$contents
->[
$_
] =~ /^(Copyright\s+)\d{4}(\s+.*)/) {
$contents
->[
$_
] =
"$1$year$2"
;
$info
{
$pod_file
} =
$year
;
last
;
}
}
untie
$tie
;
}
return
\
%info
;
}
sub
copyright_info {
my
(
$fs_entry
) =
@_
;
$fs_entry
//= DEFAULT_POD_DIR;
_validate_fs_entry(
$fs_entry
);
my
@pod_files
= _pod_find_files(
$fs_entry
);
my
%copyright_info
;
for
my
$file
(
@pod_files
) {
my
$copyright
= _pod_extract_file_copyright(
$file
);
next
if
!
defined
$copyright
||
$copyright
!~ /^\d{4}$/;
$copyright_info
{
$file
} =
$copyright
if
defined
$copyright
;
}
return
\
%copyright_info
;
}
sub
cpan_upload {
my
(
$dist_file_name
,
%args
) =
@_
;
config(\
%args
);
if
(!
defined
$dist_file_name
) {
croak(
"cpan_upload() requires the name of a distribution file sent in"
);
}
if
(! -f
$dist_file_name
) {
croak(
"File name sent to cpan_upload() isn't a valid file"
);
}
$args
{user} //=
$args
{cpan_id};
$args
{password} //=
$args
{cpan_pw};
$args
{user} =
$ENV
{CPAN_USERNAME}
if
!
$args
{user};
$args
{password} =
$ENV
{CPAN_PASSWORD}
if
!
$args
{password};
if
(!
$args
{user} || !
$args
{password}) {
croak(
"\ncpan_upload() requires --cpan_id and --cpan_pw"
);
}
if
(
$args
{dry_run}) {
print
"\nCPAN upload is in dry run mode... nothing will be uploaded\n"
;
}
CPAN::Uploader->upload_file(
$dist_file_name
,
\
%args
);
print
"\nSuccessfully uploaded $dist_file_name to the CPAN\n"
;
return
%args
;
}
sub
git_add {
_git_add();
}
sub
git_ignore {
my
(
$dir
) =
@_
;
$dir
//=
'.'
;
my
@content
= _git_ignore_file();
_git_ignore_write_file(
$dir
, \
@content
);
return
@content
;
}
sub
git_commit {
_git_commit(
@_
);
}
sub
git_clone {
_git_clone(
@_
);
}
sub
git_push {
_git_push(
@_
);
}
sub
git_pull {
_git_pull(
@_
);
}
sub
git_release {
_git_release(
@_
);
}
sub
git_repo {
_git_repo();
}
sub
git_status_differs {
_git_status_differs(
@_
);
}
sub
git_tag {
_git_tag(
@_
);
}
sub
init {
my
(
%args
) =
@_
;
config(\
%args
);
my
$cwd
= getcwd();
if
(
$cwd
=~ _dist_dir_re()) {
croak
"Can't run init() while in the '$cwd' directory"
;
}
$args
{license} =
'artistic2'
if
!
exists
$args
{license};
$args
{builder} =
'ExtUtils::MakeMaker'
;
for
(
qw(modules author email)
) {
if
(!
exists
$args
{
$_
}) {
croak(
"init() requires '$_' in the parameter hash"
);
}
}
if
(
ref
$args
{modules} ne
'ARRAY'
) {
croak(
"init()'s 'modules' parameter must be an array reference"
);
}
if
(
$args
{verbose}) {
delete
$args
{verbose};
Module::Starter->create_distro(
%args
);
}
else
{
capture_merged {
Module::Starter->create_distro(
%args
);
};
}
my
(
$module
) = (@{
$args
{modules} })[0];
my
$module_file
=
$module
;
$module_file
=~ s/::/\//g;
$module_file
=
"lib/$module_file.pm"
;
my
$module_dir
=
$module
;
$module_dir
=~ s/::/-/g;
chdir
$module_dir
or croak(
"Can't change into directory '$module_dir'"
);
unlink
$module_file
or croak(
"Can't delete the Module::Starter module '$module_file': $!"
);
_module_write_template(
$module_file
,
$module
,
$args
{author},
$args
{email});
chdir
'..'
or croak
"Can't change into original directory"
;
}
sub
manifest_skip {
my
(
$dir
) =
@_
;
$dir
//=
'.'
;
my
@content
= _manifest_skip_file();
_manifest_skip_write_file(
$dir
, \
@content
);
return
@content
;
}
sub
manifest_t {
my
(
$dir
) =
@_
;
$dir
//=
'./t'
;
my
@content
= _manifest_t_file();
_manifest_t_write_file(
$dir
, \
@content
);
return
@content
;
}
sub
move_distribution_files {
my
(
$module
) =
@_
;
if
(!
defined
$module
) {
croak(
"_move_distribution_files() requires a module name sent in"
);
}
my
$module_dir
=
$module
;
$module_dir
=~ s/::/-/g;
my
@move_count
= rmove_glob(
"$module_dir/*"
,
'.'
)
or croak(
"Can't move files from the '$module_dir' directory: $!"
);
my
$dist_count
= _default_distribution_file_count();
for
my
$outer_idx
(0..
$#move_count
) {
my
$outer
=
$move_count
[
$outer_idx
];
for
my
$inner_idx
(0..
$#$outer
) {
my
$inner
=
$move_count
[
$outer_idx
][
$inner_idx
];
for
(0..
$#$inner
) {
if
(
$inner
->[
$_
] !=
$dist_count
->[
$outer_idx
][
$inner_idx
][
$_
]) {
croak(
"Results from the move are mismatched... bailing out"
);
}
}
}
}
rmtree
$module_dir
or croak(
"Couldn't remove the '$module_dir' directory"
);
return
0;
}
sub
remove_unwanted_files {
for
(_unwanted_filesystem_entries()) {
rmtree
$_
;
}
make_manifest();
return
0;
}
sub
make_dist {
my
(
$verbose
) =
@_
;
my
$cmd
=
"${\MAKE} dist"
;
$verbose
? `
$cmd
` : capture_merged {`
$cmd
`};
if
($? != 0) {
croak(
"Exit code $? returned... '${\MAKE} dist' failed"
);
}
return
$?;
}
sub
make_distclean {
my
(
$verbose
) =
@_
;
my
$cmd
=
"${\MAKE} distclean"
;
$verbose
?
print
`
$cmd
` : capture_merged {`
$cmd
`};
if
($? != 0) {
croak(
"Exit code $? returned... '${\MAKE} distclean' failed\n"
);
}
return
$?;
}
sub
make_manifest {
my
(
$verbose
) =
@_
;
if
(
$verbose
) {
if
(-f
'MANIFEST'
) {
unlink
'MANIFEST'
or
die
"make_manifest() Couldn't remove MANIFEST\n"
;
}
print
`$^X Makefile.PL`;
print
`${\MAKE} manifest`;
make_distclean(
$verbose
);
}
else
{
capture_merged {
if
(-f
'MANIFEST'
) {
unlink
'MANIFEST'
or
die
"make_manifest() Couldn't remove MANIFEST\n"
;
}
`$^X Makefile.PL`;
`${\MAKE} manifest`;
make_distclean(
$verbose
);
};
}
if
($? != 0) {
croak(
"Exit code $? returned... '${\MAKE} manifest' failed\n"
);
}
return
$?;
}
sub
make_test {
my
(
$verbose
) =
@_
;
if
(
$verbose
) {
print
`$^X Makefile.PL`;
print
`${\MAKE} test`;
}
capture_merged {
`$^X Makefile.PL`;
`${\MAKE} test`;
};
if
($? != 0) {
croak(
"Exit code $? returned... '${\MAKE} test' failed\n"
);
}
return
$?;
}
sub
version_bump {
my
(
$version
,
$fs_entry
) =
@_
;
my
$dry_run
= 0;
if
(
defined
$version
&&
$version
=~ /^-/) {
print
"\nDry run\n\n"
;
$version
=~ s/-//;
$dry_run
= 1;
}
$fs_entry
//= DEFAULT_DIR;
_validate_version(
$version
);
_validate_fs_entry(
$fs_entry
);
my
@module_files
= _module_find_files(
$fs_entry
);
my
%files
;
for
(
@module_files
) {
my
$current_version
= _module_extract_file_version(
$_
);
my
$version_line
= _module_extract_file_version_line(
$_
);
my
@file_contents
= _module_fetch_file_contents(
$_
);
if
(!
defined
$version_line
) {
next
;
}
if
(!
defined
$current_version
) {
next
;
}
if
(version->parse(
$current_version
) >= version->parse(
$version
)) {
croak(
"Your new version $version must be greater than the current "
.
"one, $current_version"
);
}
my
$mem_file
;
open
my
$wfh
,
'>'
, \
$mem_file
or croak(
"Can't open mem file!: $!"
);
for
my
$line
(
@file_contents
) {
chomp
$line
;
if
(
$line
eq
$version_line
) {
$line
=~ s/
$current_version
/
$version
/;
}
$line
.=
"\n"
;
print
$wfh
$line
;
$files
{
$_
}{from} =
$current_version
;
$files
{
$_
}{to} =
$version
;
}
close
$wfh
;
$files
{
$_
}{dry_run} =
$dry_run
;
$files
{
$_
}{content} =
$mem_file
;
if
(!
$dry_run
) {
_module_write_file(
$_
,
$mem_file
);
}
}
return
\
%files
;
}
sub
version_incr {
my
(
$version
) =
@_
;
croak(
"version_incr() needs a version number sent in"
)
if
!
defined
$version
;
my
$incremented_version
;
_validate_version(
$version
);
return
sprintf
(
"%.2f"
,
$version
+
'0.01'
);
}
sub
version_info {
my
(
$fs_entry
) =
@_
;
$fs_entry
//= DEFAULT_DIR;
_validate_fs_entry(
$fs_entry
);
my
@module_files
= _module_find_files(
$fs_entry
);
my
%version_info
;
for
(
@module_files
) {
my
$version
= _module_extract_file_version(
$_
);
$version_info
{
$_
} =
$version
;
}
return
\
%version_info
;
}
sub
_changes_tie {
my
(
$changes
) =
@_
;
croak(
"_changes_tie() needs a Changes file name sent in"
)
if
!
defined
$changes
;
my
$tie
=
tie
my
@changes
,
'Tie::File'
,
$changes
;
return
(\
@changes
,
$tie
);
}
sub
_changes_write_file {
my
(
$file
,
$content
) =
@_
;
open
my
$fh
,
'>'
,
$file
or cluck(
"Can't open file $file: $!"
);
for
(
@$content
) {
print
$fh
"$_\n"
}
close
$fh
;
return
0;
}
sub
_ci_github_write_file {
my
(
$contents
) =
@_
;
if
(
ref
$contents
ne
'ARRAY'
) {
croak(
"_ci_github_write_file() requires an array ref of contents"
);
}
my
$ci_file
//= GITHUB_CI_PATH . GITHUB_CI_FILE;
make_path(GITHUB_CI_PATH)
if
! -d GITHUB_CI_PATH;
open
my
$fh
,
'>'
,
$ci_file
or croak $!;
print
$fh
"$_\n"
for
@$contents
;
}
sub
_config_file_write {
my
(
$file
,
$contents
) =
@_
;
if
(
ref
$contents
ne
'HASH'
) {
croak(
"_config_file_write() requires a hash ref of contents"
);
}
my
$jobj
= JSON->new;
my
$json
=
$jobj
->pretty->encode(
$contents
);
open
my
$fh
,
'>'
,
$file
or croak
"Can't open config $file for writing: $!"
;
print
$fh
$json
;
}
sub
_default_distribution_file_count {
return
[
[ [1, 0, 0] ],
[ [1, 0, 0] ],
[ [3, 2, 0] ],
[ [1, 0, 0] ],
[ [1, 0, 0] ],
[ [1, 0, 0] ],
[ [5, 1, 0] ],
[ [2, 1, 0] ],
];
}
sub
_git_ignore_write_file {
my
(
$dir
,
$content
) =
@_
;
open
my
$fh
,
'>'
,
"$dir/.gitignore"
or croak $!;
for
(
@$content
) {
print
$fh
"$_\n"
}
return
0;
}
sub
_makefile_tie {
my
(
$mf
) =
@_
;
croak(
"_makefile_tie() needs a Makefile name sent in"
)
if
!
defined
$mf
;
my
$tie
=
tie
my
@mf
,
'Tie::File'
,
$mf
;
return
(\
@mf
,
$tie
);
}
sub
_makefile_insert_meta_merge {
my
(
$mf
) =
@_
;
croak(
"_makefile_insert_meta_merge() needs a Makefile tie sent in"
)
if
!
defined
$mf
;
return
if
grep
/META_MERGE/,
@$mf
;
for
(0..
$#$mf
) {
if
(
$mf
->[
$_
] =~ /MIN_PERL_VERSION/) {
splice
@$mf
,
$_
+1, 0, _makefile_section_meta_merge();
last
;
}
}
}
sub
_makefile_insert_bugtracker {
my
(
$author
,
$repo
,
$makefile
) =
@_
;
if
(!
defined
$makefile
) {
croak(
"_makefile_insert_bugtracker() needs author, repo and makefile"
);
}
my
(
$mf
,
$tie
) = _makefile_tie(
$makefile
);
return
-1
if
grep
/bugtracker/,
@$mf
;
if
(
grep
! /META_MERGE/,
@$mf
) {
_makefile_insert_meta_merge(
$mf
);
}
for
(0..
$#$mf
) {
if
(
$mf
->[
$_
] =~ /
resources
=> \{/) {
splice
@$mf
,
$_
+1, 0, _makefile_section_bugtracker(
$author
,
$repo
);
last
;
}
}
untie
$tie
;
return
0;
}
sub
_makefile_insert_repository {
my
(
$author
,
$repo
,
$makefile
) =
@_
;
if
(!
defined
$makefile
) {
croak(
"_makefile_insert_repository() needs author, repo and makefile"
);
}
my
(
$mf
,
$tie
) = _makefile_tie(
$makefile
);
return
-1
if
grep
/repository/,
@$mf
;
if
(
grep
! /META_MERGE/,
@$mf
) {
_makefile_insert_meta_merge(
$mf
);
}
for
(0..
$#$mf
) {
if
(
$mf
->[
$_
] =~ /
resources
=> \{/) {
splice
@$mf
,
$_
+1, 0, _makefile_section_repo(
$author
,
$repo
);
last
;
}
}
untie
$tie
;
return
0;
}
sub
_manifest_skip_write_file {
my
(
$dir
,
$content
) =
@_
;
open
my
$fh
,
'>'
,
"$dir/MANIFEST.SKIP"
or croak $!;
for
(
@$content
) {
print
$fh
"$_\n"
}
return
0;
}
sub
_manifest_t_write_file {
my
(
$dir
,
$content
) =
@_
;
open
my
$fh
,
'>'
,
"$dir/manifest.t"
or croak(
"Can't open t/manifest.t for writing: $!\n"
);
for
(
@$content
) {
print
$fh
"$_\n"
}
return
0;
}
sub
_module_extract_file_version {
my
(
$module_file
) =
@_
;
my
$version_line
= _module_extract_file_version_line(
$module_file
);
if
(
defined
$version_line
) {
if
(
$version_line
=~ /=(.*)$/) {
my
$ver
= $1;
$ver
=~ s/\s+//g;
$ver
=~ s/;//g;
$ver
=~ s/[a-zA-Z]+//g;
$ver
=~ s/"//g;
$ver
=~ s/'//g;
if
(!
defined
eval
{ version->parse(
$ver
); 1 }) {
warn
(
"$_: Can't find a valid version\n"
);
return
undef
;
}
return
$ver
;
}
}
else
{
warn
(
"$_: Can't find a \$VERSION definition\n"
);
}
return
undef
;
}
sub
_module_extract_file_version_line {
my
(
$module_file
) =
@_
;
my
$doc
= PPI::Document->new(
$module_file
);
my
$token
=
$doc
->find(
sub
{
$_
[1]->isa(
"PPI::Statement::Variable"
)
and
$_
[1]->content =~ /\
$VERSION
/;
}
);
return
undef
if
ref
$token
ne
'ARRAY'
;
my
$version_line
=
$token
->[0]->content;
return
$version_line
;
}
sub
_module_fetch_file_contents {
my
(
$file
) =
@_
;
open
my
$fh
,
'<'
,
$file
or croak(
"Can't open file '$file' for reading!: $!"
);
my
@contents
= <
$fh
>;
close
$fh
;
return
@contents
;
}
sub
_module_find_files {
my
(
$fs_entry
,
$module
) =
@_
;
$fs_entry
//= DEFAULT_DIR;
if
(
defined
$module
) {
$module
=~ s/::/\//g;
$module
.=
'.pm'
;
}
else
{
$module
=
'*.pm'
;
}
return
File::Find::Rule->file()
->name(
$module
)
->in(
$fs_entry
);
}
sub
_module_insert_ci_badges {
my
(
$author
,
$repo
,
$module_file
) =
@_
;
my
(
$mf
,
$tie
) = _module_tie(
$module_file
);
return
-1
if
grep
/badge\.svg/,
@$mf
;
for
(0..
$#$mf
) {
if
(
$mf
->[
$_
] =~ /^=head1 NAME/) {
splice
@$mf
,
$_
+3, 0, _module_section_ci_badges(
$author
,
$repo
);
last
;
}
}
untie
$tie
;
return
0;
}
sub
_module_tie {
my
(
$mod_file
) =
@_
;
croak(
"Acme-STEVEB() needs a module file name sent in"
)
if
!
defined
$mod_file
;
my
$tie
=
tie
my
@mf
,
'Tie::File'
,
$mod_file
;
return
(\
@mf
,
$tie
);
}
sub
_module_write_file {
my
(
$module_file
,
$content
) =
@_
;
open
my
$wfh
,
'>'
,
$module_file
or croak(
"Can't open '$module_file' for writing!: $!"
);
print
$wfh
$content
;
close
$wfh
or croak(
"Can't close the temporary memory module file!: $!"
);
}
sub
_module_write_template {
my
(
$module_file
,
$module
,
$author
,
$email
) =
@_
;
if
(!
defined
$module_file
) {
croak(
"_module_write_template() needs the module's file name sent in"
);
}
if
(!
defined
$module
|| !
defined
$author
|| !
defined
$email
) {
croak(
"_module_template_file() requires 'module', 'author' and 'email' parameters"
);
}
my
@content
= _module_template_file(
$module
,
$author
,
$email
);
open
my
$wfh
,
'>'
,
$module_file
or croak(
"Can't open '$module_file' for writing!: $!"
);
print
$wfh
"$_\n"
for
@content
;
}
sub
_pod_extract_file_copyright {
my
(
$module_file
) =
@_
;
my
$copyright_line
= _pod_extract_file_copyright_line(
$module_file
);
if
(
defined
$copyright_line
) {
if
(
$copyright_line
=~ /^Copyright\s+(\d{4})\s+\w+/) {
return
$1;
}
}
else
{
warn
(
"$_: Can't find a Copyright definition\n"
);
}
return
undef
;
}
sub
_pod_extract_file_copyright_line {
my
(
$pod_file
) =
@_
;
open
my
$fh
,
'<'
,
$pod_file
or croak(
"Can't open POD file $pod_file: $!"
);
while
(<
$fh
>) {
if
(/^Copyright\s+\d{4}\s+\w+/) {
return
$_
;
}
}
}
sub
_pod_find_files {
my
(
$fs_entry
) =
@_
;
$fs_entry
//= DEFAULT_POD_DIR;
return
File::Find::Rule->file()
->name(
'*.pod'
,
'*.pm'
,
'*.pl'
)
->in(
$fs_entry
);
}
sub
_pod_tie {
my
(
$pod_file
) =
@_
;
croak(
"_pod_tie() needs a POD file name sent in"
)
if
!
defined
$pod_file
;
my
$tie
=
tie
my
@pf
,
'Tie::File'
,
$pod_file
;
return
(\
@pf
,
$tie
);
}
sub
_dist_dir_re {
return
qr/dist-mgr(?:-\d+\.\d+)?(?:-\w+|_\d+)?$/
i;
}
sub
_validate_git {
my
$sep
= $^O =~ /win32/i ?
';'
:
':'
;
return
grep
{-x
"$_/git"
}
split
/
$sep
/,
$ENV
{PATH};
}
sub
_validate_fs_entry {
my
(
$fs_entry
) =
@_
;
cluck(
"Need name of dir or file!"
)
if
!
defined
$fs_entry
;
return
FSTYPE_IS_DIR
if
-d
$fs_entry
;
return
FSTYPE_IS_FILE
if
-f
$fs_entry
;
croak(
"File system entry '$fs_entry' is invalid"
);
}
sub
_validate_version {
my
(
$version
) =
@_
;
croak(
"version parameter must be supplied!"
)
if
!
defined
$version
;
if
(!
defined
eval
{ version->parse(
$version
); 1 }) {
croak(
"The version number '$version' specified is invalid"
);
}
}
sub
_export_private {
push
@EXPORT_OK
,
@EXPORT_PRIVATE
;
return
\
@EXPORT_OK
;
}
sub
__placeholder {}
1;