[ Index ]

PHP Cross Reference of DokuWiki

title

Body

[close]

/bin/ -> dwpage.php (source)

   1  #!/usr/bin/env php
   2  <?php
   3  
   4  use splitbrain\phpcli\CLI;
   5  use splitbrain\phpcli\Options;
   6  
   7  if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
   8  define('NOSESSION', 1);
   9  require_once (DOKU_INC . 'inc/init.php');
  10  
  11  /**
  12   * Checkout and commit pages from the command line while maintaining the history
  13   */
  14  class PageCLI extends CLI {
  15  
  16      protected $force = false;
  17      protected $username = '';
  18  
  19      /**
  20       * Register options and arguments on the given $options object
  21       *
  22       * @param Options $options
  23       * @return void
  24       */
  25      protected function setup(Options $options) {
  26          /* global */
  27          $options->registerOption(
  28              'force',
  29              'force obtaining a lock for the page (generally bad idea)',
  30              'f'
  31          );
  32          $options->registerOption(
  33              'user',
  34              'work as this user. defaults to current CLI user',
  35              'u',
  36              'username'
  37          );
  38          $options->setHelp(
  39              'Utility to help command line Dokuwiki page editing, allow ' .
  40              'pages to be checked out for editing then committed after changes'
  41          );
  42  
  43          /* checkout command */
  44          $options->registerCommand(
  45              'checkout',
  46              'Checks out a file from the repository, using the wiki id and obtaining ' .
  47              'a lock for the page. ' . "\n" .
  48              'If a working_file is specified, this is where the page is copied to. ' .
  49              'Otherwise defaults to the same as the wiki page in the current ' .
  50              'working directory.'
  51          );
  52          $options->registerArgument(
  53              'wikipage',
  54              'The wiki page to checkout',
  55              true,
  56              'checkout'
  57          );
  58          $options->registerArgument(
  59              'workingfile',
  60              'How to name the local checkout',
  61              false,
  62              'checkout'
  63          );
  64  
  65          /* commit command */
  66          $options->registerCommand(
  67              'commit',
  68              'Checks in the working_file into the repository using the specified ' .
  69              'wiki id, archiving the previous version.'
  70          );
  71          $options->registerArgument(
  72              'workingfile',
  73              'The local file to commit',
  74              true,
  75              'commit'
  76          );
  77          $options->registerArgument(
  78              'wikipage',
  79              'The wiki page to create or update',
  80              true,
  81              'commit'
  82          );
  83          $options->registerOption(
  84              'message',
  85              'Summary describing the change (required)',
  86              'm',
  87              'summary',
  88              'commit'
  89          );
  90          $options->registerOption(
  91              'trivial',
  92              'minor change',
  93              't',
  94              false,
  95              'commit'
  96          );
  97  
  98          /* lock command */
  99          $options->registerCommand(
 100              'lock',
 101              'Obtains or updates a lock for a wiki page'
 102          );
 103          $options->registerArgument(
 104              'wikipage',
 105              'The wiki page to lock',
 106              true,
 107              'lock'
 108          );
 109  
 110          /* unlock command */
 111          $options->registerCommand(
 112              'unlock',
 113              'Removes a lock for a wiki page.'
 114          );
 115          $options->registerArgument(
 116              'wikipage',
 117              'The wiki page to unlock',
 118              true,
 119              'unlock'
 120          );
 121  
 122          /* gmeta command */
 123          $options->registerCommand(
 124              'getmeta',
 125              'Prints metadata value for a page to stdout.'
 126          );
 127          $options->registerArgument(
 128              'wikipage',
 129              'The wiki page to get the metadata for',
 130              true,
 131              'getmeta'
 132          );
 133          $options->registerArgument(
 134              'key',
 135              'The name of the metadata item to be retrieved.' . "\n" .
 136              'If empty, an array of all the metadata items is returned.' ."\n" .
 137              'For retrieving items that are stored in sub-arrays, separate the ' .
 138              'keys of the different levels by spaces, in quotes, eg "date modified".',
 139              false,
 140              'getmeta'
 141          );
 142      }
 143  
 144      /**
 145       * Your main program
 146       *
 147       * Arguments and options have been parsed when this is run
 148       *
 149       * @param Options $options
 150       * @return void
 151       */
 152      protected function main(Options $options) {
 153          $this->force = $options->getOpt('force', false);
 154          $this->username = $options->getOpt('user', $this->getUser());
 155  
 156          $command = $options->getCmd();
 157          $args = $options->getArgs();
 158          switch($command) {
 159              case 'checkout':
 160                  $wiki_id = array_shift($args);
 161                  $localfile = array_shift($args);
 162                  $this->commandCheckout($wiki_id, $localfile);
 163                  break;
 164              case 'commit':
 165                  $localfile = array_shift($args);
 166                  $wiki_id = array_shift($args);
 167                  $this->commandCommit(
 168                      $localfile,
 169                      $wiki_id,
 170                      $options->getOpt('message', ''),
 171                      $options->getOpt('trivial', false)
 172                  );
 173                  break;
 174              case 'lock':
 175                  $wiki_id = array_shift($args);
 176                  $this->obtainLock($wiki_id);
 177                  $this->success("$wiki_id locked");
 178                  break;
 179              case 'unlock':
 180                  $wiki_id = array_shift($args);
 181                  $this->clearLock($wiki_id);
 182                  $this->success("$wiki_id unlocked");
 183                  break;
 184              case 'getmeta':
 185                  $wiki_id = array_shift($args);
 186                  $key = trim(array_shift($args));
 187                  $meta = p_get_metadata($wiki_id, $key, METADATA_RENDER_UNLIMITED);
 188                  echo trim(json_encode($meta, JSON_PRETTY_PRINT));
 189                  echo "\n";
 190                  break;
 191              default:
 192                  echo $options->help();
 193          }
 194      }
 195  
 196      /**
 197       * Check out a file
 198       *
 199       * @param string $wiki_id
 200       * @param string $localfile
 201       */
 202      protected function commandCheckout($wiki_id, $localfile) {
 203          global $conf;
 204  
 205          $wiki_id = cleanID($wiki_id);
 206          $wiki_fn = wikiFN($wiki_id);
 207  
 208          if(!file_exists($wiki_fn)) {
 209              $this->fatal("$wiki_id does not yet exist");
 210          }
 211  
 212          if(empty($localfile)) {
 213              $localfile = getcwd() . '/' . \dokuwiki\Utf8\PhpString::basename($wiki_fn);
 214          }
 215  
 216          if(!file_exists(dirname($localfile))) {
 217              $this->fatal("Directory " . dirname($localfile) . " does not exist");
 218          }
 219  
 220          if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
 221              $this->fatal("Attempt to check out file into data directory - not allowed");
 222          }
 223  
 224          $this->obtainLock($wiki_id);
 225  
 226          if(!copy($wiki_fn, $localfile)) {
 227              $this->clearLock($wiki_id);
 228              $this->fatal("Unable to copy $wiki_fn to $localfile");
 229          }
 230  
 231          $this->success("$wiki_id > $localfile");
 232      }
 233  
 234      /**
 235       * Save a file as a new page revision
 236       *
 237       * @param string $localfile
 238       * @param string $wiki_id
 239       * @param string $message
 240       * @param bool $minor
 241       */
 242      protected function commandCommit($localfile, $wiki_id, $message, $minor) {
 243          $wiki_id = cleanID($wiki_id);
 244          $message = trim($message);
 245  
 246          if(!file_exists($localfile)) {
 247              $this->fatal("$localfile does not exist");
 248          }
 249  
 250          if(!is_readable($localfile)) {
 251              $this->fatal("Cannot read from $localfile");
 252          }
 253  
 254          if(!$message) {
 255              $this->fatal("Summary message required");
 256          }
 257  
 258          $this->obtainLock($wiki_id);
 259  
 260          saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor);
 261  
 262          $this->clearLock($wiki_id);
 263  
 264          $this->success("$localfile > $wiki_id");
 265      }
 266  
 267      /**
 268       * Lock the given page or exit
 269       *
 270       * @param string $wiki_id
 271       */
 272      protected function obtainLock($wiki_id) {
 273          if($this->force) $this->deleteLock($wiki_id);
 274  
 275          $_SERVER['REMOTE_USER'] = $this->username;
 276  
 277          if(checklock($wiki_id)) {
 278              $this->error("Page $wiki_id is already locked by another user");
 279              exit(1);
 280          }
 281  
 282          lock($wiki_id);
 283  
 284          if(checklock($wiki_id)) {
 285              $this->error("Unable to obtain lock for $wiki_id ");
 286              var_dump(checklock($wiki_id));
 287              exit(1);
 288          }
 289      }
 290  
 291      /**
 292       * Clear the lock on the given page
 293       *
 294       * @param string $wiki_id
 295       */
 296      protected function clearLock($wiki_id) {
 297          if($this->force) $this->deleteLock($wiki_id);
 298  
 299          $_SERVER['REMOTE_USER'] = $this->username;
 300          if(checklock($wiki_id)) {
 301              $this->error("Page $wiki_id is locked by another user");
 302              exit(1);
 303          }
 304  
 305          unlock($wiki_id);
 306  
 307          if(file_exists(wikiLockFN($wiki_id))) {
 308              $this->error("Unable to clear lock for $wiki_id");
 309              exit(1);
 310          }
 311      }
 312  
 313      /**
 314       * Forcefully remove a lock on the page given
 315       *
 316       * @param string $wiki_id
 317       */
 318      protected function deleteLock($wiki_id) {
 319          $wikiLockFN = wikiLockFN($wiki_id);
 320  
 321          if(file_exists($wikiLockFN)) {
 322              if(!unlink($wikiLockFN)) {
 323                  $this->error("Unable to delete $wikiLockFN");
 324                  exit(1);
 325              }
 326          }
 327      }
 328  
 329      /**
 330       * Get the current user's username from the environment
 331       *
 332       * @return string
 333       */
 334      protected function getUser() {
 335          $user = getenv('USER');
 336          if(empty ($user)) {
 337              $user = getenv('USERNAME');
 338          } else {
 339              return $user;
 340          }
 341          if(empty ($user)) {
 342              $user = 'admin';
 343          }
 344          return $user;
 345      }
 346  }
 347  
 348  // Main
 349  $cli = new PageCLI();
 350  $cli->run();