App-DocKnot
view release on metacpan or search on metacpan
lib/App/DocKnot/Update.pm view on Meta::CPAN
if (defined($repo)) {
my $root = path($repo->work_tree());
$repo->run('add', $spin_path->relative($root)->stringify());
$repo->run('rm', $faq_path->relative($root)->stringify());
}
return;
}
# Convert an *.rpod file to a *.spin pointer. Intended to be run via
# Path::Iterator::Rule.
#
# $rpod_path - Path to *.rpod file
# $repo - Optional Git::Repository object for input tree
sub _convert_rpod_pointer {
my ($self, $rpod_path, $repo) = @_;
# Convert the file.
my $data_ref = $self->_read_rpod_pointer($rpod_path);
my $basename = $rpod_path->basename('.rpod');
my $spin_path = $rpod_path->sibling($basename . '.spin');
$self->_write_spin_pointer($data_ref, $spin_path);
# If we have a Git repository, update Git.
if (defined($repo)) {
my $root = path($repo->work_tree());
$repo->run('add', $spin_path->relative($root)->stringify());
$repo->run('rm', $rpod_path->relative($root)->stringify());
}
return;
}
##############################################################################
# Public Interface
##############################################################################
# Create a new App::DocKnot::Update object, which will be used for subsequent
# calls.
#
# $args - Anonymous hash of arguments with the following keys:
# metadata - Path to the directory containing package metadata
# output - Path to the output file with the converted metadata
#
# Returns: Newly created object
# Throws: Text exceptions on invalid metadata directory path
sub new {
my ($class, $args_ref) = @_;
my $self = {
metadata => path($args_ref->{metadata} // 'docs/metadata'),
output => path($args_ref->{output} // 'docs/docknot.yaml'),
};
bless($self, $class);
return $self;
}
# Update an older version of DocKnot configuration. Currently, this only
# handles the old JSON format.
#
# Raises: autodie exception on failure to read metadata
# Text exception on inconsistencies in the package data
# Text exception if schema checking failed on the converted config
sub update {
my ($self) = @_;
# Ensure we were given a valid metadata argument.
if (!$self->{metadata}->is_dir()) {
my $metadata = $self->{metadata};
croak("metadata path $metadata does not exist or is not a directory");
}
# Tell YAML::XS that we'll be feeding it JSON::PP booleans.
local $YAML::XS::Boolean = 'JSON::PP';
# Load the config.
my $data_ref = $self->_config_from_json();
# Add the current format version.
$data_ref->{format} = 'v1';
# Move bootstrap to build.bootstrap.
if (defined($data_ref->{bootstrap})) {
$data_ref->{build}{bootstrap} = $data_ref->{bootstrap};
delete $data_ref->{bootstrap};
}
# Move build.lancaster to test.lancaster.
if (defined($data_ref->{build}{lancaster})) {
$data_ref->{test}{lancaster} = $data_ref->{build}{lancaster};
delete $data_ref->{build}{lancaster};
}
# Move packaging.debian to packaging.debian.package, move debian to
# packaging.debian, and move packaging to distribution.packaging.
if (defined($data_ref->{packaging})) {
if (defined($data_ref->{packaging}{debian})) {
my $package = $data_ref->{packaging}{debian};
$data_ref->{packaging}{debian} = { package => $package };
}
}
if (defined($data_ref->{debian})) {
$data_ref->{packaging}{debian} //= {};
$data_ref->{packaging}{debian}
= { $data_ref->{debian}->%*, $data_ref->{packaging}{debian}->%* };
delete $data_ref->{debian};
}
if ($data_ref->{packaging}) {
$data_ref->{distribution}{packaging} = $data_ref->{packaging};
delete $data_ref->{packaging};
}
# Move readme.sections to sections. If there was a testing override, move
# it to test.override and delete it from sections.
if (defined($data_ref->{readme})) {
$data_ref->{sections} = $data_ref->{readme}{sections};
delete $data_ref->{readme};
for my $section_ref ($data_ref->{sections}->@*) {
if (lc($section_ref->{title}) eq 'testing') {
$data_ref->{test}{override} = $section_ref->{body};
last;
}
}
$data_ref->{sections}
= [grep { lc($_->{title}) ne 'testing' } $data_ref->{sections}->@*];
}
# support.cpan is obsolete. If vcs.github is set and support.github is
# not, use it as support.github.
if (defined($data_ref->{support}{cpan})) {
if (!defined($data_ref->{support}{github})) {
if (defined($data_ref->{vcs}{github})) {
$data_ref->{support}{github} = $data_ref->{vcs}{github};
}
}
delete $data_ref->{support}{cpan};
}
# Check the schema of the resulting file.
my $schema_path = $self->appdata_path('schema/docknot.yaml');
my $schema_ref = YAML::XS::LoadFile($schema_path);
eval { validate($schema_ref, $data_ref) };
if ($@) {
my $errors = $@;
chomp($errors);
die "schema validation failed:\n$errors\n";
}
# Write the new YAML package configuration.
YAML::XS::DumpFile($self->{output}->stringify(), $data_ref);
return;
}
# Update an input tree for spin to the current format.
#
# $path - Optional path to the spin input tree, defaults to current directory
#
# Raises: Text exception on failure
sub update_spin {
my ($self, $path) = @_;
$path = defined($path) ? path($path) : path(q{.});
my $repo;
if ($path->child('.git')->is_dir()) {
$repo = Git::Repository->new(work_tree => "$path");
}
# Convert all *.faq files to *.spin files.
my $rule = Path::Iterator::Rule->new()->name(qr{ [.] faq \z }xms);
my $iter = $rule->iter($path, { follow_symlinks => 0 });
while (defined(my $file = $iter->())) {
$self->_convert_faq_pointer(path($file), $repo);
}
# Convert all *.rpod files to *.spin files.
$rule = Path::Iterator::Rule->new()->name(qr{ [.] rpod \z }xms);
$iter = $rule->iter($path, { follow_symlinks => 0 });
while (defined(my $file = $iter->())) {
$self->_convert_rpod_pointer(path($file), $repo);
}
return;
}
##############################################################################
# Module return value and documentation
##############################################################################
1;
__END__
=for stopwords
Allbery DocKnot MERCHANTABILITY NONINFRINGEMENT sublicense CPAN XDG
=head1 NAME
App::DocKnot::Update - Update DocKnot input or package configuration
=head1 SYNOPSIS
use App::DocKnot::Update;
my $update = App::DocKnot::Update->new(
{
metadata => 'docs/metadata',
output => 'docs/docknot.yaml',
}
);
$update->update();
$update->update_spin('/path/to/spin/input');
=head1 REQUIREMENTS
Perl 5.24 or later and the modules Git::Repository, File::BaseDir,
File::ShareDir, JSON::MaybeXS, Path::Iterator::Rule, Path::Tiny, Perl6::Slurp,
and YAML::XS, all of which are available from CPAN.
=head1 DESCRIPTION
This component of DocKnot updates package configuration from older versions.
( run in 0.702 second using v1.01-cache-2.11-cpan-39bf76dae61 )