about summary refs log tree commit diff stats
path: root/wiki/bin/dwpage.php
diff options
context:
space:
mode:
Diffstat (limited to 'wiki/bin/dwpage.php')
-rwxr-xr-xwiki/bin/dwpage.php322
1 files changed, 322 insertions, 0 deletions
diff --git a/wiki/bin/dwpage.php b/wiki/bin/dwpage.php
new file mode 100755
index 0000000..3124563
--- /dev/null
+++ b/wiki/bin/dwpage.php
@@ -0,0 +1,322 @@
+#!/usr/bin/php
+<?php
+
+use splitbrain\phpcli\CLI;
+use splitbrain\phpcli\Options;
+
+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 CLI {
+
+    protected $force = false;
+    protected $username = '';
+
+    /**
+     * Register options and arguments on the given $options object
+     *
+     * @param Options $options
+     * @return void
+     */
+    protected function setup(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 Options $options
+     * @return void
+     */
+    protected function main(Options $options) {
+        $this->force = $options->getOpt('force', false);
+        $this->username = $options->getOpt('user', $this->getUser());
+
+        $command = $options->getCmd();
+        $args = $options->getArgs();
+        switch($command) {
+            case 'checkout':
+                $wiki_id = array_shift($args);
+                $localfile = array_shift($args);
+                $this->commandCheckout($wiki_id, $localfile);
+                break;
+            case 'commit':
+                $localfile = array_shift($args);
+                $wiki_id = array_shift($args);
+                $this->commandCommit(
+                    $localfile,
+                    $wiki_id,
+                    $options->getOpt('message', ''),
+                    $options->getOpt('trivial', false)
+                );
+                break;
+            case 'lock':
+                $wiki_id = array_shift($args);
+                $this->obtainLock($wiki_id);
+                $this->success("$wiki_id locked");
+                break;
+            case 'unlock':
+                $wiki_id = array_shift($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();