如何将脚本上传到CPAN
如果你有一个有用的Perl脚本,你可能想把它放到CPAN上。成为CPAN作者是Perl程序员的必经之路,你将了解CPAN基础设施,共享代码是一件好事。在将分发版上传到CPAN的几分钟内,它就会被索引并由拥有CPAN客户端的任何人安装,这真是太不可思议了。
所以,假设我有一个这个Perl脚本
#!/usr/bin/env perl
use strict;
use warnings;
use DateTime;
my $text = 'bar';
my $dt = DateTime->now;
if ($dt->mon == 1 && $dt->day == 31) {
$text = reverse $text;
}
print "$text\n";
exit 0;
它通常打印“bar”,但在1月31日,即国家倒退日,它打印“rab”。我将一步步带你把脚本放到CPAN上。
设置你的分发目录
上传到CPAN被称为分发版,每个分发版包含多个文件,所以我需要创建一个目录来存放我即将创建的所有文件。由于大多数应用程序都是在上面的命名空间App
下上传的,我也会这样做。
$ mkdir App-foo
$ cd App-foo
这是根项目目录。现在我将创建一些子目录
$ mkdir script
$ mkdir -p lib/App
lib/App
是我们将要创建的存根模块的父目录。script
目录是放置foo
脚本的地方。
为CPAN准备脚本
我将把我的脚本复制到script/foo
。我喜欢对我的CPAN脚本进行的一个更改是shebang行。对于我的个人脚本,我通常使用
#!/usr/bin/env perl
这个优势是,通过调用env
,可以更改执行时使用的Perl,这在我运行perlbrew或plenv时很棒。但是,并不是每个人都这样管理多个Perl安装。相反,我喜欢使用
#!perl
当分发版安装时,shebang行会自动更改到安装分发版所使用的Perl可执行文件的绝对路径,如下所示
#!/home/dfarrell/.plenv/versions/5.22.0/bin/perl5.22.0
您也可以使用#!/usr/bin/perl
,它会被安装过程覆盖。我喜欢使用#!perl
的原因是,如果没有安装脚本或指定运行它的Perl,它将无法工作。这避免了像意外使用系统Perl来运行脚本这样的错误。
我还需要添加一些文档,所以最终的脚本看起来像这样
#!perl
use strict;
use warnings;
use DateTime;
my $text = 'bar';
my $dt = DateTime->now;
if ($dt->mon == 1 && $dt->day == 31) {
$text = reverse $text;
}
print "$text\n";
exit 0;
=head1 NAME
foo - print bar, usually
=head1 DESCRIPTION
A simple script which usually prints C<bar>. On national backwards day
(January 31), it prints C<rab>. This distribution is used to show others
how to prepare a script for CPAN.
=head1 SYNOPSIS
$ foo
bar
=head1 AUTHOR
David Farrell
=head1 LICENSE
FreeBSD
=head1 INSTALLATION
Using C<cpan>:
$ cpan App::foo
Manual install:
$ perl Makefile.PL
$ make
$ make install
=cut
我在这里包括了安装说明,你稍后会看到原因。
创建存根模块
CPAN工具链要求每个分发版至少有一个包1,所以我将创建一个存根lib/App/foo.pm
。
package App::foo;
our $VERSION = 0.01;
=head1 NAME
App::foo - an app that usually prints "bar"
=head1 DESCRIPTION
This is a stub module, see F<script/foo> for details of the app.
=head1 AUTHOR
David Farrell
=head1 LICENSE
FreeBSD
=cut
1;
这个存根模块做了一些重要的事情:有这个包意味着CPAN可以索引这个模块,它将在metacpan上可搜索,并且可以被CPAN客户端(如cpan
和cpanm
)安装。它设置分发版版本号,并包含一些基本文档,引导用户到foo
脚本,这是这个分发版的核心。
1你可以通过编辑META文件而不提供Perl模块来欺骗CPAN。查看stasis以了解示例。缺点是,没有真正的包,Perl工具链中的其他工具可能会损坏,不建议这样做。
创建Makefile.PL
我们需要的其他文件是Makefile.PL
。这是一个Perl脚本,它将创建构建、测试和安装模块的Makefile。稍后,我将使用Perl工具链中的一些内置例程来使用我们的Makefile.PL做更多的事情。
use 5.008004;
use ExtUtils::MakeMaker;
WriteMakefile(
NAME => 'App::foo',
VERSION_FROM => 'lib/App/foo.pm',
ABSTRACT_FROM => 'lib/App/foo.pm',
AUTHOR => 'David Farrell',
LICENSE => 'freebsd',
MIN_PERL_VERSION => '5.008004',
EXE_FILES => ['script/foo'],
PREREQ_PM => {
'strict' => 0,
'warnings' => 0,
'DateTime' => '0.37',
},
(eval { ExtUtils::MakeMaker->VERSION(6.46) } ? (META_MERGE => {
'meta-spec' => { version => 2 },
resources => {
repository => {
type => 'git',
url => 'https://github.com/dnmfarrell/foo.git',
web => 'https://github.com/dnmfarrell/foo',
},
}})
: ()
),
);
此 Makefile.PL
脚本使用了 ExtUtils::MakeMaker。在脚本的最顶部,声明 use 5.008004
确保此脚本只能由 Perl 5.8.4 或更高版本运行。存在 MINIMUM_PERL_VERSION
条目,以便 CPAN 客户端和服务(如 CPAN 测试者)知道使用此分发版需要什么最低 Perl 版本。
您可以看到,我已经将版本和摘要文本设置为从占位符模块获取。我已经将许可证设置为 FreeBSD,但还有许多 其他 也可以接受。许可证和最低 Perl 版本条目是新选项,可能在较旧的 ExtUtils::MakeMaker 版本中生成警告 - 这没关系,它们将被忽略,构建将继续。
EXE_FILES
行很重要;它将确保在安装时将脚本复制到可执行目录。 PREREQ_PM
是脚本使用的运行时模块的哈希引用。在这种情况下,支持脚本中使用的 mon()
方法的 DateTime 的第一个版本是 0.37(技术上 mon()
是一个别名,我可以将其切换到 month()
,但这会使示例变得不那么有趣)。对于 strict 和 warnings 前缀,没有最低版本,所以我可以直接使用零。
脚本的最后一部分从 eval
开始,这有点奇怪。较旧的 ExtUtils::MakeMaker 版本不支持 CPAN 元规范的第 2 版,因此使用 META_MERGE,这将仅在构建现代版本时包含在内。如果分发代码位于 GitHub 等存储库中,则可以使用此可选条目。否则,它不是必需的。如果存在此条目,类似 MetaCPAN 的网站将在 GitHub 上包含指向存储库的链接。
创建一个 README
我喜欢在这个地方作弊
$ perldoc -u script/foo > README.pod
这会将脚本中的原始 POD 写入 README.pod
。要记住的一件事是,在此文件中包含安装说明。这就是为什么我在脚本 POD 中包含它的原因。
添加一个 LICENSE 文件
我已经在 makefile 中将此分发版的软件许可证指定为 FreeBSD,因此我应该将许可证的副本包含在分发版中。使用 App::Software::License,这很容易。
$ software-license --holder 'David Farrell' --license FreeBSD --type fulltext > LICENSE
这将在我的名字下创建一个 FreeBSD 许可证,并将其写入 LICENSE
文件。
构建分发版 tarball
现在有趣的部分开始了!
$ perl Makefile.PL
Generating a Unix-style Makefile
Writing Makefile for App::foo
Writing MYMETA.yml and MYMETA.json
这会创建 Makefile
,但还会创建定义分发版元数据的 META 文件。这些文件由 CPAN 工具链用于索引、版本控制和依赖关系管理(CPAN::Meta::Spec 描述元数据规范)。
$ make manifest
"/home/dfarrell/.plenv/versions/5.22.0/bin/perl5.22.0" "-MExtUtils::Manifest=mkmanifest" -e mkmanifest
Added to MANIFEST: lib/App/foo.pm
Added to MANIFEST: LICENSE
Added to MANIFEST: Makefile.PL
Added to MANIFEST: MANIFEST
Added to MANIFEST: README.pod
Added to MANIFEST: script/foo
这将创建一个 MANIFEST
文件,其中列出分发版中的所有文件。
$ make
cp lib/App/foo.pm blib/lib/App/foo.pm
cp README.pod blib/lib/App/README.pod
cp script/foo blib/script/foo
"/home/dfarrell/.plenv/versions/5.22.0/bin/perl5.22.0" -MExtUtils::MY -e 'MY->fixin(shift)' -- blib/script/foo
Manifying 1 pod document
Manifying 2 pod documents
$ make install
Manifying 1 pod document
Manifying 2 pod documents
Installing /home/dfarrell/.plenv/versions/5.22.0/lib/perl5/site_perl/5.22.0/App/foo.pm
Installing /home/dfarrell/.plenv/versions/5.22.0/lib/perl5/site_perl/5.22.0/App/README.pod
Installing /home/dfarrell/.plenv/versions/5.22.0/man/man1/foo.1
Installing /home/dfarrell/.plenv/versions/5.22.0/man/man3/App::README.3
Installing /home/dfarrell/.plenv/versions/5.22.0/man/man3/App::foo.3
Installing /home/dfarrell/.plenv/versions/5.22.0/bin/foo
Appending installation info to /home/dfarrell/.plenv/versions/5.22.0/lib/perl5/5.22.0/x86_64-linux/perllocal.pod
cp lib/App/foo.pm blib/lib/App/foo.pm
cp script/foo blib/script/foo
"/home/dfarrell/.plenv/versions/5.22.0/bin/perl5.22.0" -MExtUtils::MY -e 'MY->fixin(shift)' -- blib/script/foo
Manifying 1 pod document
这些命令构建分发版并将其安装在我的计算机上。我现在可以测试运行该脚本了
$ foo
bar
这可行,所以我将创建分发版 tarball
$ make dist
rm -rf App-foo-0.01
"/home/dfarrell/.plenv/versions/5.22.0/bin/perl5.22.0" "-MExtUtils::Manifest=manicopy,maniread" \
-e "manicopy(maniread(),'App-foo-0.01', 'best');"
mkdir App-foo-0.01
mkdir App-foo-0.01/lib
mkdir App-foo-0.01/lib/App
mkdir App-foo-0.01/script
Generating META.yml
Generating META.json
tar cvf App-foo-0.01.tar App-foo-0.01
App-foo-0.01/
App-foo-0.01/script/
App-foo-0.01/script/foo
App-foo-0.01/Makefile.PL
App-foo-0.01/lib/
App-foo-0.01/lib/App/
App-foo-0.01/lib/App/foo.pm
App-foo-0.01/META.json
App-foo-0.01/META.yml
App-foo-0.01/MANIFEST
App-foo-0.01/README.pod
rm -rf App-foo-0.01
gzip --best App-foo-0.01.tar
Created App-foo-0.01.tar.gz
几乎完成了,我将使用 Makefile 清理构建文件
$ make clean
rm -f \
foo.bso foo.def \
foo.exp foo.x \
blib/arch/auto/App/foo/extralibs.all \
blib/arch/auto/App/foo/extralibs.ld Makefile.aperl \
*.a *.o \
*perl.core MYMETA.json \
MYMETA.yml blibdirs.ts \
core core.*perl.*.? \
core.[0-9] core.[0-9][0-9] \
core.[0-9][0-9][0-9] core.[0-9][0-9][0-9][0-9] \
core.[0-9][0-9][0-9][0-9][0-9] libfoo.def \
mon.out perl \
perl perl.exe \
perlmain.c pm_to_blib \
pm_to_blib.ts so_locations \
tmon.out
rm -rf \
blib
mv Makefile Makefile.old > /dev/null 2>&1
上传到 CPAN
我已经有一个 PAUSE 账户,所以我可以跳过此步骤。否则,潜在的 CPAN 作者需要 注册 PAUSE 账户。不要跳过“简短描述您为何想要一个 PAUSE ID”条目 - 这是 PAUSE 管理员区分人类请求和机器人请求的方法之一,您不希望被误认为是机器人!
一旦我 登录 PAUSE,我就可以从 上传页面 上传分发版。现在我喜欢使用 CPAN::Uploader 从命令行操作。它将像这样工作
$ cpan-upload -u DFARRELL App-foo-0.01.tar.gz
cpan-upload
将提示输入我的 PAUSE 密码,并确认上传成功。
几分钟内,我将从PAUSE收到两封电子邮件:一封确认已上传的发行文件,另一封确认它已被索引。根据CPAN镜像更新索引的速度,用户现在可以在命令行中使用以下命令安装模块:
$ cpan App::foo
总结
一开始可能看起来工作量很大,但我只需创建一个存根模块和Makefile.PL,这两者都可以从其他地方复制并编辑。其他文件都是自动生成的。本文中描述的所有文件都可以在GitHub 仓库 中找到。
《中级Perl》 的第12章更详细地描述了如何创建Perl发行版。perlnewmod 是关于如何创建模块并将其准备用于CPAN的简要概述。
本文最初发布在 PerlTricks.com 上。
标签
反馈
这篇文章有什么问题吗?请在 GitHub 上打开一个issue或pull request来帮助我们。