JSM now supports an array of base dirs

This commit is contained in:
Pavel Shevaev 2023-05-25 18:02:16 +03:00
parent 0b75d8404a
commit e5507303cd
2 changed files with 67 additions and 55 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
tags

View File

@ -6,7 +6,7 @@ class JSM
static private $modules = array();
static private $consts = array();
private $base_dir;
private $base_dirs = array();
private $file;
private $scope_vars = array(array());
private $includes = array();
@ -16,12 +16,17 @@ class JSM
private $cur_modules = array();
private $args_parser;
function __construct($base_dir, $file)
function __construct($base_dirs/*can be a string for BC*/, $file)
{
//for rand constants
mt_srand();
$this->base_dir = rtrim(jsm_normalize_path($base_dir, true/*nix*/), '/');
if(is_string($base_dirs))
$base_dirs = array($base_dirs);
$this->base_dirs = array_map(
function($base_dir) { return rtrim(jsm_normalize_path($base_dir, true/*nix*/), '/'); },
$base_dirs
);
$this->file = $file;
$this->args_parser = new JSM_ArgsParser();
}
@ -261,9 +266,9 @@ class JSM
$full_path = realpath($curr_dir . '/' . $m[1]);
if(!$full_path)
throw new Exception("Bad relative path '$m[1]'");
//2) now turning the path into *nix alike
$full_path = jsm_normalize_path($full_path, true/*nix*/);
$rel_path = ltrim(str_replace($this->base_dir, '', $full_path), '/');
$rel_path = jsm_make_rel_path($this->base_dirs, $full_path);
return $rel_path;
}
@ -275,8 +280,7 @@ class JSM
if(!$full_path)
throw new Exception("Bad relative path '$m[1]'" . ($curr_dir . '/' . $m[1]));
$full_path = jsm_normalize_path($full_path, true/*nix*/);
$rel_path = ltrim(str_replace($this->base_dir, '', $full_path), '/');
$rel_path = jsm_make_rel_path($this->base_dirs, $full_path);
$rel_path = str_replace('.conf.js', '', $rel_path);
return "@$rel_path";
@ -301,11 +305,9 @@ class JSM
return $txt;
}
/*private */function _includesCallback(array $m, $curr_file)
/*private */function _includesCallback($inc_path, $curr_file)
{
$file_name = $m[1];
$dir = ($file_name[0] == '/') ? $this->base_dir : dirname($curr_file);
$file = jsm_normalize_path($dir . '/' . $m[1]);
$file = jsm_resolve_inc_path($this->base_dirs, $curr_file, $inc_path);
$cm = $this->_currentModule();
@ -355,7 +357,7 @@ class JSM
$self = $this;
$txt = preg_replace_callback(
'~<%\s*INC\s*\(\s*"([^"]+)"\s*\)\s*%>~',
function($m) use($self, $file) { return $self->_includesCallback($m, $file); },
function($m) use($self, $file) { return $self->_includesCallback($m[1], $file); },
$txt);
}
@ -373,43 +375,28 @@ class JSM
return strpos($file, $ext, strlen($file) - strlen($ext) - 1) !== false;
}
static function getDeps($base_dir, $file)
static function getDeps(array $base_dirs, $file)
{
$deps = array();
self::_getDeps($base_dir, $file, $deps);
self::_getDeps($base_dirs, $file, $deps);
return $deps;
}
static private function _extractDeps($txt)
{
$dep_files = array();
if(preg_match_all('~<%\s*((?:INC)|(?:BHL))\s*\(\s*"([^\n]+)~', $txt, $ms))
if(preg_match_all('~<%\s*(?:INC)\s*\(\s*"([^\n]+)~', $txt, $ms))
{
foreach($ms[1] as $idx => $type)
foreach($ms[1] as $raw_dep)
{
$raw_dep = $ms[2][$idx];
$is_bhl = $type === "BHL";
if($is_bhl)
{
$bhl_imps = explode(',', str_replace('"', '', $raw_dep));
foreach($bhl_imps as $bhl_imp)
{
if($bhl_imp)
$dep_files[$bhl_imp . '.bhl'] = true;
}
}
else
{
$dep_file = substr($raw_dep, 0, strpos($raw_dep, '"'));
$dep_files[$dep_file] = false;
}
$dep_file = substr($raw_dep, 0, strpos($raw_dep, '"'));
$dep_files[$dep_file] = true;
}
}
return $dep_files;
return array_keys($dep_files);
}
static private function _getDeps($base_dir, $file, &$deps)
static private function _getDeps(array $base_dirs, $file, &$deps)
{
static $cache = array();
@ -424,36 +411,29 @@ class JSM
$extracted_deps = self::_extractDeps($txt);
foreach($extracted_deps as $inc => $is_bhl)
foreach($extracted_deps as $inc)
{
$dir = ($inc[0] == '/') ? $base_dir : dirname($file);
$dep_file = jsm_normalize_path($dir . "/" . $inc);
$local_deps[] = array($is_bhl, $dep_file);
$dep_file = jsm_resolve_inc_path($base_dirs, $file, $inc);
$local_deps[] = $dep_file;
$cache[$file] = $local_deps;
}
}
else
$local_deps = $cache[$file];
foreach($local_deps as $local_dep)
foreach($local_deps as $dep_file)
{
list($is_bhl, $dep_file) = $local_dep;
if(in_array($dep_file, $deps))
continue;
$deps[] = $dep_file;
//NOTE: bhl deps are shallow
if(!$is_bhl)
try
{
try
{
self::_getDeps($base_dir, $dep_file, $deps);
}
catch(Exception $e)
{
throw new Exception("Bad deps for '$file' : " . $e->getMessage());
}
self::_getDeps($base_dirs, $dep_file, $deps);
}
catch(Exception $e)
{
throw new Exception("Bad deps for '$file' : " . $e->getMessage());
}
}
}
@ -587,6 +567,7 @@ class JSM
{
$txt = $this->_replaceVarsWithMacro($file, $txt);
//let's exit early if there are no macro calls
if(strpos($txt, '<%') === false)
{
$node->addChild(new JSM_TextNode($txt));
@ -616,7 +597,7 @@ class JSM
$mcall = $this->_newCall($name);
if($mcall === null)
throw new Exception("No node for '$name'");
throw new Exception("No macro for '$name'");
$this->_pushNode($mcall);
}
@ -627,7 +608,7 @@ class JSM
throw new Exception("Non paired macro ending");
$tmp_node = $this->_node(false/*non strict*/);
if($tmp_node == null)
throw new Exception("No current node(prev. node " . $mcall->name . ")");
throw new Exception("No current macro (prev. " . $mcall->name . ")");
$tmp_node->addChild($mcall);
}
else
@ -805,7 +786,7 @@ class JSM_MacroPHPNode implements JSM_MacroNode
{
//NOTE: making sure file containing PHP macro was actually included by this file
if(!$this->is_builtin && !$jsm->_isIncluded($this->refl->getFileName()))
throw new Exception("Not found");
throw new Exception("Macro source file was not included by config file itself: ".$this->refl->getFileName());
$named = false;
$args = array();
@ -1438,6 +1419,36 @@ function jsm_normalize_path($path, $unix=null/*null means try to guess*/)
return $res;
}
function jsm_resolve_inc_path(array $base_dirs, $curr_file, $inc_path)
{
return jsm_normalize_path(
$inc_path[0] == '/' ?
jsm_make_full_path($base_dirs, $inc_path) :
dirname($curr_file) . '/' . $inc_path
);
}
function jsm_make_full_path(array $base_dirs, $rel_path)
{
foreach($base_dirs as $dir)
if(is_file($dir . '/' . $rel_path))
return $dir . '/' . $rel_path;
throw new Exception("No file for relative path '$rel_path'");
}
function jsm_make_rel_path(array $base_dirs, $full_path)
{
$full_path = jsm_normalize_path($full_path, true/*nix*/);
foreach($base_dirs as $base_dir)
{
$rel_path = str_replace($base_dir, '', $full_path);
if(strlen($rel_path) < strlen($full_path))
return ltrim($rel_path, '/');
}
throw new Exception("File '$full_path' not mapped to any base dir");
}
function jsm_eval_string(JSM $jsm, $expr_str)
{
$expr = new JSM_Expr();