318 lines
8.5 KiB
PHP
318 lines
8.5 KiB
PHP
|
#!/usr/bin/php
|
||
|
<?php
|
||
|
if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__).'/../').'/');
|
||
|
define('NOSESSION', 1);
|
||
|
require_once(DOKU_INC.'inc/init.php');
|
||
|
|
||
|
/**
|
||
|
* Checkout and commit pages from the command line while maintaining the history
|
||
|
*/
|
||
|
class PageCLI extends DokuCLI {
|
||
|
|
||
|
protected $force = false;
|
||
|
protected $username = '';
|
||
|
|
||
|
/**
|
||
|
* Register options and arguments on the given $options object
|
||
|
*
|
||
|
* @param DokuCLI_Options $options
|
||
|
* @return void
|
||
|
*/
|
||
|
protected function setup(DokuCLI_Options $options) {
|
||
|
/* global */
|
||
|
$options->registerOption(
|
||
|
'force',
|
||
|
'force obtaining a lock for the page (generally bad idea)',
|
||
|
'f'
|
||
|
);
|
||
|
$options->registerOption(
|
||
|
'user',
|
||
|
'work as this user. defaults to current CLI user',
|
||
|
'u',
|
||
|
'username'
|
||
|
);
|
||
|
$options->setHelp(
|
||
|
'Utility to help command line Dokuwiki page editing, allow '.
|
||
|
'pages to be checked out for editing then committed after changes'
|
||
|
);
|
||
|
|
||
|
/* checkout command */
|
||
|
$options->registerCommand(
|
||
|
'checkout',
|
||
|
'Checks out a file from the repository, using the wiki id and obtaining '.
|
||
|
'a lock for the page. '."\n".
|
||
|
'If a working_file is specified, this is where the page is copied to. '.
|
||
|
'Otherwise defaults to the same as the wiki page in the current '.
|
||
|
'working directory.'
|
||
|
);
|
||
|
$options->registerArgument(
|
||
|
'wikipage',
|
||
|
'The wiki page to checkout',
|
||
|
true,
|
||
|
'checkout'
|
||
|
);
|
||
|
$options->registerArgument(
|
||
|
'workingfile',
|
||
|
'How to name the local checkout',
|
||
|
false,
|
||
|
'checkout'
|
||
|
);
|
||
|
|
||
|
/* commit command */
|
||
|
$options->registerCommand(
|
||
|
'commit',
|
||
|
'Checks in the working_file into the repository using the specified '.
|
||
|
'wiki id, archiving the previous version.'
|
||
|
);
|
||
|
$options->registerArgument(
|
||
|
'workingfile',
|
||
|
'The local file to commit',
|
||
|
true,
|
||
|
'commit'
|
||
|
);
|
||
|
$options->registerArgument(
|
||
|
'wikipage',
|
||
|
'The wiki page to create or update',
|
||
|
true,
|
||
|
'commit'
|
||
|
);
|
||
|
$options->registerOption(
|
||
|
'message',
|
||
|
'Summary describing the change (required)',
|
||
|
'm',
|
||
|
'summary',
|
||
|
'commit'
|
||
|
);
|
||
|
$options->registerOption(
|
||
|
'trivial',
|
||
|
'minor change',
|
||
|
't',
|
||
|
false,
|
||
|
'commit'
|
||
|
);
|
||
|
|
||
|
/* lock command */
|
||
|
$options->registerCommand(
|
||
|
'lock',
|
||
|
'Obtains or updates a lock for a wiki page'
|
||
|
);
|
||
|
$options->registerArgument(
|
||
|
'wikipage',
|
||
|
'The wiki page to lock',
|
||
|
true,
|
||
|
'lock'
|
||
|
);
|
||
|
|
||
|
/* unlock command */
|
||
|
$options->registerCommand(
|
||
|
'unlock',
|
||
|
'Removes a lock for a wiki page.'
|
||
|
);
|
||
|
$options->registerArgument(
|
||
|
'wikipage',
|
||
|
'The wiki page to unlock',
|
||
|
true,
|
||
|
'unlock'
|
||
|
);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Your main program
|
||
|
*
|
||
|
* Arguments and options have been parsed when this is run
|
||
|
*
|
||
|
* @param DokuCLI_Options $options
|
||
|
* @return void
|
||
|
*/
|
||
|
protected function main(DokuCLI_Options $options) {
|
||
|
$this->force = $options->getOpt('force', false);
|
||
|
$this->username = $options->getOpt('user', $this->getUser());
|
||
|
|
||
|
$command = $options->getCmd();
|
||
|
switch($command) {
|
||
|
case 'checkout':
|
||
|
$wiki_id = array_shift($options->args);
|
||
|
$localfile = array_shift($options->args);
|
||
|
$this->commandCheckout($wiki_id, $localfile);
|
||
|
break;
|
||
|
case 'commit':
|
||
|
$localfile = array_shift($options->args);
|
||
|
$wiki_id = array_shift($options->args);
|
||
|
$this->commandCommit(
|
||
|
$localfile,
|
||
|
$wiki_id,
|
||
|
$options->getOpt('message', ''),
|
||
|
$options->getOpt('trivial', false)
|
||
|
);
|
||
|
break;
|
||
|
case 'lock':
|
||
|
$wiki_id = array_shift($options->args);
|
||
|
$this->obtainLock($wiki_id);
|
||
|
$this->success("$wiki_id locked");
|
||
|
break;
|
||
|
case 'unlock':
|
||
|
$wiki_id = array_shift($options->args);
|
||
|
$this->clearLock($wiki_id);
|
||
|
$this->success("$wiki_id unlocked");
|
||
|
break;
|
||
|
default:
|
||
|
echo $options->help();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check out a file
|
||
|
*
|
||
|
* @param string $wiki_id
|
||
|
* @param string $localfile
|
||
|
*/
|
||
|
protected function commandCheckout($wiki_id, $localfile) {
|
||
|
global $conf;
|
||
|
|
||
|
$wiki_id = cleanID($wiki_id);
|
||
|
$wiki_fn = wikiFN($wiki_id);
|
||
|
|
||
|
if(!file_exists($wiki_fn)) {
|
||
|
$this->fatal("$wiki_id does not yet exist");
|
||
|
}
|
||
|
|
||
|
if(empty($localfile)) {
|
||
|
$localfile = getcwd().'/'.utf8_basename($wiki_fn);
|
||
|
}
|
||
|
|
||
|
if(!file_exists(dirname($localfile))) {
|
||
|
$this->fatal("Directory ".dirname($localfile)." does not exist");
|
||
|
}
|
||
|
|
||
|
if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
|
||
|
$this->fatal("Attempt to check out file into data directory - not allowed");
|
||
|
}
|
||
|
|
||
|
$this->obtainLock($wiki_id);
|
||
|
|
||
|
if(!copy($wiki_fn, $localfile)) {
|
||
|
$this->clearLock($wiki_id);
|
||
|
$this->fatal("Unable to copy $wiki_fn to $localfile");
|
||
|
}
|
||
|
|
||
|
$this->success("$wiki_id > $localfile");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Save a file as a new page revision
|
||
|
*
|
||
|
* @param string $localfile
|
||
|
* @param string $wiki_id
|
||
|
* @param string $message
|
||
|
* @param bool $minor
|
||
|
*/
|
||
|
protected function commandCommit($localfile, $wiki_id, $message, $minor) {
|
||
|
$wiki_id = cleanID($wiki_id);
|
||
|
$message = trim($message);
|
||
|
|
||
|
if(!file_exists($localfile)) {
|
||
|
$this->fatal("$localfile does not exist");
|
||
|
}
|
||
|
|
||
|
if(!is_readable($localfile)) {
|
||
|
$this->fatal("Cannot read from $localfile");
|
||
|
}
|
||
|
|
||
|
if(!$message) {
|
||
|
$this->fatal("Summary message required");
|
||
|
}
|
||
|
|
||
|
$this->obtainLock($wiki_id);
|
||
|
|
||
|
saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor);
|
||
|
|
||
|
$this->clearLock($wiki_id);
|
||
|
|
||
|
$this->success("$localfile > $wiki_id");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Lock the given page or exit
|
||
|
*
|
||
|
* @param string $wiki_id
|
||
|
*/
|
||
|
protected function obtainLock($wiki_id) {
|
||
|
if($this->force) $this->deleteLock($wiki_id);
|
||
|
|
||
|
$_SERVER['REMOTE_USER'] = $this->username;
|
||
|
|
||
|
if(checklock($wiki_id)) {
|
||
|
$this->error("Page $wiki_id is already locked by another user");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
lock($wiki_id);
|
||
|
|
||
|
if(checklock($wiki_id)) {
|
||
|
$this->error("Unable to obtain lock for $wiki_id ");
|
||
|
var_dump(checklock($wiki_id));
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Clear the lock on the given page
|
||
|
*
|
||
|
* @param string $wiki_id
|
||
|
*/
|
||
|
protected function clearLock($wiki_id) {
|
||
|
if($this->force) $this->deleteLock($wiki_id);
|
||
|
|
||
|
$_SERVER['REMOTE_USER'] = $this->username;
|
||
|
if(checklock($wiki_id)) {
|
||
|
$this->error("Page $wiki_id is locked by another user");
|
||
|
exit(1);
|
||
|
}
|
||
|
|
||
|
unlock($wiki_id);
|
||
|
|
||
|
if(file_exists(wikiLockFN($wiki_id))) {
|
||
|
$this->error("Unable to clear lock for $wiki_id");
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Forcefully remove a lock on the page given
|
||
|
*
|
||
|
* @param string $wiki_id
|
||
|
*/
|
||
|
protected function deleteLock($wiki_id) {
|
||
|
$wikiLockFN = wikiLockFN($wiki_id);
|
||
|
|
||
|
if(file_exists($wikiLockFN)) {
|
||
|
if(!unlink($wikiLockFN)) {
|
||
|
$this->error("Unable to delete $wikiLockFN");
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the current user's username from the environment
|
||
|
*
|
||
|
* @return string
|
||
|
*/
|
||
|
protected function getUser() {
|
||
|
$user = getenv('USER');
|
||
|
if(empty ($user)) {
|
||
|
$user = getenv('USERNAME');
|
||
|
} else {
|
||
|
return $user;
|
||
|
}
|
||
|
if(empty ($user)) {
|
||
|
$user = 'admin';
|
||
|
}
|
||
|
return $user;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
// Main
|
||
|
$cli = new PageCLI();
|
||
|
$cli->run();
|