250 lines
4.8 KiB
PHP
Executable file
250 lines
4.8 KiB
PHP
Executable file
#!/usr/bin/env php
|
|
<?php
|
|
// Command line utility to compile LESS to STDOUT
|
|
// Leaf Corcoran <leafot@gmail.com>, 2013
|
|
|
|
$exe = array_shift($argv); // remove filename
|
|
|
|
$HELP = <<<EOT
|
|
Usage: $exe [options] input-file [output-file]
|
|
|
|
Options include:
|
|
|
|
-h, --help Show this message
|
|
-v Print the version
|
|
-f=format Set the output format, includes "default", "compressed"
|
|
-c Keep /* */ comments in output
|
|
-r Read from STDIN instead of input-file
|
|
-w Watch input-file, and compile to output-file if it is changed
|
|
-T Dump formatted parse tree
|
|
-X Dump raw parse tree
|
|
|
|
|
|
EOT;
|
|
|
|
$opts = getopt('hvrwncXTf:', array('help'));
|
|
while (count($argv) > 0 && preg_match('/^-([-hvrwncXT]$|[f]=)/', $argv[0])) {
|
|
array_shift($argv);
|
|
}
|
|
|
|
function has() {
|
|
global $opts;
|
|
foreach (func_get_args() as $arg) {
|
|
if (isset($opts[$arg])) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
if (has("h", "help")) {
|
|
exit($HELP);
|
|
}
|
|
|
|
error_reporting(E_ALL);
|
|
$path = realpath(dirname(__FILE__)).'/';
|
|
|
|
require $path."lessc.inc.php";
|
|
|
|
$VERSION = lessc::$VERSION;
|
|
|
|
$fa = "Fatal Error: ";
|
|
function err($msg) {
|
|
fwrite(STDERR, $msg."\n");
|
|
}
|
|
|
|
if (php_sapi_name() != "cli") {
|
|
err($fa.$argv[0]." must be run in the command line.");
|
|
exit(1);
|
|
}
|
|
|
|
function make_less($fname = null) {
|
|
global $opts;
|
|
$l = new lessc($fname);
|
|
|
|
if (has("f")) {
|
|
$format = $opts["f"];
|
|
if ($format != "default") $l->setFormatter($format);
|
|
}
|
|
|
|
if (has("c")) {
|
|
$l->setPreserveComments(true);
|
|
}
|
|
|
|
return $l;
|
|
}
|
|
|
|
function process($data, $import = null) {
|
|
global $fa;
|
|
|
|
$l = make_less();
|
|
if ($import) $l->importDir = $import;
|
|
|
|
try {
|
|
echo $l->parse($data);
|
|
exit(0);
|
|
} catch (exception $ex) {
|
|
err($fa."\n".str_repeat('=', 20)."\n".
|
|
$ex->getMessage());
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (has("v")) {
|
|
exit($VERSION."\n");
|
|
}
|
|
|
|
if (has("r")) {
|
|
if (!empty($argv)) {
|
|
$data = $argv[0];
|
|
} else {
|
|
$data = "";
|
|
while (!feof(STDIN)) {
|
|
$data .= fread(STDIN, 8192);
|
|
}
|
|
}
|
|
exit(process($data));
|
|
}
|
|
|
|
if (has("w")) {
|
|
// need two files
|
|
if (!is_file($in = array_shift($argv)) ||
|
|
null == $out = array_shift($argv))
|
|
{
|
|
err($fa.$exe." -w infile outfile");
|
|
exit(1);
|
|
}
|
|
|
|
echo "Watching ".$in.
|
|
(has("n") ? ' with notifications' : '').
|
|
", press Ctrl + c to exit.\n";
|
|
|
|
$cache = $in;
|
|
$last_action = 0;
|
|
while (true) {
|
|
clearstatcache();
|
|
|
|
// check if anything has changed since last fail
|
|
$updated = false;
|
|
if (is_array($cache)) {
|
|
foreach ($cache['files'] as $fname=>$_) {
|
|
if (filemtime($fname) > $last_action) {
|
|
$updated = true;
|
|
break;
|
|
}
|
|
}
|
|
} else $updated = true;
|
|
|
|
// try to compile it
|
|
if ($updated) {
|
|
$last_action = time();
|
|
|
|
try {
|
|
$cache = lessc::cexecute($cache);
|
|
echo "Writing updated file: ".$out."\n";
|
|
if (!file_put_contents($out, $cache['compiled'])) {
|
|
err($fa."Could not write to file ".$out);
|
|
exit(1);
|
|
}
|
|
} catch (exception $ex) {
|
|
echo "\nFatal Error:\n".str_repeat('=', 20)."\n".
|
|
$ex->getMessage()."\n\n";
|
|
|
|
if (has("n")) {
|
|
`notify-send -u critical "compile failed" "{$ex->getMessage()}"`;
|
|
}
|
|
}
|
|
}
|
|
|
|
sleep(1);
|
|
}
|
|
exit(0);
|
|
}
|
|
|
|
if (!$fname = array_shift($argv)) {
|
|
echo $HELP;
|
|
exit(1);
|
|
}
|
|
|
|
function dumpValue($node, $depth = 0) {
|
|
if (is_object($node)) {
|
|
$indent = str_repeat(" ", $depth);
|
|
$out = array();
|
|
foreach ($node->props as $prop) {
|
|
$out[] = $indent . dumpValue($prop, $depth + 1);
|
|
}
|
|
$out = implode("\n", $out);
|
|
if (!empty($node->tags)) {
|
|
$out = "+ ".implode(", ", $node->tags)."\n".$out;
|
|
}
|
|
return $out;
|
|
} elseif (is_array($node)) {
|
|
if (empty($node)) return "[]";
|
|
$type = $node[0];
|
|
if ($type == "block")
|
|
return dumpValue($node[1], $depth);
|
|
|
|
$out = array();
|
|
foreach ($node as $value) {
|
|
$out[] = dumpValue($value, $depth);
|
|
}
|
|
return "{ ".implode(", ", $out)." }";
|
|
} else {
|
|
if (is_string($node) && preg_match("/[\s,]/", $node)) {
|
|
return '"'.$node.'"';
|
|
}
|
|
return $node; // normal value
|
|
}
|
|
}
|
|
|
|
|
|
function stripValue($o, $toStrip) {
|
|
if (is_array($o) || is_object($o)) {
|
|
$isObject = is_object($o);
|
|
$o = (array)$o;
|
|
foreach ($toStrip as $removeKey) {
|
|
if (!empty($o[$removeKey])) {
|
|
$o[$removeKey] = "*stripped*";
|
|
}
|
|
}
|
|
|
|
foreach ($o as $k => $v) {
|
|
$o[$k] = stripValue($v, $toStrip);
|
|
}
|
|
|
|
if ($isObject) {
|
|
$o = (object)$o;
|
|
}
|
|
}
|
|
|
|
return $o;
|
|
}
|
|
|
|
function dumpWithoutParent($o, $alsoStrip=array()) {
|
|
$toStrip = array_merge(array("parent"), $alsoStrip);
|
|
print_r(stripValue($o, $toStrip));
|
|
}
|
|
|
|
try {
|
|
$less = make_less($fname);
|
|
if (has("T", "X")) {
|
|
$parser = new lessc_parser($less, $fname);
|
|
$tree = $parser->parse(file_get_contents($fname));
|
|
if (has("X"))
|
|
$out = print_r($tree, 1);
|
|
else
|
|
$out = dumpValue($tree)."\n";
|
|
} else {
|
|
$out = $less->parse();
|
|
}
|
|
|
|
if (!$fout = array_shift($argv)) {
|
|
echo $out;
|
|
} else {
|
|
file_put_contents($fout, $out);
|
|
}
|
|
|
|
} catch (exception $ex) {
|
|
err($fa.$ex->getMessage());
|
|
exit(1);
|
|
}
|
|
|
|
?>
|