Compare commits

...

4 Commits

Author SHA1 Message Date
Pavel Shevaev e68ad37770 Fixing main
Publish PHP Package / docker (push) Successful in 6s Details
2025-03-24 09:53:07 +03:00
Pavel Shevaev 8dc71ab534 Fixing disabled built-in tasks; Improving missing task error reporting
Publish PHP Package / docker (push) Successful in 6s Details
2025-03-24 09:50:17 +03:00
Pavel Shevaev d40c2fe201 Improving handling of file system events
Publish PHP Package / docker (push) Successful in 6s Details
2025-03-19 18:37:46 +03:00
Pavel Shevaev 0189c9d7af Adding more convenience stuff
Publish PHP Package / docker (push) Successful in 6s Details
2025-03-06 13:56:27 +03:00
5 changed files with 179 additions and 113 deletions

View File

@ -87,7 +87,12 @@ class TaskmanArtefact
function initSources(?\taskman\TaskmanFileChanges $file_changes)
{
foreach($this->getSourcesSpec() as $src_idx => $src_spec)
$all_src_specs = $this->getSourcesSpec();
//let's process a convenience special case
if(count($all_src_specs) > 0 && !is_array($all_src_specs[0]))
$all_src_specs = [$all_src_specs];
foreach($all_src_specs as $src_idx => $src_spec)
{
//[[dir1, dir2, ..], [ext1, ext2, ..]]
if(is_array($src_spec) && count($src_spec) == 2 &&
@ -106,7 +111,7 @@ class TaskmanArtefact
$changed = array();
foreach($src_spec[0] as $spec_dir)
{
$matches = $file_changes->matchDirectory($spec_dir);
$matches = $file_changes->matchDirectory($spec_dir, $src_spec[1]);
$changed[$spec_dir] = $matches;
}
return new TaskmanDirFiles($changed);
@ -157,6 +162,11 @@ class TaskmanDirFiles implements \ArrayAccess, \Countable, \Iterator
$this->dir2files[$dir] = $files;
}
function __toString() : string
{
return var_export($this->dir2files, true);
}
function toMap() : array
{
return $this->dir2files;

View File

@ -166,7 +166,7 @@ function _read_env_vars()
}
}
function _process_argv(&$argv)
function _process_argv(array &$argv)
{
global $TASKMAN_LOG_LEVEL;
global $TASKMAN_BATCH;
@ -253,3 +253,32 @@ function _process_argv(&$argv)
$argv = $filtered;
}
function _extract_lines_from_file(string $file_path) : array
{
$lines = array();
$fh = fopen($file_path, 'r+');
if($fh === false)
return $lines;
try
{
if(flock($fh, LOCK_EX))
{
while(($line = fgets($fh)) !== false)
$lines[] = $line;
ftruncate($fh, 0);
flock($fh, LOCK_UN);
}
}
finally
{
fclose($fh);
}
return $lines;
}

View File

@ -2,11 +2,6 @@
namespace taskman;
use Exception;
include_once(__DIR__ . '/internal.inc.php');
include_once(__DIR__ . '/util.inc.php');
include_once(__DIR__ . '/tasks.inc.php');
include_once(__DIR__ . '/artefact.inc.php');
$GLOBALS['TASKMAN_TASKS'] = array();
$GLOBALS['TASKMAN_CLOSURES'] = array();
$GLOBALS['TASKMAN_STACK'] = array();
@ -21,6 +16,11 @@ $GLOBALS['TASKMAN_ERROR_HANDLER'] = null;
$GLOBALS['TASKMAN_START_TIME'] = 0;
$GLOBALS['TASKMAN_FILES_CHANGES'] = null;
include_once(__DIR__ . '/internal.inc.php');
include_once(__DIR__ . '/util.inc.php');
include_once(__DIR__ . '/tasks.inc.php');
include_once(__DIR__ . '/artefact.inc.php');
class TaskmanException extends Exception
{}
@ -126,6 +126,7 @@ class TaskmanTask
$specs = $this->getPropOr("artefacts", array());
if(is_callable($specs))
$specs = $specs();
if(is_array($specs))
{
foreach($specs as $dst => $src_spec)
@ -135,6 +136,11 @@ class TaskmanTask
return $artefacts;
}
function getArtefact(int $idx) : artefact\TaskmanArtefact
{
return $this->getArtefacts()[$idx];
}
function getFileChanges() : ?TaskmanFileChanges
{
return $this->file_changes;
@ -175,7 +181,7 @@ class TaskmanTask
$level = count($TASKMAN_STACK)-1;
msg_sys("***** ".str_repeat('-', $level)."task '" . $this->getName() . "' start *****\n");
log(0, "***** ".str_repeat('-', $level)."task '" . $this->getName() . "' start *****\n");
if(!$TASKMAN_NO_DEPS)
{
@ -193,7 +199,7 @@ class TaskmanTask
if(!$TASKMAN_NO_DEPS)
run_many($this->after_deps);
msg_sys("***** ".str_repeat('-', $level)."task '" . $this->getName() . "' done(" .
log(0, "***** ".str_repeat('-', $level)."task '" . $this->getName() . "' done(" .
round(microtime(true)-$bench,2) . '/' .round(microtime(true)-$TASKMAN_START_TIME,2) . " sec.) *****\n");
$this->has_run[$args_str] = true;
@ -273,7 +279,7 @@ class TaskmanTask
if($artefact->isStale())
{
msg_sys("Task '{$this->name}' artefact '{$artefact->getPath()}' (sources at ".implode(',', $artefact->getNewerSourcesIndices()).") is stale\n");
log(0, "Task '{$this->name}' artefact '{$artefact->getPath()}' (sources at ".implode(',', $artefact->getNewerSourcesIndices()).") is stale\n");
}
}
@ -293,28 +299,35 @@ class TaskmanTask
class TaskmanFileChanges
{
const Changed = 1;
const Created = 2;
const Renamed = 3;
const Deleted = 4;
//file => status
private $changed = array();
private $removed = array();
static function parse(string $json_or_file)
{
if($json_or_file[0] == '[')
$json = $json_or_file;
else
$json = file_get_contents($json_or_file);
{
$lines = internal\_extract_lines_from_file($json_or_file);
$json = '[' . implode(',', $lines) . ']';
}
$decoded = json_decode($json, true);
if(!is_array($decoded))
throw new Exception('Bad json');
throw new Exception('Bad json: ' . $json);
$changed = array();
$removed = array();
$base_dir = dirname($_SERVER['PHP_SELF']);
foreach($decoded as $items)
{
if(count($items) != 2)
if(count($items) < 2)
throw new Exception('Bad entry');
list($status, $file) = $items;
@ -331,30 +344,33 @@ class TaskmanFileChanges
$file = artefact\normalize_path($file);
if($status == 'C')
$changed[$file] = true;
else if($status == 'R')
$removed[$file] = true;
if($status == 'Changed')
$changed[$file] = self::Changed;
else if($status == 'Created')
$changed[$file] = self::Created;
else if($status == 'Renamed')
$changed[$file] = self::Renamed;
else if($status == 'Deleted')
$changed[$file] = self::Deleted;
else
throw new Exception('Unknown status: ' . $status);
}
return new TaskmanFileChanges($changed, $removed);
return new TaskmanFileChanges($changed);
}
//NOTE: these are actually maps: file => true
function __construct(array $changed, array $removed)
//NOTE: maps: file => status
function __construct(array $changed)
{
$this->changed = $changed;
$this->removed = $removed;
}
function isEmpty() : bool
{
return count($this->changed) == 0 && count($this->removed) == 0;
return count($this->changed) == 0;
}
function matchDirectory(string $dir) : array
function matchDirectory(string $dir, array $extensions = array()) : array
{
$dir = rtrim($dir, '/\\');
$dir .= DIRECTORY_SEPARATOR;
@ -362,25 +378,115 @@ class TaskmanFileChanges
$filtered = [];
foreach($this->changed as $path => $_)
if(strpos($path, $dir) === 0)
$filtered[] = $path;
foreach($this->removed as $path => $_)
if(strpos($path, $dir) === 0)
if(self::matchDirAndExtension($path, $dir, $extensions))
$filtered[] = $path;
return $filtered;
}
static function matchDirAndExtension(string $path, string $dir, array $extensions) : bool
{
if(strpos($path, $dir) !== 0)
return false;
foreach($extensions as $ext)
if(!str_ends_with($path, $ext))
return false;
return true;
}
function matchFiles(iterable $files) : array
{
$filtered = [];
foreach($files as $file)
{
if(isset($this->changed[$file]) || isset($this->removed[$file]))
if(isset($this->changed[$file]))
$filtered[] = $file;
}
return $filtered;
}
}
function main(
array $argv = array(),
callable $help_func = null,
bool $proc_argv = true,
bool $read_env_vars = true
)
{
$GLOBALS['TASKMAN_START_TIME'] = microtime(true);
if($help_func)
$GLOBALS['TASKMAN_HELP_FUNC'] = $help_func;
if($read_env_vars)
internal\_read_env_vars();
if($proc_argv)
internal\_process_argv($argv);
$GLOBALS['TASKMAN_SCRIPT'] = array_shift($argv);
internal\_collect_tasks();
$always_tasks = array();
$default_task = null;
foreach(get_tasks() as $task_obj)
{
if($task_obj->hasProp('always'))
array_unshift($always_tasks, $task_obj);
if($task_obj->hasProp('default'))
{
if($default_task)
throw new TaskmanException("Assigned default task '" . $default_task->getName() . "' conflicts with '" . $task_obj->getName() . "'");
else
$default_task = $task_obj;
}
}
foreach($always_tasks as $always_task)
run($always_task);
if(sizeof($argv) > 0)
{
$task_str = array_shift($argv);
$tasks = internal\_parse_taskstr($task_str);
if(count($tasks) == 1 && !internal\_isset_task($tasks[0]))
{
$pattern = $tasks[0];
if($pattern[0] == '~')
{
$pattern = substr($pattern, 1, strlen($pattern) - 1);
$is_similar = true;
}
elseif(substr($pattern, -1, 1) == '~')
{
$pattern = substr($pattern, 0, strlen($pattern) - 1);
$is_similar = true;
}
else
$is_similar = false;
$hints = internal\_get_hints($pattern);
if($is_similar && count($hints) == 1)
$tasks = $hints;
else
{
$similars = '';
if($hints)
$similars .= "\nSimilar tasks: " . implode(', ', $hints) . ".";
throw new Exception("Task '{$tasks[0]}' not found. $similars");
}
}
run_many($tasks, $argv);
}
else if($default_task)
run($default_task, $argv);
log(0, "***** All done (".round(microtime(true)-$GLOBALS['TASKMAN_START_TIME'],2)." sec.) *****\n");
}

View File

@ -13,7 +13,8 @@ task('help', function($args = array())
$all = get_tasks();
foreach($all as $task)
{
if($filter && (strpos($task->getName(), $filter) === false && strpos($task->getPropOr("alias", ""), $filter) === false))
if($filter && (strpos($task->getName(), $filter) === false &&
strpos($task->getPropOr("alias", ""), $filter) === false))
continue;
if(strlen($task->getName()) > $maxlen)

View File

@ -163,86 +163,6 @@ function _(string $str) : string
return $str;
}
function main($argv = array(), $help_func = null, $proc_argv = true, $read_env_vars = true)
{
$GLOBALS['TASKMAN_START_TIME'] = microtime(true);
if($help_func)
$GLOBALS['TASKMAN_HELP_FUNC'] = $help_func;
if($read_env_vars)
internal\_read_env_vars();
if($proc_argv)
internal\_process_argv($argv);
$GLOBALS['TASKMAN_SCRIPT'] = array_shift($argv);
internal\_collect_tasks();
$always_tasks = array();
$default_task = null;
foreach(get_tasks() as $task_obj)
{
if($task_obj->hasProp('always'))
array_unshift($always_tasks, $task_obj);
if($task_obj->hasProp('default'))
{
if($default_task)
throw new TaskmanException("Assigned default task '" . $default_task->getName() . "' conflicts with '" . $task_obj->getName() . "'");
else
$default_task = $task_obj;
}
}
foreach($always_tasks as $always_task)
run($always_task);
if(sizeof($argv) > 0)
{
$task_str = array_shift($argv);
$tasks = internal\_parse_taskstr($task_str);
if(count($tasks) == 1 && !internal\_isset_task($tasks[0]))
{
$pattern = $tasks[0];
if($pattern[0] == '~')
{
$pattern = substr($pattern, 1, strlen($pattern) - 1);
$is_similar = true;
}
elseif(substr($pattern, -1, 1) == '~')
{
$pattern = substr($pattern, 0, strlen($pattern) - 1);
$is_similar = true;
}
else
$is_similar = false;
$hints = internal\_get_hints($pattern);
if($is_similar && count($hints) == 1)
$tasks = $hints;
else
{
printf("ERROR! Task %s not found\n", $tasks[0]);
if($hints)
{
printf("Similar tasks:\n");
foreach($hints as $hint)
printf(" %s\n", $hint);
}
exit(1);
}
}
run_many($tasks, $argv);
}
else if($default_task)
run($default_task, $argv);
msg_sys("***** All done (".round(microtime(true)-$GLOBALS['TASKMAN_START_TIME'],2)." sec.) *****\n");
}
function usage($script_name = "<taskman-script>")
{
internal\_default_usage($script_name);