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