generator.php 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344
  1. <?php
  2. global $options;
  3. $steps = 10;
  4. function user_consent($msg,$defaultyes = null,$defaultno = null)
  5. {
  6. global $options;
  7. if (isset($options["-n"]))
  8. return false;
  9. if ($defaultyes !== null && isset($options[$defaultyes]))
  10. return true;
  11. if ($defaultno !== null && isset($options[$defaultno]))
  12. return false;
  13. $response = false;
  14. do
  15. {
  16. echo "$msg (y/n)\n";
  17. $response = rtrim(fgets(STDIN));
  18. if ($response === "n" || $response == "N")
  19. return false;
  20. } while ($response !== "y" && $response !== "Y" && $response !== "");
  21. return true;
  22. }
  23. function user_prompt($msg,$default)
  24. {
  25. global $options;
  26. echo "$msg [Default: $default]\n";
  27. $response = "";
  28. if (!isset($options["-n"]))
  29. $response = rtrim(fgets(STDIN));
  30. if ($response == "")
  31. $response = $default;
  32. echo "You entered: '$response'\n";
  33. return $response;
  34. }
  35. function print_help()
  36. {
  37. $name = basename(__FILE__);
  38. echo<<<END
  39. Usage: php $name /path/folder1/main.tex /path/folder2/article.tex ... /path/folderN/paper.tex\n
  40. Generate a thesis template from the provided paper tex files and folders.
  41. The absolute minimum for a cumulative thesis is currently 3 papers first-authored and 6 in total.
  42. --force-overwrite overwrite files and folders
  43. --no-overwrite do not overwrite files and folders
  44. --no-compile-check do not perform a compile check
  45. --use-backups restore backups before making changes
  46. -n skip all prompts (implies --no-overwrite)
  47. --help display this help and exit
  48. END;
  49. exit(0);
  50. }
  51. function error_exit($msg,$usage = false)
  52. {
  53. echo "ERROR: $msg\n";
  54. if ($usage)
  55. echo "Usage: php ".basename(__FILE__)." /path/folder1/main.tex /path/folder2/article.tex ... /path/folderN/paper.tex\n";
  56. exit(-1);
  57. }
  58. function check_software()
  59. {
  60. if (!str_starts_with(shell_exec("latexmk --version"),"Latexmk,"))
  61. error_exit("latexmk not installed");
  62. if (!str_starts_with(shell_exec("pdftotext --help 2>&1"),"pdftotext version"))
  63. error_exit("pdftotext not installed");
  64. }
  65. function rrmdir($dir) {
  66. if (is_dir($dir)) {
  67. $files = scandir($dir);
  68. foreach ($files as $file)
  69. if ($file != "." && $file != "..") rrmdir("$dir/$file");
  70. rmdir($dir);
  71. }
  72. else if (file_exists($dir)) unlink($dir);
  73. }
  74. function rcopy($src, $dst) {
  75. if (file_exists($dst)) rrmdir($dst);
  76. if (is_dir($src)) {
  77. mkdir($dst);
  78. $files = scandir($src);
  79. foreach ($files as $file)
  80. if ($file != "." && $file != "..") rcopy("$src/$file", "$dst/$file");
  81. }
  82. else if (file_exists($src)) copy($src, $dst);
  83. }
  84. function rscandir($dir,$extensions = []) {
  85. $result = [];
  86. if (!str_ends_with($dir,"/"))
  87. $dir .= "/";
  88. if (str_ends_with($dir,"latex.out/"))
  89. return $result;
  90. $array = scandir($dir);
  91. foreach ($array as $item) {
  92. if (!str_starts_with($item,"."))
  93. {
  94. if (!is_dir($dir.$item))
  95. {
  96. $extension_match = true;
  97. if ($extensions != [])
  98. {
  99. $extension_match = false;
  100. foreach ($extensions as $e)
  101. {
  102. if (str_ends_with($item,"$e"))
  103. {
  104. $extension_match = true;
  105. }
  106. }
  107. }
  108. if ($extension_match)
  109. $result[] = $dir.$item;
  110. }
  111. else
  112. $result = array_merge($result, rscandir($dir.$item,$extensions));
  113. }
  114. }
  115. return $result;
  116. }
  117. function unique_targets($targets)
  118. {
  119. $parts_required = 1;
  120. $unique_targets = [];
  121. while (count($unique_targets) != count($targets))
  122. {
  123. foreach ($targets as $t)
  124. {
  125. $tparts = explode("/",$t);
  126. $tpcount = count($tparts);
  127. $tparts = array_splice($tparts,$tpcount-$parts_required,$parts_required);
  128. $t = implode("_",$tparts);
  129. if (isset($unique_targets[$t]))
  130. {
  131. $parts_required++;
  132. $unique_targets = [];
  133. break;
  134. }
  135. $unique_targets[$t] = 1;
  136. }
  137. }
  138. return array_keys($unique_targets);
  139. }
  140. function check_folders($argv)
  141. {
  142. $args = array_slice($argv,1);
  143. $sourcedirs = [];
  144. foreach ($args as $a)
  145. {
  146. if (!str_starts_with($a,"-"))
  147. $sourcedirs[] = $a;
  148. }
  149. if (count($sourcedirs) < 1)
  150. {
  151. error_exit("Too few papers. Need at least one paper to run this.",true);
  152. }
  153. if (count($sourcedirs) < 3)
  154. {
  155. echo "Warning: Too few papers. The statutes require as an absolute minimum for a cumulative thesis at least 3 first-author papers and at least 6 in total.";
  156. }
  157. if (count($sourcedirs) < 5)
  158. {
  159. echo "Warning: Few papers. Check your institute guidelines to see how many papers are recommended. Also the statutes require as an absolute minimum for a cumulative thesis at least 6 papers in total.";
  160. }
  161. $texfiles = [];
  162. for ($i = 0; $i < count($sourcedirs); $i++)
  163. {
  164. $texfiles[$i] = basename($sourcedirs[$i]);
  165. $sourcedirs[$i] = dirname($sourcedirs[$i]);
  166. }
  167. $targets = unique_targets($sourcedirs);
  168. return [$targets,$texfiles,$sourcedirs];
  169. }
  170. function check_and_copy_folders($argv)
  171. {
  172. [$targets,$texfiles,$sourcedirs] = check_folders($argv);
  173. //echo "Source -> Target Directory Mapping:\n";
  174. $mapping = array_combine($sourcedirs,$targets);
  175. //print_r($mapping);
  176. foreach ($mapping as $s => $t)
  177. {
  178. if (!file_exists($s))
  179. error_exit("$s not found");
  180. if (file_exists($t) && !user_consent("$t already exists... overwrite?","--force-overwrite","--no-overwrite"))
  181. {
  182. echo "Skipping ".$s.", ".$t." already exists...\n";
  183. }
  184. else
  185. {
  186. echo "Copying ".$s." to ".$t."...\n";
  187. rcopy($s,$t);
  188. }
  189. }
  190. return array_combine($targets,$texfiles);
  191. }
  192. function file_get_and_backup($f)
  193. {
  194. global $options;
  195. if (isset($options["--use-backups"]))
  196. {
  197. if (file_exists("$f.bak"))
  198. copy("$f.bak", $f);
  199. }
  200. $content = file_get_contents("$f");
  201. if (!file_exists("$f.bak"))
  202. file_put_contents("$f.bak",$content);
  203. return $content;
  204. }
  205. function adjust_references($papers,$extensions = [])
  206. {
  207. foreach ($papers as $d => $f)
  208. {
  209. $tex = file_get_and_backup("$d/$f");
  210. $files = rscandir($d,$extensions);
  211. foreach ($files as $file)
  212. {
  213. if (str_ends_with($file,".bib"))
  214. {
  215. $bib = file_get_and_backup($file);
  216. $bib = preg_replace("/(^\s*@\s*[a-z]+\s*\{\s*)((?!$d)\S)/i",'${1}'.$d.':${2}',$bib);
  217. $bib = preg_replace("/(\n\s*@\s*[a-z]+\s*\{\s*)((?!$d)\S)/i",'${1}'.$d.':${2}',$bib);
  218. file_put_contents($file,$bib);
  219. }
  220. else
  221. {
  222. $tex = file_get_and_backup($file);
  223. // labels of lstlistings etc
  224. $tex = preg_replace("/([\[,]\s*label\s*=\s*)((?!$d)[^\[,]+[\[,])/i",'${1}'.$d.':${2}',$tex);
  225. // normal labels
  226. $tex = preg_replace("/(\\\label\s*\{\s*)((?!$d)[^}]+\})/i",'${1}'.$d.':${2}',$tex);
  227. // cref ref autoref
  228. $refs = [];
  229. preg_match_all("/\\\(cref|ref|autoref)\s*\{\s*[^}]+\}/i",$tex,$refs);
  230. foreach ($refs[0] as $ref)
  231. {
  232. $oldref = $ref;
  233. $ref = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$ref);
  234. $ref = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$ref);
  235. $tex = str_replace($oldref,$ref,$tex);
  236. }
  237. // cite citeA citeauthor etc
  238. $cites = [];
  239. preg_match_all("/\\\([a-z]*cite[a-z]*)\s*\{\s*[^}]+\}/i",$tex,$cites);
  240. foreach ($cites[0] as $cite)
  241. {
  242. $oldcite = $cite;
  243. $cite = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$cite);
  244. $cite = preg_replace("/([{,])\s*((?!$d)[^,}]+[},])/i",'${1}'.$d.':${2}',$cite);
  245. $tex = str_replace($oldcite,$cite,$tex);
  246. }
  247. file_put_contents($file,$tex);
  248. }
  249. }
  250. }
  251. return array();
  252. }
  253. function check_options($argv)
  254. {
  255. $options = [];
  256. foreach ($argv as $a)
  257. {
  258. if (str_starts_with($a,"-"))
  259. $options[$a] = 1;
  260. if ($a == "-n")
  261. $options["--no-overwrite"] = 1;
  262. }
  263. return $options;
  264. }
  265. function compile_check($papers,$precopy = false)
  266. {
  267. if ($precopy)
  268. $papers = array_combine($papers,$papers);
  269. foreach ($papers as $p => $f)
  270. {
  271. echo "======= Paper $p -> $f START =======\n";
  272. if ($precopy)
  273. {
  274. echo "$p\n";
  275. if (strpos($p,"/") === false || str_starts_with($p,".") || !is_dir(dirname($p)))
  276. continue;
  277. $f = basename($p);
  278. $p = dirname($p);
  279. }
  280. else
  281. {
  282. shell_exec("cd $p; latexmk -c 2>/dev/null; latexmk -C 2>/dev/null; rm -f *.bbl");
  283. }
  284. $str = shell_exec("cd $p; latexmk -latexoption=\"-shell-escape\" -g -pdf $f 2>&1");
  285. $lines = explode("\n",$str);
  286. $skip = true;
  287. $failed = false;
  288. foreach($lines as $l)
  289. {
  290. if (str_starts_with($l,"Latexmk: ====List of undefined refs and citations:"))
  291. $skip = false;
  292. if ($skip)
  293. continue;
  294. if (stripos($l,"fail") !== false)
  295. $failed = true;
  296. echo "$l\n";
  297. }
  298. if ($failed || user_consent("Please check the PDF file. Are there any problems with invalid references to figures, tables or with the bibliography?","--","--no-overwrite"))
  299. error_exit("The paper did not compile properly, please fix the errors next before continuing.");
  300. echo "======= Paper $p -> $f END =======\n";
  301. }
  302. }
  303. check_software();
  304. $options = check_options($argv);
  305. if (isset($options["--help"]))
  306. print_help();
  307. echo "\n=== Step 1/$steps: Check Folders ===\n\n";
  308. [$targets,$texfiles,$sourcedirs] = check_folders($argv);
  309. echo "\n=== Step 2/$steps: Pre-Copy Compile Check ===\n\n";
  310. $targets_exist = true;
  311. foreach ($targets as $t)
  312. if (!is_dir($t))
  313. $targets_exist = false;
  314. if (isset($options["--no-compile-check"]) || $targets_exist)
  315. echo "Skipping...\n";
  316. else
  317. compile_check($argv,true);
  318. echo "\n=== Step 3/$steps: Copying Files ===\n\n";
  319. $papers = check_and_copy_folders($argv);
  320. echo "\n=== Step 4/$steps: Adjusting References (in *.bib *.tex *.tikz) ===\n\n";
  321. $bibresources = adjust_references($papers,[".bib",".tex",".tikz"]);
  322. echo "\n=== Step 5/$steps: Compile Check ===\n\n";
  323. if (isset($options["--no-compile-check"]))
  324. echo "Skipping...\n";
  325. else
  326. compile_check($papers);
  327. echo "\n=== Step 6/$steps: Generate main.tex ===\n\n";
  328. $thesis_type = user_prompt("Enter Thesis Type ","PhD Thesis");
  329. $thesis_title = user_prompt("Enter Thesis Title ","Security of TODO");
  330. $thesis_part1_title = user_prompt("Enter Introductory Part Title ","Introduction to the Security of TODO");
  331. $thesis_author = user_prompt("Enter Your Name ","Harry Potter");
  332. $thesis_date = user_prompt("Enter Prospective Defense Month", "July 1998");
  333. $thesis_institute = user_prompt("Enter Your Institute","Institute for Applied Information Processing and Communications");
  334. ob_start();
  335. require "main.tex.php";
  336. $maintex_content = ob_get_contents();
  337. ob_end_clean();
  338. if (!file_exists("main.bib"))
  339. file_put_contents("main.bib","");
  340. //if (!file_exists("main.tex") || user_consent("main.tex already exists. overwrite?")) // TODO: enable this check
  341. file_put_contents("main.tex",$maintex_content);
  342. ?>