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。