App-DocKnot

 view release on metacpan or  search on metacpan

lib/App/DocKnot/Update.pm  view on Meta::CPAN

# Update package configuration for a DocKnot version upgrade.
#
# Adjusts the DocKnot configuration data for changes in format for newer
# versions of DocKnot.
#
# SPDX-License-Identifier: MIT

##############################################################################
# Modules and declarations
##############################################################################

package App::DocKnot::Update v8.0.1;

use 5.024;
use autodie;
use parent qw(App::DocKnot);
use warnings;

use Carp qw(croak);
use JSON::MaybeXS qw(JSON);
use Kwalify qw(validate);
use Path::Iterator::Rule;
use Path::Tiny qw(path);
use YAML::XS ();

# The older JSON metadata format stored text snippets in separate files in the
# file system.  This is the list of additional files to load from the metadata
# directory if they exist.  The contents of these files will be added to the
# configuration in a key of the same name.  If the key contains a slash, like
# foo/bar, it will be stored as a nested hash, as $data{foo}{bar}.
our @JSON_METADATA_FILES = qw(
    bootstrap
    build/middle
    build/suffix
    debian/summary
    packaging/extra
    support/extra
    test/prefix
    test/suffix
);

##############################################################################
# JSON helper methods
##############################################################################

# Internal helper routine to return the path of a file or directory from the
# package metadata directory.  The resulting file or directory path is not
# checked for existence.
#
# @path - The relative path of the file as a list of components
#
# Returns: Path::Tiny for the metadata file
sub _metadata_path {
    my ($self, @path) = @_;
    return path($self->{metadata}, @path);
}

# Internal helper routine to read a file from the package metadata directory
# and return the contents.  The file is specified as a list of path
# components.
#
# @path - The path of the file to load, as a list of components
#
# Returns: The contents of the file as a string
#  Throws: slurp exception on failure to read the file
sub _load_metadata {
    my ($self, @path) = @_;
    my $path = $self->_metadata_path(@path);
    return $path->slurp_utf8();
}

# Like _load_metadata, but interprets the contents of the metadata file as
# JSON and decodes it, returning the resulting object.  This uses the relaxed
# parsing mode, so comments and commas after data elements are supported.
#
# @path - The path of the file to load, as a list of components
#
# Returns: Anonymous hash or array resulting from decoding the JSON object
#  Throws: slurp or JSON exception on failure to load or decode the object
sub _load_metadata_json {
    my ($self, @path) = @_;

lib/App/DocKnot/Update.pm  view on Meta::CPAN

    # 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(
        {



( run in 0.605 second using v1.01-cache-2.11-cpan-39bf76dae61 )