Merge pull request #3940 from dokuwiki-translate/lang_update_607_1680627612
[dokuwiki.git] / bin / dwpage.php
bloba640fa78305c86dad40c33aef9a8b171ec15c25f
1 #!/usr/bin/env php
2 <?php
4 use splitbrain\phpcli\CLI;
5 use splitbrain\phpcli\Options;
7 if(!defined('DOKU_INC')) define('DOKU_INC', realpath(dirname(__FILE__) . '/../') . '/');
8 define('NOSESSION', 1);
9 require_once(DOKU_INC . 'inc/init.php');
11 /**
12 * Checkout and commit pages from the command line while maintaining the history
14 class PageCLI extends CLI {
16 protected $force = false;
17 protected $username = '';
19 /**
20 * Register options and arguments on the given $options object
22 * @param Options $options
23 * @return void
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'
32 $options->registerOption(
33 'user',
34 'work as this user. defaults to current CLI user',
35 'u',
36 'username'
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'
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.'
52 $options->registerArgument(
53 'wikipage',
54 'The wiki page to checkout',
55 true,
56 'checkout'
58 $options->registerArgument(
59 'workingfile',
60 'How to name the local checkout',
61 false,
62 'checkout'
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.'
71 $options->registerArgument(
72 'workingfile',
73 'The local file to commit',
74 true,
75 'commit'
77 $options->registerArgument(
78 'wikipage',
79 'The wiki page to create or update',
80 true,
81 'commit'
83 $options->registerOption(
84 'message',
85 'Summary describing the change (required)',
86 'm',
87 'summary',
88 'commit'
90 $options->registerOption(
91 'trivial',
92 'minor change',
93 't',
94 false,
95 'commit'
98 /* lock command */
99 $options->registerCommand(
100 'lock',
101 'Obtains or updates a lock for a wiki page'
103 $options->registerArgument(
104 'wikipage',
105 'The wiki page to lock',
106 true,
107 'lock'
110 /* unlock command */
111 $options->registerCommand(
112 'unlock',
113 'Removes a lock for a wiki page.'
115 $options->registerArgument(
116 'wikipage',
117 'The wiki page to unlock',
118 true,
119 'unlock'
122 /* gmeta command */
123 $options->registerCommand(
124 'getmeta',
125 'Prints metadata value for a page to stdout.'
127 $options->registerArgument(
128 'wikipage',
129 'The wiki page to get the metadata for',
130 true,
131 'getmeta'
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'
145 * Your main program
147 * Arguments and options have been parsed when this is run
149 * @param Options $options
150 * @return void
152 protected function main(Options $options) {
153 $this->force = $options->getOpt('force', false);
154 $this->username = $options->getOpt('user', $this->getUser());
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)
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();
197 * Check out a file
199 * @param string $wiki_id
200 * @param string $localfile
202 protected function commandCheckout($wiki_id, $localfile) {
203 global $conf;
205 $wiki_id = cleanID($wiki_id);
206 $wiki_fn = wikiFN($wiki_id);
208 if(!file_exists($wiki_fn)) {
209 $this->fatal("$wiki_id does not yet exist");
212 if(empty($localfile)) {
213 $localfile = getcwd() . '/' . \dokuwiki\Utf8\PhpString::basename($wiki_fn);
216 if(!file_exists(dirname($localfile))) {
217 $this->fatal("Directory " . dirname($localfile) . " does not exist");
220 if(stristr(realpath(dirname($localfile)), realpath($conf['datadir'])) !== false) {
221 $this->fatal("Attempt to check out file into data directory - not allowed");
224 $this->obtainLock($wiki_id);
226 if(!copy($wiki_fn, $localfile)) {
227 $this->clearLock($wiki_id);
228 $this->fatal("Unable to copy $wiki_fn to $localfile");
231 $this->success("$wiki_id > $localfile");
235 * Save a file as a new page revision
237 * @param string $localfile
238 * @param string $wiki_id
239 * @param string $message
240 * @param bool $minor
242 protected function commandCommit($localfile, $wiki_id, $message, $minor) {
243 $wiki_id = cleanID($wiki_id);
244 $message = trim($message);
246 if(!file_exists($localfile)) {
247 $this->fatal("$localfile does not exist");
250 if(!is_readable($localfile)) {
251 $this->fatal("Cannot read from $localfile");
254 if(!$message) {
255 $this->fatal("Summary message required");
258 $this->obtainLock($wiki_id);
260 saveWikiText($wiki_id, file_get_contents($localfile), $message, $minor);
262 $this->clearLock($wiki_id);
264 $this->success("$localfile > $wiki_id");
268 * Lock the given page or exit
270 * @param string $wiki_id
272 protected function obtainLock($wiki_id) {
273 if($this->force) $this->deleteLock($wiki_id);
275 $_SERVER['REMOTE_USER'] = $this->username;
277 if(checklock($wiki_id)) {
278 $this->error("Page $wiki_id is already locked by another user");
279 exit(1);
282 lock($wiki_id);
284 if(checklock($wiki_id)) {
285 $this->error("Unable to obtain lock for $wiki_id ");
286 var_dump(checklock($wiki_id));
287 exit(1);
292 * Clear the lock on the given page
294 * @param string $wiki_id
296 protected function clearLock($wiki_id) {
297 if($this->force) $this->deleteLock($wiki_id);
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);
305 unlock($wiki_id);
307 if(file_exists(wikiLockFN($wiki_id))) {
308 $this->error("Unable to clear lock for $wiki_id");
309 exit(1);
314 * Forcefully remove a lock on the page given
316 * @param string $wiki_id
318 protected function deleteLock($wiki_id) {
319 $wikiLockFN = wikiLockFN($wiki_id);
321 if(file_exists($wikiLockFN)) {
322 if(!unlink($wikiLockFN)) {
323 $this->error("Unable to delete $wikiLockFN");
324 exit(1);
330 * Get the current user's username from the environment
332 * @return string
334 protected function getUser() {
335 $user = getenv('USER');
336 if(empty ($user)) {
337 $user = getenv('USERNAME');
338 } else {
339 return $user;
341 if(empty ($user)) {
342 $user = 'admin';
344 return $user;
348 // Main
349 $cli = new PageCLI();
350 $cli->run();