The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

Dist::Zilla::Plugin::Manifest::Write::Manual - Manifest::Write plugin user manual

VERSION

Version v0.9.7, released on 2016-12-14 22:51 UTC.

WHAT?

Dist-Zilla-Plugin-Manifest-Write (or Manifest::Write for brevity) is a plugin for Dist::Zilla, a replacement for standard plugin Manifest. Manifest::Write writes annotated distribution manifest: each filename is followed by a comment explaining origin of the file: if it is a part of software, meta information, or 3rd-party file. Also it can exclude built files from distribution, e. g. extra tests have to be built (to run) but need not be distributed.

This is Manifest::Write plugin user manual. Read this if you want to have annotated distribution manifest.

If you are going to hack or extend Manifest::Write, read the module documentation. General topics like getting source, building, installing, bug reporting and some others are covered in the README.

SYNOPSIS

In your dist.ini:

    ...
    [GatherDir]         ; Plugin which adds source files to distribution.
                        ; You may use other plugins, like GatherFromManifest
                        ; or Manifest::Read.
    [Manifest::Write]
        source_provider = GatherDir
        exclude_files   = :ExtraTestFiles
    ...

DESCRIPTION

Manifest::Write is a replacement for standard plugin Manifest. To use Manifest::Write, you should replace line

    [Manifest]

with

    [Manifest::Write]

in your dist.ini file, and specify one or more source providers, e. g.:

    [Manifest::Write]
        source_provider = GatherDir

(See source_provider option below for details.)

Manifest File

Manifest file enlists files which should be included into the distribution. Usually manifest file itself is also included into the distribution.

The name of manifest file written by the Manifest::Write is specified by manifest option. Default value is MANIFEST, a conventional name for the manifest file.

Manifest File Format

Manifest file generated by Manifest::Write follows the format defined in "MANIFEST" in ExtUtils::Manifest. However, comments generated by the Manifest::Write have internal structure, see below.

