PageRenderTime 45ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/bin/dwpage.php

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