Perlwikibot/clean sandbox.pl
clean_sandbox.pl 是一个使用未发布的 perlwikibot 3.0 版本的简单脚本。它只是通过提交包含一些标准文本的编辑来清理维基的 沙盒,覆盖之前存在的任何内容。
#!/usr/bin/perl
use strict;
use warnings;
use utf8;
use Carp;
use Getopt::Long;
use Pod::Usage;
use Config::General qw(ParseConfig);
use MediaWiki::Bot 3.0.0;
my $VERSION = '0.0.1';
在这里,我们使用两个应该被认为是必须的pragma:strict 和 warnings。这些是使你成为更好的程序员的工具,因为它们迫使你遵循一些规则。
我们还使用 Getopt::Long 从用户那里获取命令行选项。这极大地简化了解析 @ARGV - 你不应该自己尝试这样做。始终使用 Perl 模块 - Getopt::Long 是其中之一,但还有其他模块。
Pod::Usage 允许我们使用 Perl 的 POD 标记嵌入在源代码中,为用户提供 man 样式的文档。
Config::General 允许我们轻松解析配置文件。同样,还有其他模块,但这个模块提供了一些我们将要使用的功能,例如 heredocs。
最后,我们需要 MediaWiki::Bot
版本 3.0.0 或更高版本。3.0.0 仍在开发中,因此方法调用可能会发生变化。
$VERSION 字符串将在稍后使用,并且可能被其他使用此文件的脚本使用,就像我们对 MediaWiki::Bot 所做的那样。
=head1 NAME
clean_sandbox.pl - Cleans a wiki's sandbox
=head1 SYNOPSIS
clean_sandbox.pl --wiki=meta --summary="Cleaning the sandbox"
Options:
--help Opens this man page and exit
--version Print version information and exit
--dry-run Do everything but edit
--debug Print debug output
--wiki Sets which wiki to use
--text Sets what text to use
--page Sets what page to edit
--summary Sets an edit summary
--username Sets a non-default username
--password Request a password prompt
=head1 OPTIONS
=cut
在这里,我们为用户提供一些文档。这使用 POD(参见 perldoc perlpod
),并且如果用户提供 --help 选项,它将被解析并显示给用户。该文件中包含更多 POD,但未包含在本页面中。
my $help;
my $version;
my $dry_run;
my $debug;
my $wiki;
my $text;
my $page;
my $summary;
my $username;
my $password;
GetOptions(
'help|h|?' => \$help,
'version|v' => \$version,
'dry-run' => \$dry_run,
'debug|verbose' => \$debug,
'wiki=s' => \$wiki,
'text=s' => \$text,
'page=s' => \$page,
'summary=s' => \$summary,
'username=s' => \$username,
'password:s' => \$password, # We can ask for it interactively!
);
这声明了所有命令行选项的变量,并让 Getopt::Long 解析 @ARGV 并为我们分配给这些变量。这比手动尝试这样做要好得多。
在左侧,是选项名称以及任何别名。例如,help|h|? 提供了一个名称(help)和两个别名(h 和 ?)。命令行上该选项的存在被分配给 $help。其他选项,例如 dry-run 只有规范名称。还有一些选项需要一个必填参数,例如 wiki=s。 = 表示该参数是必填的;s 表示它是字符串。最后,password 具有一个由 :s 表示的可选字符串参数。该选项的参数是可选的,因为我们更喜欢交互式地提示输入密码。命令行参数对系统上的所有用户都是可见的,因此应避免这样做。
if ($version) {
require File::Basename;
my $script = File::Basename::basename($0);
print "$script version $VERSION\n" and exit;
}
如果用户在命令行上指定了 --version,则 $version 将为真。我们打印一条简单的消息,其中包含我们上面声明的版本字符串,然后退出。
if (defined($password)) { # I think this is wrong, actually... we'll prompt interactively even if they do --password pass. Should check defined and false.
require Term::ReadKey;
print "[clean_sandbox.pl] password: ";
Term::ReadKey::ReadMode('noecho'); # Don't show the password
$password = Term::ReadKey::ReadLine(0);
Term::ReadKey::ReadMode('restore'); # Don't bork their terminal
}
如果在命令行上指定了 --password,我们会交互式地提示输入密码。为此,我们可以使用 Term::ReadKey,它提供了几个对该任务有用的方法。首先,请注意 require 在运行时被评估,而 use 在编译时被评估,即使它永远不会运行。 use 还会将默认方法 import() 到当前上下文中,而 require 不会。我们可以自己 import(),但在这种情况下,不这样做也很容易。
我们将使用一种标准方法来读取密码。首先,我们显示提示,然后将终端设置为“noecho”读取模式。这意味着用户的击键不会在屏幕上显示任何内容。接下来,我们读取用户的输入并将其分配给 $password。以前,这个变量只是告诉我们命令行上是否指定了 --password - 现在它包含密码的文本。最后,我们恢复用户终端的原始特性。如果我们没有这样做,它将继续在“noecho”模式下运行,用户不会喜欢这样。
if (!$username or !$password or !$wiki) {
warn 'Reading config/main.conf' if $debug;
my %main = ParseConfig (
-ConfigFile => 'config/main.conf',
-LowerCaseNames => 1,
-AutoTrue => 1,
-UTF8 => 1,
);
$username = $main{'default'} unless $username; warn "Using $username" if $debug;
die "I can't figure out what account to use! Try setting default in config/main.conf, or use --username" unless $username;
die "There's no block for $username and you didn't specify enough data on the command line to continue" unless $main{'bot'}{$username};
$password = $main{'bot'}{$username}{'password'} if (!$password);
warn "Setting \$password" if $debug;
$wiki = $main{'bot'}{$username}{'wiki'} unless $wiki;
warn "Setting \$wiki to $wiki" if $debug;
}
如果我们还没有用户名、密码和维基,那么我们应该从配置文件中读取它们。 Config::General 提供 ParseConfig 方法来执行此操作。
我们提供给它文件名(相对于当前文件)和一些选项。 UTF8 很重要,因为该文件在许多情况下可以包含 UTF8 字符,并且确实会包含 UTF8 字符。示例配置文件
default = Mike's bot account <bot Mike's bot account> password = fake password wiki = enwikibooks </bot>
当 Config::General 读取此文件时,它会创建一个 哈希 来表示数据。一旦我们有了那个哈希,我们就会尝试获取我们缺少的数据,如果我们无法完成,就会警告用户。
my $bot = MediaWiki::Bot->new(); # Create a default object so we can query sitematrix if need be
$bot->{'debug'} = $debug;
请注意,一些 warn 语句取决于 $debug。这是另一个命令行标志,要求脚本输出有关其操作的更多信息,以简化调试。我们要求 MediaWiki::Bot 也这样做。
my $domain;
if (!$text or !$page or !$summary) {
warn 'Reading config/clean_sandbox.conf' if $debug;
my %conf = ParseConfig (
-ConfigFile => 'config/clean_sandbox.conf',
-LowerCaseNames => 1,
-UTF8 => 1,
);
if ($wiki =~ m/\w\.\w/) {
$domain = $wiki;
$wiki = $bot->domain_to_db($wiki);
}
%conf = %{ $conf{$wiki} }; # Keep just the part we want.
$text = $conf{'text'} unless $text; warn "Setting \$text to $text" if $debug;
$page = $conf{'page'} unless $page; warn "Setting \$page to $page" if $debug;
$summary = $conf{'summary'} unless $summary; warn "Setting \$summary to $summary" if $debug;
}
在这里,我们使用 Config::General::ParseConfig 来解析另一个配置文件。该文件包含许多维基的数据,包括它们的沙盒位置、应该放在沙盒上的标准文本以及他们想要使用的编辑摘要。这很有用,因为有些机器人操作员可能不会说他们机器人在哪里清理沙盒的语言。这也意味着他们不必每次都指定 --page "Project:Sandbox" --text "{{/Don't edit this line}}\n<!--Practice your editing here-->" --summary "Bot: cleaning sandbox"
。这些数据可以存储在配置文件中。
由于此文件包含许多维基的数据,而我们不需要所有数据,因此我们丢弃了大部分数据。 ParseConfig 创建一个大型哈希,但我们只保留了我们实际想要编辑的维基的相关部分。然后,我们找到我们缺少的任何数据。
$domain = $bot->db_to_domain($wiki) if ($wiki !~ m/\w\.\w/);
$bot = MediaWiki::Bot->new({
host => $domain,
login_data => { username => $username, password => $password },
});
与早期版本的 Perlwikibot 不同,3.0 将自动处理许多事情,以简化脚本编写。在这里,我们创建一个新的机器人对象,该对象将自动为我们登录和配置。有关 new() 构造函数的详细信息,请查看 MediaWiki::Bot 的 POD 文档。
die <<"END" if $dry_run;
This is where we would attempt the following edit:
\$bot->edit({
page => $page,
text => $text,
summary => $summary
is_minor => 1,
});
on $domain
END
这是一个 heredoc(heredoc) - 它允许我们轻松打印多行字符串。如果用户在命令行上指定了 --dry-run,我们想执行到这一点的所有操作,但实际上不进行编辑。因此,如果 $dry_run 被设置,我们将打印出这个多行字符串,显示会发生什么,然后退出。<<"END" 的 << 部分告诉 Perl 之后是一个 heredoc;END 告诉 Perl 要查找什么分隔符来知道 heredoc 已结束;双引号告诉 Perl 我们希望它是一个插入字符串。
warn "Editing..." if $debug;
$bot->edit({
page => $page,
text => $text,
summary => $summary
is_minor => 1,
}) or die "Couldn't edit";
这实际上通过调用 MediaWiki::Bot 的 edit() 方法并传递页面名称、要放置的文本、编辑摘要以及它是一个次要编辑来进行编辑。有关 edit() 的详细信息,请查看 POD。