If the first non-whitespace character of a line is hash character (#), such line is a comment.

Other lines in annotated manifest follows the format:

    NAME # DEED file BREED by ADDER [ and munged by MUNGER,… ]

Square brackets denote optional part, ellipsis denotes repeatable part, hash (#), file, by, and munged by are literals.

NAME

Just a file name. If file name contains spaces, apostrophes ('), backslashes (\), or hashes (#) it is formatted as Perl single-quoted string literal, otherwise it is written as-is.

#

Technically, hash character is not required because everything after a file name is a comment, hash just visually emphasises it.

DEED

File "deed" is file ownership: if the file (1) belongs to the project, is (2) meta information, or (3) third-party file. In the first case "deed" is project (distribution) name, in the second — metainfo, in the third — 3rd party. (So, do not name your project "metainfo" to avoid confusion.)

BREED

File "breed" explains how the file appeared in the distribution — was it added (copied as-is from the project sources) or built (generated).

ADDER

File "adder" is a moniker of plugin (see "Plugin moniker") brought (either added or built, see "BREED") the file into the distribution.

Plugins bringing files to distribution do FileInjector or FileGatherer roles. Some plugins add existing files to distribution (e. g. GatherDir, Manifest::Read), others generate new files (e. g. Test::EOL, Test::NoTabs).

MUNGER

File "munger" is a plugin changed the file during build.

Plugins modifying files in distribution do FileMunger role. Some plugins may touch files slightly (for example, PkgVersion changes a single line in Perl modules), others may rewrite them heavily (PodWeaver removes or comments out all existing POD and generates new POD at the end).

The same file may be changed several times during build. For example, Perl module may be processed by both PkgVersion and PodWeaver.

Quite often the same plugin appears as both adder and munger. Many plugins add a generic template to the distribution first, then tune the template to meet the distribution needs.

If a file was not changed after its addition to the distribution, annotation will not show any mungers for this file, obviously. Also, all munger may be forcibly hidden by show_mungers option.

Skip File

Skip file defines files which should not be included into distribution. See "MANIFEST.SKIP" in ExtUtils::Manifest for more details.

Manifest::Write generates skip file. Skip file name is set by manifest_skip option. Default name is MANIFEST.SKIP. Empty name disables generating skip file.

Skip file generated by the Manifest::Write consists of list of excluded files (see "exclude_files") and copy of content of MANIFEST.SKIP file from currently installed ExtUtils::Manifest distribution (content is copied at the distribution build time). "#!include" and "#!include_default" are not used (because they are not recognized by Module::Manifest).

Skip file could be necessary to let Test::DistManifest pass — the tests checks the every file is either listed in MANIFEST or skipped.

OPTIONS

exclude_files

This option excludes files from the manifest (and from the distribution archive).

Option value should be a name of file finder. Default value is :NoFiles (i. e. no files are excluded, all the built files are packed to the distribution archive).

This is a multi-value option, i. e. it could be specified several times. Files found by any of the specified finders are excluded from the distribution archive.

    [Manifest::Write]
        exclude_files = :ExtraTestFiles

See also "Excluding Files".

manifest

Name of manifest file to write. Default value is MANIFEST. It is unlikely you will need to change the default value.

It could be used, though, to generate both standard and annotated manifests (for testing, comparison, etc):

    [Manifest]          ; Writes 'MANIFEST'.
    [Manifest::Write]   ; Writes 'Manifest.annotated'.
        manifest = Manifest.annotated

manifest_skip

Name of skip file to write. Default value is MANIFEST.SKIP. It is unlikely you will need to change the default value. However, empty value disables generating MANIFEST.SKIP:

    [Manifest::Write]
        manifest_skip = ; Disable writing 'MANIFEST.SKIP'.

source_provider

This is a multi-value option, i. e. option may be specified several times. Every option value is a name of plugin (see "Plugin name") which adds source files to distribution.

    source_provider = GatherDir
    source_provider = GatherDir::Template
    source_provider = GenerateFile

There are no default source file providers. You will likely want to specify GatherDir, GatherFromManifest and similar plugins as source providers.

Note: source files term does not mean exactly Perl sources. Source files are your files (usually hand-crafted), in contrast to metainfo and 3rd party files generated by various Dist::Zilla plugins. Sources may include Perl modules, scripts, POD files, tests, and any other files composing your software.

source_providers

The option splits its value into plugin names using whitespaces as separators, so

    source_providers = GatherDir GatherDir::Template GenerateFile

is just a shortcut for

    source_provider = GatherDir
    source_provider = GatherDir::Template
    source_provider = GenerateFile

metainfo_provider

This is multi-value option too. Every value is a name of plugin (see "Plugin name") which adds meta information files to the distribution:

    metainfo_provider = MetaYAML
    metainfo_provider = MetaJSON
    metainfo_provider = Manifest

Default meta info providers are CPANFile, Manifest, MetaYAML, MetaJSON, and the Manifest::Write plugin itself. It seems these metainfo providers should satisfy most of the users.

Specifying any metainfo_provider or metainfo_providers option (even with empty value) cancels all the default metainfo providers:

    metainfo_provider =     ; Cancel default metainfo providers.

metainfo_providers

The option allows to specify several source providers in single line:

    metainfo_providers = MetaYAML MetaJSON Manifest

The option splits its value to separate plugin names, using whitespaces as separators. If plugin names contain spaces, use metainfo_provider option.

strict

Let us consider an example:

    [Manifest::Write]
        metainfo_provider = MetaYML

At the first glance it may look ok, but there is a mistake: correct plugin name is MetaYAML, not MetaYML (assumed the plugin was not explicitly (re)named). Left unnoticed, such a typo may cause bad manifest: files may have incorrect "deed" classification.

To avoid such mistakes Manifest::Write checks plugin names specified in source_provider and metainfo_provider options. Any name specified in these options must be a name of Dist::Zilla plugin consumed FileInjector role (or FileGatherer, which is a kind of FileInjector). If not, Manifest::Write issues error message and aborts build process.

This behaviour may be modified by strict option, which sets the level of strictness. Level 1 behaviour is described above (strict checks, any mistake is fatal), this is default. At level -1 Manifest::Write does not check provider names at all. At level 0 some mistakes are fatal, some are not. Using a plugin which does not do FileInjector role is fatal error. Using a string which is not a (loaded) plugin name is not fatal (because it may be a name proper plugin which is not loaded, e. g. commented out):

    ; [MetaYAML]
    [Manifest::Write]
        metainfo_provider = MetaYAML
        ;   MetaYAML is a correct name of not loaded plugin,
        ;   but Manifest::Write cannot verify it easily.
        strict = 0
        ;   Print a message but do not abort build.

show_mungers

If set to 1, information about file mungers (if any) is included into file annotation. If 0, file mungers is not shown completely. Default value is 0. See "File Mungers".

NOTES

Plugin Identification

Every Dist:Zilla plugin has (at least) two attributes: moniker and name. Both are used for plugin identification, but these terms are not explained well in Dist::Zilla documentation. Often plugin moniker equals to the plugin name (and so they are interchangeable), but sometimes not. The difference is important enough to be explained.

Plugin moniker

In order to load plugin, Dist::Zilla should know plugin package. Great majority of plugin packages start with Dist::Zilla::Plugin:: prefix. Using full package names in dist.ini file looks ugly:

    [Dist::Zilla::Plugin::GatherDir]
    [Dist::Zilla::Plugin::PruneCruft]
    [Dist::Zilla::Plugin::Manifest]
    [Dist::Zilla::Plugin::MetaYAML]
    [Dist::Zilla::Plugin::MetaJSON]

So Dist::Zilla uses plugin monikers instead of plugin package names. Moniker is a plugin package name with the common prefix stripped down:

    [GatherDir]
    [PruneCruft]
    [Manifest]
    [MetaYAML]
    [MetaJSON]

Dist::Zilla prepends a plugin moniker with the common prefix to get plugin package name.

In rare cases when plugin package does not start with the common prefix, plugin moniker must start with = to let Dist::Zilla know the common prefix should not be used:

    [=MyPrivatePlugin]

Dist::Zilla drops equal sign and uses the rest as package name.

Since moniker is a part of package name, it cannot include characters not valid for package names (equal sign in the first position is an exception).

Plugin name

Someone may want to use the same plugin more than once. To differentiate plugins with the same moniker, Dist::Zilla introduces plugin names. Name is unique string that identifies plugin in dist.ini. Plugin name is specified in dist.ini after plugin moniker and separated from the moniker by slash:

    [GenerateFile/Copying]
        filename = COPYING
        content  = ...
    [GenerateFile/ReadMe]
        filename = README
        content  = ...

If plugin name is not specified explicitly, the plugin gets automatically assigned name, which is the same as the plugin moniker:

    [Manifest]  ; plugin named "Manifest"

Actually, it is just short form of

    [Manifest/Manifest]  ; plugin named "Manifest"

All the plugins in dist.ini must have unique names.

Since name is just a string, it may include arbitrary characters, probably with few exceptions like square brackets and newlines.

Thus, a plugin name is a string identifier assigned to the plugin by distribution author. Plugin names are unique within dist.ini, but they are also "local" within dist.ini because nobody except the distribution author takes care about plugin names used in the dist.ini. (dist.ini file may even be excluded from distribution.)

In contrast, a plugin moniker is (part of) the plugin package name, and so "assigned" by plugin author. If plugin is published on CPAN (which is quite common), plugin moniker becomes a "global" entity.

So, in dist.ini file, source_provider and metainfo_provider options accept plugin names because names unambiguously identify plugins in dist.ini. However, in manifest file, plugin monikers are used because plugin names have little or no meaning for distribution users, while plugin monikers are still valuable.

File Mungers

Dist::Zilla records each file operation (adding, content modification, etc) in a history log attached to every file (see added_by attribute declared in Dist::Zilla::Role::File).

File adder is recorded properly.

Unfortunately, (in Dist::Zilla 5.039) subsequent file modifications are recorded not too accurate: Dist::Zilla guesses the plugin that changed the file. When guessing, it uses heuristic which works correctly only in trivial cases. In non-trivial cases recorded information is not fully correct (this is a soft form to say "incorrect"). "Non-trivial case" does not mean something overcomplicated: consuming a role or extending a class are non-trivial cases. So, file history log may have records that file was modified by a role (actually the file was modified by the plugin consumed the role) or a plugin's parent class (actual modifier was the plugin itself).

Thus, all but the first records in file history log are unreliable.

Manifest::Write uses file history logs to generate file annotations. So file annotations in manifest are inaccurate too. A file adder is quite reliable, but file mungers are not.

This is reason why show_mungers option is set to 0 by default.

Excluding Files

Rationale

Excluding files from the distribution archive looks like pruning, but there is a big difference. Pruned files are excluded from Dist::Zilla attention before build (and so, such files are not built), while exclude_files option excludes files from the distribution tarball. Excluded files are built anyway, but not included into the archive. What is the reason for such strange action?

Many distributions built by Dist::Zilla have number of author and/or release tests, collectively called "extra tests". Most of these tests are not written by the distribution author but generated by various Dist::Zilla plugins. These generated tests should be built (in order to run them before making a release) and all these tests are included into the distribution archive (just because Dist::Zilla packs all built files).

But extra tests have little sense for distribution users. By their nature extra tests are intended to be run either by the distribution author (author tests) or the releaser (release tests); neither cpan nor cpanp nor cpanm run extra tests before installing a distribution.

Thus, extra test should be built, but there is no point to include them into the distribution. As far as I know Dist::Zilla does not have "official" way to do it. Manifest::Write fulfills this lack.

Why Manifest::Write?

Ok, excluding extra tests from the distribution archive seems to be a good idea, but why Manifets::Write does it? Manifest::Write's job is writing the manifest, excluding files from the archive looks like a task for a dedicated plugin, doesn't it?

Yes, it does. Writing such a plugin would be a trivial work. However, there is a problem. Such a plugin would work just before creating the archive, when all the files (including the MANIFEST) are built already, so excluding files from the archive makes the MANIFEST incorrect. (I thought out few ways to workaround the problem, but not a good one.)

Wait a moment. Let us treat the manifest not as "the list of packed files" but as "the list of files to pack". Excluding a file from the manifest automatically causes disappearing the file from the distribution archive. It sounds logical, doesn't it?

Thus, Manifest::Write's exclude_file option excludes the files from the manifest, and disappearing the files from the distribution archive is just a (desirable) side effect.

WHY?

MANIFEST is a metainfo file, a part of every distribution. It is a plain list of files included into the distribution. Typical MANIFEST looks like:

    Build.PL
    COPYING
    Changes
    MANIFEST
    META.yml
    README
    dist.ini
    lib/Dummy.pm
    t/00-compile.t

Format of manifest allows comments, but comments are rarely used.

As it noted before, manifest is a plain list of files. However, files included into a distribution differ:

  1. Some files are created by software author (in the example above, lib/Dummy.pm could be such file). Some of these files may be processed by various filters (like PkgVersion or PodWeaver).

  2. Some files contain distribution meta information (META.yml and MANIFEST itself).

  3. Some files may be generated by a tool from third party templates (Dist-Zilla and its plugins can generate a lot of various files, in the example above all the tests could be generated, as well as Build.PL, COPYING, Changes, and README).

Sometimes you may want (or have) to trace origin of files: whether this or that file was created by author or automatically generated, if the file was processed or added as-is. With a standard manifest (built by Manifest plugin) you have to guess this or study the distribution build process: look into dist.ini file, used plugins and plugin bundles. In contrast to standard Manifest plugin, Manifest::Write writes annotated manifest:

    # This file was generated with Dist::Zilla::Plugin::Manifest::Write v0.9.6.
    Build.PL       # 3rd party file built by ModuleBuildTiny
    COPYING        #     Dummy file added by GatherDir
    Changes        #     Dummy file added by GatherDir
    MANIFEST       #  metainfo file built by Manifest::Write
    META.yml       #  metainfo file built by MetaYAML
    README         #     Dummy file added by GatherDir
    dist.ini       #     Dummy file added by GatherDir
    lib/Dummy.pm   #     Dummy file added by GatherDir
    t/00-compile.t # 3rd party file built by Test::Compile

(In the example above "Dummy" is name of manifested distribution.)

Having such annotated manifest there is no need to guess origin of files. (However, see File Mungers.)

SEE ALSO

Dist::Zilla
Dist::Zilla::Plugin::Manifest
Dist::Zilla::Role::FileInjector
Dist::Zilla::Role::FileGatherer
Dist::Zilla::Role::FilePruner
"MANIFEST.SKIP" in ExtUtils::Manifest
Dist::Zilla::Plugin::Manifest::Write

AUTHOR

Van de Bugger <van.de.bugger@gmail.com>

COPYRIGHT AND LICENSE

Copyright (C) 2015, 2016 Van de Bugger

License GPLv3+: The GNU General Public License version 3 or later <http://www.gnu.org/licenses/gpl-3.0.txt>.

This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.