plessc 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/php -q
  2. <?php
  3. // Command line utility to compile LESS to STDOUT
  4. // Leaf Corcoran <leafot@gmail.com>, 2012
  5. $exe = array_shift($argv); // remove filename
  6. $HELP = <<<EOT
  7. Usage: $exe [options] input-file [output-file]
  8. Options include:
  9. -h, --help Show this message
  10. -v Print the version
  11. -f=format Set the output format, includes "default", "compressed"
  12. -c Keep /* */ comments in output
  13. -r Read from STDIN instead of input-file
  14. -w Watch input-file, and compile to output-file if it is changed
  15. -T Dump formatted parse tree
  16. -X Dump raw parse tree
  17. EOT;
  18. $opts = getopt('hvrwncXTf:', array('help'));
  19. while (count($argv) > 0 && preg_match('/^-([-hvrwncXT]$|[f]=)/', $argv[0])) {
  20. array_shift($argv);
  21. }
  22. function has() {
  23. global $opts;
  24. foreach (func_get_args() as $arg) {
  25. if (isset($opts[$arg])) return true;
  26. }
  27. return false;
  28. }
  29. if (has("h", "help")) {
  30. exit($HELP);
  31. }
  32. error_reporting(E_ALL);
  33. $path = realpath(dirname(__FILE__)).'/';
  34. require $path."lessc.inc.php";
  35. $VERSION = lessc::$VERSION;
  36. $fa = "Fatal Error: ";
  37. function err($msg) {
  38. fwrite(STDERR, $msg."\n");
  39. }
  40. if (php_sapi_name() != "cli") {
  41. err($fa.$argv[0]." must be run in the command line.");
  42. exit(1);
  43. }
  44. function make_less($fname = null) {
  45. global $opts;
  46. $l = new lessc($fname);
  47. if (has("f")) {
  48. $format = $opts["f"];
  49. if ($format != "default") $l->setFormatter($format);
  50. }
  51. if (has("c")) {
  52. $l->setPreserveComments(true);
  53. }
  54. return $l;
  55. }
  56. function process($data, $import = null) {
  57. global $fa;
  58. $l = make_less();
  59. if ($import) $l->importDir = $import;
  60. try {
  61. echo $l->parse($data);
  62. exit(0);
  63. } catch (exception $ex) {
  64. err($fa."\n".str_repeat('=', 20)."\n".
  65. $ex->getMessage());
  66. exit(1);
  67. }
  68. }
  69. if (has("v")) {
  70. exit($VERSION."\n");
  71. }
  72. if (has("r")) {
  73. if (!empty($argv)) {
  74. $data = $argv[0];
  75. } else {
  76. $data = "";
  77. while (!feof(STDIN)) {
  78. $data .= fread(STDIN, 8192);
  79. }
  80. }
  81. exit(process($data));
  82. }
  83. if (has("w")) {
  84. // need two files
  85. if (!is_file($in = array_shift($argv)) ||
  86. null == $out = array_shift($argv))
  87. {
  88. err($fa.$exe." -w infile outfile");
  89. exit(1);
  90. }
  91. echo "Watching ".$in.
  92. (has("n") ? ' with notifications' : '').
  93. ", press Ctrl + c to exit.\n";
  94. $cache = $in;
  95. $last_action = 0;
  96. while (true) {
  97. clearstatcache();
  98. // check if anything has changed since last fail
  99. $updated = false;
  100. if (is_array($cache)) {
  101. foreach ($cache['files'] as $fname=>$_) {
  102. if (filemtime($fname) > $last_action) {
  103. $updated = true;
  104. break;
  105. }
  106. }
  107. } else $updated = true;
  108. // try to compile it
  109. if ($updated) {
  110. $last_action = time();
  111. try {
  112. $cache = lessc::cexecute($cache);
  113. echo "Writing updated file: ".$out."\n";
  114. if (!file_put_contents($out, $cache['compiled'])) {
  115. err($fa."Could not write to file ".$out);
  116. exit(1);
  117. }
  118. } catch (exception $ex) {
  119. echo "\nFatal Error:\n".str_repeat('=', 20)."\n".
  120. $ex->getMessage()."\n\n";
  121. if (has("n")) {
  122. `notify-send -u critical "compile failed" "{$ex->getMessage()}"`;
  123. }
  124. }
  125. }
  126. sleep(1);
  127. }
  128. exit(0);
  129. }
  130. if (!$fname = array_shift($argv)) {
  131. echo $HELP;
  132. exit(1);
  133. }
  134. function dumpValue($node, $depth = 0) {
  135. if (is_object($node)) {
  136. $indent = str_repeat(" ", $depth);
  137. $out = array();
  138. foreach ($node->props as $prop) {
  139. $out[] = $indent . dumpValue($prop, $depth + 1);
  140. }
  141. $out = implode("\n", $out);
  142. if (!empty($node->tags)) {
  143. $out = "+ ".implode(", ", $node->tags)."\n".$out;
  144. }
  145. return $out;
  146. } elseif (is_array($node)) {
  147. if (empty($node)) return "[]";
  148. $type = $node[0];
  149. if ($type == "block")
  150. return dumpValue($node[1], $depth);
  151. $out = array();
  152. foreach ($node as $value) {
  153. $out[] = dumpValue($value, $depth);
  154. }
  155. return "{ ".implode(", ", $out)." }";
  156. } else {
  157. if (is_string($node) && preg_match("/[\s,]/", $node)) {
  158. return '"'.$node.'"';
  159. }
  160. return $node; // normal value
  161. }
  162. }
  163. function stripValue($o, $toStrip) {
  164. if (is_array($o) || is_object($o)) {
  165. $isObject = is_object($o);
  166. $o = (array)$o;
  167. foreach ($toStrip as $removeKey) {
  168. if (!empty($o[$removeKey])) {
  169. $o[$removeKey] = "*stripped*";
  170. }
  171. }
  172. foreach ($o as $k => $v) {
  173. $o[$k] = stripValue($v, $toStrip);
  174. }
  175. if ($isObject) {
  176. $o = (object)$o;
  177. }
  178. }
  179. return $o;
  180. }
  181. function dumpWithoutParent($o, $alsoStrip=array()) {
  182. $toStrip = array_merge(array("parent"), $alsoStrip);
  183. print_r(stripValue($o, $toStrip));
  184. }
  185. try {
  186. $less = make_less($fname);
  187. if (has("T", "X")) {
  188. $parser = new lessc_parser($less, $fname);
  189. $tree = $parser->parse(file_get_contents($fname));
  190. if (has("X"))
  191. $out = print_r($tree, 1);
  192. else
  193. $out = dumpValue($tree)."\n";
  194. } else {
  195. $out = $less->parse();
  196. }
  197. if (!$fout = array_shift($argv)) {
  198. echo $out;
  199. } else {
  200. file_put_contents($fout, $out);
  201. }
  202. } catch (exception $ex) {
  203. err($fa.$ex->getMessage());
  204. exit(1);
  205. }
  206. ?>