Release 2018-04-22 "Greebo"
[dokuwiki.git] / bin / wantedpages.php
blob0240eb958e0fe2e1b73b97c22d123cf8fedd6575
1 #!/usr/bin/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 * Find wanted pages
14 class WantedPagesCLI extends CLI {
16 const DIR_CONTINUE = 1;
17 const DIR_NS = 2;
18 const DIR_PAGE = 3;
20 private $skip = false;
21 private $sort = 'wanted';
23 private $result = array();
25 /**
26 * Register options and arguments on the given $options object
28 * @param Options $options
29 * @return void
31 protected function setup(Options $options) {
32 $options->setHelp(
33 'Outputs a list of wanted pages (pages that do not exist yet) and their origin pages ' .
34 ' (the pages that are linkin to these missing pages).'
36 $options->registerArgument(
37 'namespace',
38 'The namespace to lookup. Defaults to root namespace',
39 false
42 $options->registerOption(
43 'sort',
44 'Sort by wanted or origin page',
45 's',
46 '(wanted|origin)'
49 $options->registerOption(
50 'skip',
51 'Do not show the second dimension',
52 'k'
56 /**
57 * Your main program
59 * Arguments and options have been parsed when this is run
61 * @param Options $options
62 * @return void
64 protected function main(Options $options) {
65 $args = $options->getArgs();
66 if($args) {
67 $startdir = dirname(wikiFN($args[0] . ':xxx'));
68 } else {
69 $startdir = dirname(wikiFN('xxx'));
72 $this->skip = $options->getOpt('skip');
73 $this->sort = $options->getOpt('sort');
75 $this->info("searching $startdir");
77 foreach($this->get_pages($startdir) as $page) {
78 $this->internal_links($page);
80 ksort($this->result);
81 foreach($this->result as $main => $subs) {
82 if($this->skip) {
83 print "$main\n";
84 } else {
85 $subs = array_unique($subs);
86 sort($subs);
87 foreach($subs as $sub) {
88 printf("%-40s %s\n", $main, $sub);
94 /**
95 * Determine directions of the search loop
97 * @param string $entry
98 * @param string $basepath
99 * @return int
101 protected function dir_filter($entry, $basepath) {
102 if($entry == '.' || $entry == '..') {
103 return WantedPagesCLI::DIR_CONTINUE;
105 if(is_dir($basepath . '/' . $entry)) {
106 if(strpos($entry, '_') === 0) {
107 return WantedPagesCLI::DIR_CONTINUE;
109 return WantedPagesCLI::DIR_NS;
111 if(preg_match('/\.txt$/', $entry)) {
112 return WantedPagesCLI::DIR_PAGE;
114 return WantedPagesCLI::DIR_CONTINUE;
118 * Collects recursively the pages in a namespace
120 * @param string $dir
121 * @return array
122 * @throws DokuCLI_Exception
124 protected function get_pages($dir) {
125 static $trunclen = null;
126 if(!$trunclen) {
127 global $conf;
128 $trunclen = strlen($conf['datadir'] . ':');
131 if(!is_dir($dir)) {
132 throw new DokuCLI_Exception("Unable to read directory $dir");
135 $pages = array();
136 $dh = opendir($dir);
137 while(false !== ($entry = readdir($dh))) {
138 $status = $this->dir_filter($entry, $dir);
139 if($status == WantedPagesCLI::DIR_CONTINUE) {
140 continue;
141 } else if($status == WantedPagesCLI::DIR_NS) {
142 $pages = array_merge($pages, $this->get_pages($dir . '/' . $entry));
143 } else {
144 $page = array(
145 'id' => pathID(substr($dir . '/' . $entry, $trunclen)),
146 'file' => $dir . '/' . $entry,
148 $pages[] = $page;
151 closedir($dh);
152 return $pages;
156 * Parse instructions and add the non-existing links to the result array
158 * @param array $page array with page id and file path
160 function internal_links($page) {
161 global $conf;
162 $instructions = p_get_instructions(file_get_contents($page['file']));
163 $cns = getNS($page['id']);
164 $exists = false;
165 $pid = $page['id'];
166 foreach($instructions as $ins) {
167 if($ins[0] == 'internallink' || ($conf['camelcase'] && $ins[0] == 'camelcaselink')) {
168 $mid = $ins[1][0];
169 resolve_pageid($cns, $mid, $exists);
170 if(!$exists) {
171 list($mid) = explode('#', $mid); //record pages without hashes
173 if($this->sort == 'origin') {
174 $this->result[$pid][] = $mid;
175 } else {
176 $this->result[$mid][] = $pid;
184 // Main
185 $cli = new WantedPagesCLI();
186 $cli->run();