Compare commits
25 Commits
Author | SHA1 | Date |
---|---|---|
|
dbf30f1231 | |
|
abe8d938cb | |
|
e68ad37770 | |
|
8dc71ab534 | |
|
d40c2fe201 | |
|
0189c9d7af | |
|
3052d68f9b | |
|
5cae1bf622 | |
|
4cf34b0dba | |
|
37c915e72e | |
|
71205818be | |
|
c11528f477 | |
|
f2c9251e52 | |
|
2cbde0efb4 | |
|
b4698563fe | |
|
115dce40b2 | |
|
2db9f91cde | |
|
7aa8ba4cc0 | |
|
87c5107bda | |
|
8a0ad52631 | |
|
4bf7a85671 | |
|
93d2ad7575 | |
|
e9f55092be | |
|
f1a3b0c35b | |
|
183e40656f |
|
@ -0,0 +1,29 @@
|
|||
|
||||
name: Publish PHP Package
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Get tag name
|
||||
run: echo "TAG=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV
|
||||
|
||||
- name: zip and send
|
||||
run: |
|
||||
ls -la
|
||||
apt-get update -y
|
||||
apt-get install -y zip
|
||||
cd ../
|
||||
zip -r ${{ gitea.event.repository.name }}.zip ${{ gitea.event.repository.name }} -x '*.git*'
|
||||
curl -v \
|
||||
--user composer-pbl:${{ secrets.COMPOSER_PSWD }} \
|
||||
--upload-file ${{ gitea.event.repository.name }}.zip \
|
||||
https://git.bit5.ru/api/packages/bit/composer?version=${{ env.TAG }}
|
|
@ -0,0 +1 @@
|
|||
tags
|
|
@ -0,0 +1,2 @@
|
|||
## v2.3.0
|
||||
- Adding support for enviroment variables prefixed with **TASKMAN_SET_** being set as props. For example: **TASKMAN_SET_FOO=1** results in property **FOO=1**
|
235
README.md
235
README.md
|
@ -0,0 +1,235 @@
|
|||
## Taskman
|
||||
|
||||
Taskman is a simple library which allows to conveniently execute build 'tasks' written in PHP from the shell. Tasks can have dependencies on other tasks.
|
||||
|
||||
Taskman is inspired by Make, Capistrano, Ant, Maven and similar build tools.
|
||||
|
||||
The central unit of execution is 'task'. The main difference from the plain old function is the fact 'task' is executed **only once** no matter what.
|
||||
|
||||
### Examples
|
||||
|
||||
#### Hello world
|
||||
Here's a simple example of a task:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('hello', function()
|
||||
{
|
||||
echo "Hello world!\n";
|
||||
});
|
||||
```
|
||||
|
||||
Executing it from the shell yields:
|
||||
|
||||
```
|
||||
./gamectl hello
|
||||
***** task 'hello' start *****
|
||||
Hello world!
|
||||
***** task 'hello' done(0/0.27 sec.) *****
|
||||
***** All done (0.27 sec.) *****
|
||||
```
|
||||
|
||||
#### Real world example
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('ultimate_build_run',
|
||||
[
|
||||
'default' => true,
|
||||
'alias' => 'urun',
|
||||
'deps' => ['autogen', 'pack_configs', 'ensure_unity_player_settings', 'unity_defines']
|
||||
], function() {});
|
||||
```
|
||||
### Get help and list all tasks
|
||||
|
||||
You can list all tasks and their definition locations using **help** task (yes, it's a task as well):
|
||||
|
||||
```
|
||||
./gamectl help
|
||||
***** task 'help' start *****
|
||||
|
||||
Usage:
|
||||
gamectl [OPTIONS] <task-name1>[,<task-name2>,..] [-D PROP1=value [-D PROP2]]
|
||||
|
||||
Available options:
|
||||
-c specify PHP script to be included (handy for setting props,config options,etc)
|
||||
-V be super verbose
|
||||
-q be quite, only system messages
|
||||
-b batch mode: be super quite, don't even output any system messages
|
||||
-- pass all options verbatim after this mark
|
||||
|
||||
Available tasks:
|
||||
---------------------------------
|
||||
apk_install_to_device (/Users/ps/dev/skeletor/gamectl.d/client.inc.php@58)
|
||||
---------------------------------
|
||||
apk_run_on_device (/Users/ps/dev/skeletor/gamectl.d/client.inc.php@67)
|
||||
---------------------------------
|
||||
autogen @deps ["unity_defines","cs_autogen","php_autogen"] (/Users/ps/dev/skeletor/gamectl.d/autogen.inc.php@6)
|
||||
---------------------------------
|
||||
bhl_autogen @deps ["bhl_make_upm_package"] (/Users/ps/dev/skeletor/gamectl.d/bhl.inc.php@19)
|
||||
***** task 'help' done(0/0.01 sec.) *****
|
||||
***** All done (0.01 sec.) *****
|
||||
```
|
||||
|
||||
You can filter tasks you want to get help for by a partial match as follows:
|
||||
|
||||
```
|
||||
./gamectl help name
|
||||
```
|
||||
|
||||
### Tasks documentation
|
||||
|
||||
#### Task declaration
|
||||
|
||||
Task must be declared using library **task** function as follows:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('name', function() {});
|
||||
```
|
||||
|
||||
The task above now can be invoked from the shell as follows:
|
||||
|
||||
```./gamectl name```
|
||||
|
||||
#### Task aliases
|
||||
|
||||
Task may have an alias for less typing in the shell. To specify an alias one should put it as an **alias** property of a task declaration:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('name', ['alias' => 'n'],
|
||||
function() {});
|
||||
```
|
||||
|
||||
You can invoke the task by the alias as follows:
|
||||
|
||||
```./gamectl n```
|
||||
|
||||
#### Task dependencies
|
||||
|
||||
Task may have an dependencies on other tasks. To specify all dependencies one should list them in **deps** section of a task declaration:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('c', ['deps' => ['a', 'b']],
|
||||
function() {});
|
||||
```
|
||||
|
||||
All dependencies are executed before running the specified task. Running the task above yields something as follows:
|
||||
```
|
||||
./gamectl c
|
||||
***** task 'c' start *****
|
||||
***** -task 'a' start *****
|
||||
***** -task 'a' done(0/0.18 sec.) *****
|
||||
***** -task 'b' start *****
|
||||
***** -task 'b' done(0/0.18 sec.) *****
|
||||
***** task 'c' done(0/0.18 sec.) *****
|
||||
***** All done (0.18 sec.) *****
|
||||
```
|
||||
|
||||
#### Always executed tasks
|
||||
|
||||
Sometimes it's convenient to define tasks which should be executed every time without explicit invocation. For example for setting the up the default environment, properties, etc. To achieve that one should specify the **always** property for a task:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('setup_env', ['always' => true],
|
||||
function() {});
|
||||
```
|
||||
|
||||
### Build properties
|
||||
|
||||
It's possible to specify miscellaneous build properties to setup a proper build environment conditions. There's a set of routines provided by taskman for properties manipulation.
|
||||
|
||||
#### Setting a property
|
||||
|
||||
Use **set** built-in function:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('setup_env', ['always' => true],
|
||||
function() {
|
||||
set("IOS_APP_ID", "4242jfhFD");
|
||||
});
|
||||
```
|
||||
|
||||
#### Setting a property only if it's not already set
|
||||
|
||||
Use **setor** built-in function. Property will be set only if it's not set some where before. It's a convenient pattern to have a default set of properties which can be overriden by the environment properties included from an external script.
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('setup_env', ['always' => true],
|
||||
function() {
|
||||
setor("IOS_APP_ID", "4242jfhFD");
|
||||
});
|
||||
```
|
||||
|
||||
#### Getting a property
|
||||
|
||||
Use **get** built-in function:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('build_ios',
|
||||
function() {
|
||||
shell("xcode build app " . get("IOS_APP_ID"));
|
||||
});
|
||||
```
|
||||
|
||||
#### Getting a property or some default value
|
||||
|
||||
Use **getor** built-in function:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace taskman;
|
||||
|
||||
task('build_ios',
|
||||
function() {
|
||||
shell("xcode build app " . getor("IOS_APP_ID", "3232232"));
|
||||
});
|
||||
```
|
||||
|
||||
#### Listing all build properties
|
||||
|
||||
To list all defined build properties one should use the **props** task:
|
||||
|
||||
```
|
||||
./gamectl props
|
||||
|
||||
***** task 'props' start *****
|
||||
|
||||
Available props:
|
||||
---------------------------------
|
||||
UNITY_ASSETS_DIR : '/Users/ps/dev/skeletor//unity/Assets/'
|
||||
---------------------------------
|
||||
GAME_COMPANY_NAME : 'Black Hole Light'
|
||||
***** task 'props' done(0.11/0.11 sec.) *****
|
||||
***** All done (0.11 sec.) *****
|
||||
```
|
||||
|
||||
You can filter properties you want to get information about by a partial match as follows:
|
||||
|
||||
```
|
||||
./gamectl props FOO
|
||||
```
|
|
@ -0,0 +1,413 @@
|
|||
<?php
|
||||
namespace taskman\artefact;
|
||||
use Exception;
|
||||
|
||||
class TaskmanArtefact
|
||||
{
|
||||
private \taskman\TaskmanTask $task;
|
||||
private string $path;
|
||||
private array $sources_fn = array();
|
||||
private array $sources_spec = array();
|
||||
private iterable $sources = array();
|
||||
private array $sources_changed = array();
|
||||
private array $sources_changed_fn = array();
|
||||
private array $sources_affected = array();
|
||||
|
||||
function __construct(\taskman\TaskmanTask $task, string $path, array $sources_spec)
|
||||
{
|
||||
$this->task = $task;
|
||||
$this->path = $path;
|
||||
$this->sources_spec = $sources_spec;
|
||||
}
|
||||
|
||||
function getTask() : \taskman\TaskmanTask
|
||||
{
|
||||
return $this->task;
|
||||
}
|
||||
|
||||
function getPath() : string
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
function getSourcesSpec() : array
|
||||
{
|
||||
return $this->sources_spec;
|
||||
}
|
||||
|
||||
function getSources(int $idx) : iterable
|
||||
{
|
||||
if(isset($this->sources[$idx]))
|
||||
return $this->sources[$idx];
|
||||
|
||||
if(isset($this->sources_fn[$idx]))
|
||||
{
|
||||
$fn = $this->sources_fn[$idx];
|
||||
$sources = $fn();
|
||||
$this->sources[$idx] = $sources;
|
||||
return $sources;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
function setSourcesFn(int $idx, \Closure $fn)
|
||||
{
|
||||
$this->sources_fn[$idx] = $fn;
|
||||
}
|
||||
|
||||
function setSourcesChangedFn(int $idx, \Closure $fn)
|
||||
{
|
||||
$this->sources_changed_fn[$idx] = $fn;
|
||||
}
|
||||
|
||||
function getChangedSources(int $idx) : iterable
|
||||
{
|
||||
if(isset($this->sources_changed[$idx]))
|
||||
return $this->sources_changed[$idx];
|
||||
|
||||
if(isset($this->sources_changed_fn[$idx]))
|
||||
{
|
||||
$fn = $this->sources_changed_fn[$idx];
|
||||
$changed = $fn();
|
||||
$this->sources_changed[$idx] = $changed;
|
||||
return $changed;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
//obsolete
|
||||
function isSourcesNewer(int $idx) : bool
|
||||
{
|
||||
return $this->isSourcesAffected($idx);
|
||||
}
|
||||
|
||||
function isSourcesAffected(int $idx) : bool
|
||||
{
|
||||
return isset($this->sources_affected[$idx]) && $this->sources_affected[$idx];
|
||||
}
|
||||
|
||||
function getAffectedSourcesIndices() : array
|
||||
{
|
||||
return array_keys($this->sources_affected);
|
||||
}
|
||||
|
||||
function isStale() : bool
|
||||
{
|
||||
return count($this->sources_affected) > 0;
|
||||
}
|
||||
|
||||
function initSources()
|
||||
{
|
||||
$file_changes = $this->task->getFileChanges();
|
||||
|
||||
$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 &&
|
||||
is_array($src_spec[0]) && is_array($src_spec[1]))
|
||||
{
|
||||
$this->setSourcesFn($src_idx, function() use($src_spec) {
|
||||
$dir2files = array();
|
||||
foreach($src_spec[0] as $spec_dir)
|
||||
$dir2files[$spec_dir] = scan_files([$spec_dir], $src_spec[1]);
|
||||
return new TaskmanDirFiles($dir2files);
|
||||
});
|
||||
|
||||
if($file_changes != null)
|
||||
{
|
||||
$this->setSourcesChangedFn($src_idx, function() use($src_spec, $file_changes) {
|
||||
$changed = array();
|
||||
foreach($src_spec[0] as $spec_dir)
|
||||
{
|
||||
$matches = $file_changes->matchDirectory($spec_dir, $src_spec[1]);
|
||||
$changed[$spec_dir] = $matches;
|
||||
}
|
||||
return new TaskmanDirFiles($changed);
|
||||
});
|
||||
}
|
||||
}
|
||||
else if(is_array($src_spec) || $src_spec instanceof \Iterator)
|
||||
{
|
||||
$this->setSourcesFn($src_idx, fn() => $src_spec);
|
||||
|
||||
if($file_changes != null)
|
||||
{
|
||||
$this->setSourcesChangedFn($src_idx,
|
||||
fn() => $file_changes->matchFiles($this->getSources($src_idx))
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
throw new Exception("Unknown artefact '{$this->getPath()}' source type" . gettype($src_spec));
|
||||
}
|
||||
}
|
||||
|
||||
function checkAffectedSources() : bool
|
||||
{
|
||||
$file_changes = $this->task->getFileChanges();
|
||||
|
||||
foreach($this->getSourcesSpec() as $src_idx => $src_spec)
|
||||
{
|
||||
$sources = $file_changes != null ? $this->getChangedSources($src_idx) : $this->getSources($src_idx);
|
||||
if(is_stale($this->getPath(), $sources))
|
||||
{
|
||||
$this->sources_affected[$src_idx] = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
class TaskmanDirFiles implements \ArrayAccess, \Countable, \Iterator
|
||||
{
|
||||
/*var array<string, string[]>*/
|
||||
private array $dir2files = array();
|
||||
|
||||
private $iter_pos = 0;
|
||||
|
||||
function __construct(array $dir2files = array())
|
||||
{
|
||||
foreach($dir2files as $dir => $files)
|
||||
$this->dir2files[$dir] = $files;
|
||||
}
|
||||
|
||||
function __toString() : string
|
||||
{
|
||||
return var_export($this->dir2files, true);
|
||||
}
|
||||
|
||||
function toMap() : array
|
||||
{
|
||||
return $this->dir2files;
|
||||
}
|
||||
|
||||
function clear()
|
||||
{
|
||||
$this->dir2files = array();
|
||||
}
|
||||
|
||||
function isEmpty() : bool
|
||||
{
|
||||
return empty($this->dir2files);
|
||||
}
|
||||
|
||||
function count() : int
|
||||
{
|
||||
$total = 0;
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
$total += count($files);
|
||||
return $total;
|
||||
}
|
||||
|
||||
function apply(callable $fn)
|
||||
{
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
$this->dir2files[$base_dir] = $fn($base_dir, $files);
|
||||
}
|
||||
|
||||
function filter(callable $filter)
|
||||
{
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
$this->dir2files[$base_dir] = array_filter($files, $filter);
|
||||
}
|
||||
|
||||
function forEachFile(callable $fn)
|
||||
{
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
{
|
||||
foreach($files as $file)
|
||||
$fn($base_dir, $file);
|
||||
}
|
||||
}
|
||||
|
||||
function add(string $base_dir, string $file)
|
||||
{
|
||||
if(!isset($this->dir2files[$base_dir]))
|
||||
$this->dir2files[$base_dir] = array();
|
||||
|
||||
$this->dir2files[$base_dir][] = $file;
|
||||
}
|
||||
|
||||
//returns [[base_dir, file1], [base_dir, file2], ...]
|
||||
function getFlatArray() : array
|
||||
{
|
||||
$flat = [];
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
{
|
||||
foreach($files as $file)
|
||||
$flat[] = [$base_dir, $file];
|
||||
}
|
||||
return $flat;
|
||||
}
|
||||
|
||||
function getAllFiles() : array
|
||||
{
|
||||
$all_files = [];
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
$all_files = array_merge($all_files, $files);
|
||||
|
||||
return $all_files;
|
||||
}
|
||||
|
||||
//ArrayAccess interface
|
||||
function offsetExists(mixed $offset) : bool
|
||||
{
|
||||
if(!is_int($offset))
|
||||
throw new Exception("Invalid offset");
|
||||
|
||||
return $this->count() > $offset;
|
||||
}
|
||||
|
||||
function offsetGet(mixed $offset) : mixed
|
||||
{
|
||||
if(!is_int($offset))
|
||||
throw new Exception("Invalid offset");
|
||||
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
{
|
||||
$n = count($files);
|
||||
if($offset - $n < 0)
|
||||
return $files[$offset];
|
||||
$offset -= $n;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function offsetSet(mixed $offset, mixed $value) : void
|
||||
{
|
||||
if(!is_int($offset))
|
||||
throw new Exception("Invalid offset");
|
||||
|
||||
foreach($this->dir2files as $base_dir => &$files)
|
||||
{
|
||||
$n = count($files);
|
||||
if($offset - $n < 0)
|
||||
{
|
||||
$files[$offset] = $value;
|
||||
return;
|
||||
}
|
||||
$offset -= $n;
|
||||
}
|
||||
}
|
||||
|
||||
function offsetUnset(mixed $offset) : void
|
||||
{
|
||||
if(!is_int($offset))
|
||||
throw new Exception("Invalid offset");
|
||||
|
||||
foreach($this->dir2files as $base_dir => $files)
|
||||
{
|
||||
$n = count($files);
|
||||
if($offset - $n < 0)
|
||||
{
|
||||
unset($files[$offset]);
|
||||
return;
|
||||
}
|
||||
$offset -= $n;
|
||||
}
|
||||
}
|
||||
|
||||
//Iterator interface
|
||||
function rewind() : void
|
||||
{
|
||||
$this->iter_pos = 0;
|
||||
}
|
||||
|
||||
function current() : mixed
|
||||
{
|
||||
return $this->offsetGet($this->iter_pos);
|
||||
}
|
||||
|
||||
function key() : mixed
|
||||
{
|
||||
return $this->iter_pos;
|
||||
}
|
||||
|
||||
function next() : void
|
||||
{
|
||||
++$this->iter_pos;
|
||||
}
|
||||
|
||||
function valid() : bool
|
||||
{
|
||||
return $this->offsetExists($this->iter_pos);
|
||||
}
|
||||
}
|
||||
|
||||
function is_stale(string $file, iterable $deps) : bool
|
||||
{
|
||||
if(!is_file($file))
|
||||
return true;
|
||||
|
||||
$fmtime = filemtime($file);
|
||||
|
||||
foreach($deps as $dep)
|
||||
{
|
||||
if($dep && is_file($dep) && (filemtime($dep) > $fmtime))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
function scan_files(array $dirs, array $only_extensions = [], int $mode = 1) : array
|
||||
{
|
||||
$files = array();
|
||||
foreach($dirs as $dir)
|
||||
{
|
||||
if(!is_dir($dir))
|
||||
continue;
|
||||
|
||||
$dir = normalize_path($dir);
|
||||
|
||||
$iter_mode = $mode == 1 ? \RecursiveIteratorIterator::LEAVES_ONLY : \RecursiveIteratorIterator::SELF_FIRST;
|
||||
$iter = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($dir), $iter_mode);
|
||||
|
||||
foreach($iter as $filename => $cur)
|
||||
{
|
||||
if(($mode == 1 && !$cur->isDir()) ||
|
||||
($mode == 2 && $cur->isDir()))
|
||||
{
|
||||
if(!$only_extensions)
|
||||
$files[] = $filename;
|
||||
else
|
||||
{
|
||||
$flen = strlen($filename);
|
||||
foreach($only_extensions as $ext)
|
||||
{
|
||||
if(substr_compare($filename, $ext, $flen-strlen($ext)) === 0)
|
||||
$files[] = $filename;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
function normalize_path(string $path) : string
|
||||
{
|
||||
$path = str_replace('\\', '/', $path);
|
||||
$path = preg_replace('/\/+/', '/', $path);
|
||||
$parts = explode('/', $path);
|
||||
$absolutes = array();
|
||||
foreach($parts as $part)
|
||||
{
|
||||
if('.' == $part)
|
||||
continue;
|
||||
|
||||
if('..' == $part)
|
||||
array_pop($absolutes);
|
||||
else
|
||||
$absolutes[] = $part;
|
||||
}
|
||||
return implode(DIRECTORY_SEPARATOR, $absolutes);
|
||||
}
|
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
namespace taskman\internal;
|
||||
use Exception;
|
||||
|
||||
function _default_logger($msg)
|
||||
{
|
||||
echo $msg;
|
||||
}
|
||||
|
||||
function _default_usage($script_name = "<taskman-script>")
|
||||
{
|
||||
echo "\nUsage:\n $script_name [OPTIONS] <task-name1>[,<task-name2>,..] [-D PROP1=value [-D PROP2]]\n\n";
|
||||
echo "Available options:\n";
|
||||
echo " -c specify PHP script to be included (handy for setting props,config options,etc)\n";
|
||||
echo " -V be super verbose\n";
|
||||
echo " -q be quite, only system messages\n";
|
||||
echo " -b batch mode: be super quite, don't even output any system messages\n";
|
||||
echo " -- pass all options verbatim after this mark\n";
|
||||
}
|
||||
|
||||
function _collect_tasks()
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
global $TASKMAN_FILE_CHANGES;
|
||||
|
||||
$TASKMAN_TASKS = array();
|
||||
$TASKMAN_TASK_ALIASES = array();
|
||||
|
||||
$cands = _get_task_candidates();
|
||||
foreach($cands as $name => $args)
|
||||
{
|
||||
if(isset($TASKMAN_TASKS[$name]))
|
||||
throw new \taskman\TaskmanException("Task '$name' is already defined");
|
||||
|
||||
if(is_array($args))
|
||||
{
|
||||
$props = array();
|
||||
if(sizeof($args) > 2)
|
||||
{
|
||||
$props = $args[1];
|
||||
$func = $args[2];
|
||||
}
|
||||
else
|
||||
$func = $args[1];
|
||||
|
||||
$task = new \taskman\TaskmanTask($func, $name, $props, $TASKMAN_FILE_CHANGES);
|
||||
}
|
||||
else
|
||||
throw new Exception("Task '$name' is invalid");
|
||||
|
||||
$TASKMAN_TASKS[$name] = $task;
|
||||
|
||||
foreach($task->getAliases() as $alias)
|
||||
{
|
||||
if(isset($TASKMAN_TASKS[$alias]) || isset($TASKMAN_TASK_ALIASES[$alias]))
|
||||
throw new \taskman\TaskmanException("Alias '$alias' is already defined for task '$name'");
|
||||
$TASKMAN_TASK_ALIASES[$alias] = $task;
|
||||
}
|
||||
}
|
||||
|
||||
_validate_tasks();
|
||||
}
|
||||
|
||||
function _validate_tasks()
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
|
||||
foreach($TASKMAN_TASKS as $task)
|
||||
{
|
||||
try
|
||||
{
|
||||
$before = $task->getPropOr("before", "");
|
||||
if($before)
|
||||
\taskman\get_task($before)->addBeforeDep($task);
|
||||
|
||||
$after = $task->getPropOr("after", "");
|
||||
if($after)
|
||||
\taskman\get_task($after)->addAfterDep($task);
|
||||
|
||||
foreach($task->getDeps() as $dep_task)
|
||||
\taskman\get_task($dep_task);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new Exception("Task '{$task->getName()}' validation error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _get_task_candidates()
|
||||
{
|
||||
global $TASKMAN_CLOSURES;
|
||||
|
||||
$cands = array();
|
||||
|
||||
//get tasks defined as closures
|
||||
foreach($TASKMAN_CLOSURES as $name => $args)
|
||||
{
|
||||
$cands[$name] = $args;
|
||||
}
|
||||
|
||||
ksort($cands);
|
||||
|
||||
return $cands;
|
||||
}
|
||||
|
||||
function _resolve_callable_prop($name)
|
||||
{
|
||||
$prop = $GLOBALS['TASKMAN_PROP_' . $name];
|
||||
if(!($prop instanceof \Closure))
|
||||
return;
|
||||
$value = $prop();
|
||||
$GLOBALS['TASKMAN_PROP_' . $name] = $value;
|
||||
}
|
||||
|
||||
function _isset_task($task)
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
return isset($TASKMAN_TASKS[$task]) || isset($TASKMAN_TASK_ALIASES[$task]);
|
||||
}
|
||||
|
||||
function _get_hints($task)
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
$tasks = array_merge(array_keys($TASKMAN_TASKS), array_keys($TASKMAN_TASK_ALIASES));
|
||||
$found = array_filter($tasks, function($v) use($task) { return strpos($v, $task) === 0; });
|
||||
$found = array_merge($found, array_filter($tasks, function($v) use($task) { $pos = strpos($v, $task); return $pos !== false && $pos > 0; }));
|
||||
return $found;
|
||||
}
|
||||
|
||||
//e.g: run,build,zip
|
||||
function _parse_taskstr($str)
|
||||
{
|
||||
$task_spec = array();
|
||||
$items = explode(',', $str);
|
||||
foreach($items as $item)
|
||||
{
|
||||
$args = null;
|
||||
$task = $item;
|
||||
if(strpos($item, ' ') !== false)
|
||||
@list($task, $args) = explode(' ', $item, 2);
|
||||
|
||||
if($args)
|
||||
$task_spec[] = array($task, explode(' ', $args));
|
||||
else
|
||||
$task_spec[] = $task;
|
||||
}
|
||||
return $task_spec;
|
||||
}
|
||||
|
||||
function _read_env_vars()
|
||||
{
|
||||
$envs = getenv();
|
||||
|
||||
foreach($envs as $k => $v)
|
||||
{
|
||||
if(strpos($k, 'TASKMAN_SET_') === 0)
|
||||
{
|
||||
$prop_name = substr($k, 12);
|
||||
\taskman\log(0, "Setting prop '$prop_name' (with env '$k')\n");
|
||||
\taskman\set($prop_name, $v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function _process_argv(array &$argv)
|
||||
{
|
||||
global $TASKMAN_LOG_LEVEL;
|
||||
global $TASKMAN_BATCH;
|
||||
global $TASKMAN_NO_DEPS;
|
||||
global $TASKMAN_FILE_CHANGES;
|
||||
|
||||
$filtered = array();
|
||||
$process_defs = false;
|
||||
|
||||
for($i=0;$i<sizeof($argv);++$i)
|
||||
{
|
||||
$v = $argv[$i];
|
||||
|
||||
if($v == '--')
|
||||
{
|
||||
for($j=$i+1;$j<sizeof($argv);++$j)
|
||||
$filtered[] = $argv[$j];
|
||||
break;
|
||||
}
|
||||
else if($v == '-D')
|
||||
{
|
||||
$process_defs = true;
|
||||
}
|
||||
else if($v == '-V')
|
||||
{
|
||||
$TASKMAN_LOG_LEVEL = 2;
|
||||
}
|
||||
else if($v == '-q')
|
||||
{
|
||||
$TASKMAN_LOG_LEVEL = 0;
|
||||
}
|
||||
else if($v == '-b')
|
||||
{
|
||||
$TASKMAN_LOG_LEVEL = -1;
|
||||
}
|
||||
else if($v == '-O')
|
||||
{
|
||||
$TASKMAN_NO_DEPS = true;
|
||||
}
|
||||
else if($v == '-c')
|
||||
{
|
||||
if(!isset($argv[$i+1]))
|
||||
throw new \taskman\TaskmanException("Configuration file(-c option) is missing");
|
||||
require_once($argv[$i+1]);
|
||||
++$i;
|
||||
}
|
||||
else if($v == '-F')
|
||||
{
|
||||
if(!isset($argv[$i+1]))
|
||||
throw new \taskman\TaskmanException("Argument(-F option) is missing");
|
||||
|
||||
$TASKMAN_FILE_CHANGES = \taskman\TaskmanFileChanges::parse($argv[$i+1]);
|
||||
|
||||
++$i;
|
||||
}
|
||||
else if($process_defs)
|
||||
{
|
||||
$eq_pos = strpos($v, '=');
|
||||
if($eq_pos !== false)
|
||||
{
|
||||
$def_name = substr($v, 0, $eq_pos);
|
||||
$def_value = substr($v, $eq_pos+1);
|
||||
|
||||
//TODO: this code must be more robust
|
||||
if(strtolower($def_value) === 'true')
|
||||
$def_value = true;
|
||||
else if(strtolower($def_value) === 'false')
|
||||
$def_value = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$def_name = $v;
|
||||
$def_value = 1;
|
||||
}
|
||||
|
||||
\taskman\log(0, "Setting prop '$def_name'=" . var_export($def_value, true) . "\n");
|
||||
\taskman\set($def_name, $def_value);
|
||||
|
||||
$process_defs = false;
|
||||
}
|
||||
else
|
||||
$filtered[] = $v;
|
||||
}
|
||||
$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;
|
||||
}
|
||||
|
160
tags
160
tags
|
@ -1,160 +0,0 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
|
||||
!_TAG_PROGRAM_NAME Exuberant Ctags //
|
||||
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.8 //
|
||||
TASKMAN_CURRENT_TASK taskman.inc.php /^ $TASKMAN_CURRENT_TASK = $this;$/;" v
|
||||
TASKMAN_LOG_LEVEL taskman.inc.php /^ $TASKMAN_LOG_LEVEL = -1;$/;" v
|
||||
TASKMAN_LOG_LEVEL taskman.inc.php /^ $TASKMAN_LOG_LEVEL = 0;$/;" v
|
||||
TASKMAN_LOG_LEVEL taskman.inc.php /^ $TASKMAN_LOG_LEVEL = 2;$/;" v
|
||||
TASKMAN_NO_DEPS taskman.inc.php /^ $TASKMAN_NO_DEPS = true;$/;" v
|
||||
TASKMAN_TASKS taskman.inc.php /^ $TASKMAN_TASKS = array();$/;" v
|
||||
TASKMAN_TASK_ALIASES taskman.inc.php /^ $TASKMAN_TASK_ALIASES = array();$/;" v
|
||||
TaskmanException taskman.inc.php /^class TaskmanException extends Exception$/;" c
|
||||
TaskmanTask taskman.inc.php /^class TaskmanTask$/;" c
|
||||
_ taskman.inc.php /^function _($str) $/;" f
|
||||
__construct taskman.inc.php /^ function __construct(\\Closure $func, $name, $props = array())$/;" f
|
||||
_collectRelatedTasks taskman.inc.php /^ private function _collectRelatedTasks($prop_name)$/;" f
|
||||
_collect_tasks taskman.inc.php /^function _collect_tasks()$/;" f
|
||||
_getAfterDeps taskman.inc.php /^ private function _getAfterDeps()$/;" f
|
||||
_getBeforeDeps taskman.inc.php /^ private function _getBeforeDeps()$/;" f
|
||||
_getDeps taskman.inc.php /^ private function _getDeps()$/;" f
|
||||
_get_hints taskman.inc.php /^function _get_hints($task)$/;" f
|
||||
_get_task_candidates taskman.inc.php /^function _get_task_candidates()$/;" f
|
||||
_isset_task taskman.inc.php /^function _isset_task($task)$/;" f
|
||||
_log taskman.inc.php /^function _log($msg, $level = 1)$/;" f
|
||||
_parse_taskstr taskman.inc.php /^function _parse_taskstr($str)$/;" f
|
||||
_process_argv taskman.inc.php /^function _process_argv(&$argv)$/;" f
|
||||
_resolve_callable_prop taskman.inc.php /^function _resolve_callable_prop($name)$/;" f
|
||||
_taskman_default_logger taskman.inc.php /^function _taskman_default_logger($msg)$/;" f
|
||||
_taskman_default_usage taskman.inc.php /^function _taskman_default_usage($script_name = "<taskman-script>")$/;" f
|
||||
alias taskman.inc.php /^ $alias = $this->getPropOr("alias", "");$/;" v
|
||||
all taskman.inc.php /^ $all = get_tasks();$/;" v
|
||||
always_tasks taskman.inc.php /^ $always_tasks = array();$/;" v
|
||||
args taskman.inc.php /^ $args = null;$/;" v
|
||||
args taskman.inc.php /^ $this->args = $args;$/;" v
|
||||
args taskman.inc.php /^ $args = func_get_args();$/;" v
|
||||
args taskman.inc.php /^ private $args = array();$/;" v
|
||||
args taskman.inc.php /^function run($task, array $args = array())$/;" v
|
||||
args taskman.inc.php /^function run_many($tasks, $args = array())$/;" v
|
||||
args_str taskman.inc.php /^ $args_str = serialize($args);$/;" v
|
||||
argv taskman.inc.php /^ $argv = $filtered;$/;" v
|
||||
arr taskman.inc.php /^ $arr = array();$/;" v
|
||||
bench taskman.inc.php /^ $bench = microtime(true);$/;" v
|
||||
cands taskman.inc.php /^ $cands = _get_task_candidates();$/;" v
|
||||
cands taskman.inc.php /^ $cands = array();$/;" v
|
||||
current_task taskman.inc.php /^function current_task()$/;" f
|
||||
def_name taskman.inc.php /^ $def_name = $v;$/;" v
|
||||
def_name taskman.inc.php /^ $def_name = substr($v, 0, $eq_pos);$/;" v
|
||||
def_name taskman.inc.php /^ msg_sys("Setting prop $def_name=" . (is_bool($def_value) ? ($def_value ? 'true' : 'false') : $def_value) . "\\n");$/;" v
|
||||
def_value taskman.inc.php /^ $def_value = false;$/;" v
|
||||
def_value taskman.inc.php /^ $def_value = true;$/;" v
|
||||
def_value taskman.inc.php /^ $def_value = 1;$/;" v
|
||||
def_value taskman.inc.php /^ $def_value = substr($v, $eq_pos+1);$/;" v
|
||||
default_task taskman.inc.php /^ $default_task = $task_obj;$/;" v
|
||||
default_task taskman.inc.php /^ $default_task = null;$/;" v
|
||||
del taskman.inc.php /^function del($name)$/;" f
|
||||
deps taskman.inc.php /^ $deps = $this->getPropOr('deps', "");$/;" v
|
||||
eq_pos taskman.inc.php /^ $eq_pos = strpos($v, '=');$/;" v
|
||||
error_handler taskman.inc.php /^ $error_handler = $GLOBALS['TASKMAN_ERROR_HANDLER'];$/;" v
|
||||
extractName taskman.inc.php /^ static function extractName($func)$/;" f
|
||||
file taskman.inc.php /^ $file = $task->getFile();$/;" v
|
||||
file taskman.inc.php /^ $this->file = $refl->getFileName();$/;" v
|
||||
file taskman.inc.php /^ private $file;$/;" v
|
||||
filter taskman.inc.php /^ $filter = $args[0];$/;" v
|
||||
filter taskman.inc.php /^ $filter = '';$/;" v
|
||||
filtered taskman.inc.php /^ $filtered = array();$/;" v
|
||||
found taskman.inc.php /^ $found = array_filter($tasks, function($v) use($task) { return strpos($v, $task) === 0; });$/;" v
|
||||
found taskman.inc.php /^ $found = array_merge($found, array_filter($tasks, function($v) use($task) { $pos = strpos($v, $task); return $pos !== false && $pos > 0; }));$/;" v
|
||||
func taskman.inc.php /^ $func = $args[1];$/;" v
|
||||
func taskman.inc.php /^ $func = $args[2];$/;" v
|
||||
func taskman.inc.php /^ $this->func = $func;$/;" v
|
||||
func taskman.inc.php /^ private $func;$/;" v
|
||||
get taskman.inc.php /^function get($name)$/;" f
|
||||
getAliases taskman.inc.php /^ function getAliases()$/;" f
|
||||
getArgs taskman.inc.php /^ function getArgs()$/;" f
|
||||
getFile taskman.inc.php /^ function getFile()$/;" f
|
||||
getFunc taskman.inc.php /^ function getFunc()$/;" f
|
||||
getLine taskman.inc.php /^ function getLine()$/;" f
|
||||
getName taskman.inc.php /^ function getName()$/;" f
|
||||
getProp taskman.inc.php /^ function getProp($name)$/;" f
|
||||
getPropOr taskman.inc.php /^ function getPropOr($name, $def)$/;" f
|
||||
getProps taskman.inc.php /^ function getProps()$/;" f
|
||||
get_task taskman.inc.php /^function get_task($task)$/;" f
|
||||
get_tasks taskman.inc.php /^function get_tasks()$/;" f
|
||||
getor taskman.inc.php /^function getor($name, $def)$/;" f
|
||||
hasProp taskman.inc.php /^ function hasProp($name)$/;" f
|
||||
has_run taskman.inc.php /^ private $has_run = array();$/;" v
|
||||
help_func taskman.inc.php /^ $help_func = $GLOBALS['TASKMAN_HELP_FUNC'];$/;" v
|
||||
help_func taskman.inc.php /^function main($argv = array(), $help_func = null, $proc_argv = true)$/;" v
|
||||
hints taskman.inc.php /^ $hints = _get_hints($pattern);$/;" v
|
||||
is taskman.inc.php /^function is($name)$/;" f
|
||||
is_running taskman.inc.php /^ $this->is_running = false;$/;" v
|
||||
is_running taskman.inc.php /^ $this->is_running = true;$/;" v
|
||||
is_running taskman.inc.php /^ private $is_running = false;$/;" v
|
||||
is_similar taskman.inc.php /^ $is_similar = false;$/;" v
|
||||
is_similar taskman.inc.php /^ $is_similar = true;$/;" v
|
||||
items taskman.inc.php /^ $items = explode(',', $str);$/;" v
|
||||
k taskman.inc.php /^ foreach($props as $k => $v)$/;" v
|
||||
key taskman.inc.php /^ foreach($GLOBALS as $key => $value)$/;" v
|
||||
level taskman.inc.php /^ $level = count($TASKMAN_STACK)-1; $/;" v
|
||||
level taskman.inc.php /^function _log($msg, $level = 1)$/;" v
|
||||
line taskman.inc.php /^ $line = $task->getLine();$/;" v
|
||||
line taskman.inc.php /^ $this->line = $refl->getStartLine();$/;" v
|
||||
line taskman.inc.php /^ private $line;$/;" v
|
||||
logger taskman.inc.php /^ $logger = $GLOBALS['TASKMAN_LOGGER'];$/;" v
|
||||
main taskman.inc.php /^function main($argv = array(), $help_func = null, $proc_argv = true)$/;" f
|
||||
maxlen taskman.inc.php /^ $maxlen = strlen($task->getName());$/;" v
|
||||
maxlen taskman.inc.php /^ $maxlen = -1;$/;" v
|
||||
msg taskman.inc.php /^function msg($msg)$/;" f
|
||||
msg_dbg taskman.inc.php /^function msg_dbg($msg)$/;" f
|
||||
msg_sys taskman.inc.php /^function msg_sys($msg)$/;" f
|
||||
name taskman.inc.php /^ $name = substr($key, strlen('TASKMAN_PROP_'));$/;" v
|
||||
name taskman.inc.php /^ $this->name = $name;$/;" v
|
||||
name taskman.inc.php /^ foreach($task->getProps() as $name => $value)$/;" v
|
||||
name taskman.inc.php /^ foreach($TASKMAN_CLOSURES as $name => $args)$/;" v
|
||||
name taskman.inc.php /^ foreach($cands as $name => $args)$/;" v
|
||||
name taskman.inc.php /^ private $name;$/;" v
|
||||
pad taskman.inc.php /^ $pad = $maxlen + 1;$/;" v
|
||||
pad taskman.inc.php /^ $pad = $maxlen - strlen($task->getName());$/;" v
|
||||
pattern taskman.inc.php /^ $pattern = substr($pattern, 0, strlen($pattern) - 1);$/;" v
|
||||
pattern taskman.inc.php /^ $pattern = substr($pattern, 1, strlen($pattern) - 1);$/;" v
|
||||
pattern taskman.inc.php /^ $pattern = $tasks[0];$/;" v
|
||||
process_defs taskman.inc.php /^ $process_defs = false;$/;" v
|
||||
process_defs taskman.inc.php /^ $process_defs = true;$/;" v
|
||||
process_defs taskman.inc.php /^ $process_defs = false;$/;" v
|
||||
prop taskman.inc.php /^ $prop = $GLOBALS['TASKMAN_PROP_' . $name];$/;" v
|
||||
props taskman.inc.php /^ $props = $args[1];$/;" v
|
||||
props taskman.inc.php /^ $props = array();$/;" v
|
||||
props taskman.inc.php /^ $this->props = $props;$/;" v
|
||||
props taskman.inc.php /^ $props = array();$/;" v
|
||||
props taskman.inc.php /^ $props = props();$/;" v
|
||||
props taskman.inc.php /^ function __construct(\\Closure $func, $name, $props = array())$/;" v
|
||||
props taskman.inc.php /^ private $props = array();$/;" v
|
||||
props taskman.inc.php /^function props()$/;" f
|
||||
props_string taskman.inc.php /^ $props_string = '';$/;" v
|
||||
props_string taskman.inc.php /^ $props_string = rtrim($props_string);$/;" v
|
||||
refl taskman.inc.php /^ $refl = new \\ReflectionFunction($func);$/;" v
|
||||
run taskman.inc.php /^ function run($args = array())$/;" f
|
||||
run taskman.inc.php /^function run($task, array $args = array())$/;" f
|
||||
run_many taskman.inc.php /^function run_many($tasks, $args = array())$/;" f
|
||||
set taskman.inc.php /^function set($name, $value)$/;" f
|
||||
setor taskman.inc.php /^function setor($name, $value)$/;" f
|
||||
str taskman.inc.php /^ $str = preg_replace_callback($/;" v
|
||||
task taskman.inc.php /^ $task = new TaskmanTask($func, $name, $props);$/;" v
|
||||
task taskman.inc.php /^ $task = $item;$/;" v
|
||||
task taskman.inc.php /^function task($name)$/;" f
|
||||
task_obj taskman.inc.php /^ $task_obj = $task;$/;" v
|
||||
task_obj taskman.inc.php /^ $task_obj = get_task($task);$/;" v
|
||||
task_spec taskman.inc.php /^ $task_spec = array();$/;" v
|
||||
task_str taskman.inc.php /^ $task_str = array_shift($argv);$/;" v
|
||||
tasks taskman.inc.php /^ $tasks = $hints;$/;" v
|
||||
tasks taskman.inc.php /^ $tasks = _parse_taskstr($task_str);$/;" v
|
||||
tasks taskman.inc.php /^ $tasks = array();$/;" v
|
||||
tasks taskman.inc.php /^ $tasks = array_merge(array_keys($TASKMAN_TASKS), array_keys($TASKMAN_TASK_ALIASES));$/;" v
|
||||
usage taskman.inc.php /^function usage($script_name = "<taskman-script>")$/;" f
|
||||
v taskman.inc.php /^ $v = $argv[$i];$/;" v
|
||||
validate taskman.inc.php /^ function validate()$/;" f
|
||||
value taskman.inc.php /^ $value = $task_obj->getPropOr($prop_name, "");$/;" v
|
||||
value taskman.inc.php /^ $value = $prop();$/;" v
|
798
taskman.inc.php
798
taskman.inc.php
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
namespace {
|
||||
namespace taskman;
|
||||
use Exception;
|
||||
|
||||
$GLOBALS['TASKMAN_TASKS'] = array();
|
||||
$GLOBALS['TASKMAN_CLOSURES'] = array();
|
||||
|
@ -9,47 +10,48 @@ $GLOBALS['TASKMAN_LOG_LEVEL'] = 1; //0 - important, 1 - normal, 2 - debug
|
|||
$GLOBALS['TASKMAN_NO_DEPS'] = false;
|
||||
$GLOBALS['TASKMAN_SCRIPT'] = '';
|
||||
$GLOBALS['TASKMAN_CURRENT_TASK'] = null;
|
||||
$GLOBALS['TASKMAN_HELP_FUNC'] = '_taskman_default_usage';
|
||||
$GLOBALS['TASKMAN_LOGGER'] = '_taskman_default_logger';
|
||||
$GLOBALS['TASKMAN_HELP_FUNC'] = '\taskman\internal\_default_usage';
|
||||
$GLOBALS['TASKMAN_LOGGER'] = '\taskman\internal\_default_logger';
|
||||
$GLOBALS['TASKMAN_ERROR_HANDLER'] = null;
|
||||
$GLOBALS['TASKMAN_START_TIME'] = 0;
|
||||
$GLOBALS['TASKMAN_FILES_CHANGES'] = null;
|
||||
|
||||
function _taskman_default_logger($msg)
|
||||
{
|
||||
echo $msg;
|
||||
}
|
||||
|
||||
function _taskman_default_usage($script_name = "<taskman-script>")
|
||||
{
|
||||
echo "\nUsage:\n $script_name [OPTIONS] <task-name1>[,<task-name2>,..] [-D PROP1=value [-D PROP2]]\n\n";
|
||||
echo "Available options:\n";
|
||||
echo " -c specify PHP script to be included (handy for setting props,config options,etc)\n";
|
||||
echo " -V be super verbose\n";
|
||||
echo " -q be quite, only system messages\n";
|
||||
echo " -b batch mode: be super quite, don't even output any system messages\n";
|
||||
echo " -- pass all options verbatim after this mark\n";
|
||||
}
|
||||
|
||||
} //namespace global
|
||||
|
||||
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');
|
||||
|
||||
class TaskmanException extends Exception
|
||||
{}
|
||||
|
||||
class TaskmanTask
|
||||
{
|
||||
private $func;
|
||||
private $name;
|
||||
private $file;
|
||||
private $line;
|
||||
private $props = array();
|
||||
private $is_running = false;
|
||||
private $has_run = array();
|
||||
private \Closure $func;
|
||||
|
||||
private string $file;
|
||||
private int $line;
|
||||
|
||||
private string $name;
|
||||
//initialized lazily
|
||||
private ?array $_aliases = null;
|
||||
|
||||
private $args = array();
|
||||
|
||||
function __construct(\Closure $func, $name, $props = array())
|
||||
private $props = array();
|
||||
private bool $is_running = false;
|
||||
private array $has_run = array();
|
||||
|
||||
private ?array $deps = null;
|
||||
private array $before_deps = array();
|
||||
private array $after_deps = array();
|
||||
|
||||
//initialized lazily
|
||||
private ?array $_artefacts = null;
|
||||
|
||||
private ?TaskmanFileChanges $file_changes;
|
||||
|
||||
function __construct(\Closure $func, string $name,
|
||||
array $props = array(), ?TaskmanFileChanges $file_changes = null)
|
||||
{
|
||||
$refl = new \ReflectionFunction($func);
|
||||
$this->file = $refl->getFileName();
|
||||
|
@ -58,53 +60,43 @@ class TaskmanTask
|
|||
$this->func = $func;
|
||||
$this->name = $name;
|
||||
$this->props = $props;
|
||||
|
||||
$this->file_changes = $file_changes;
|
||||
}
|
||||
|
||||
function validate()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach($this->_getBeforeDeps() as $dep_task)
|
||||
get_task($dep_task);
|
||||
|
||||
foreach($this->_getDeps() as $dep_task)
|
||||
get_task($dep_task);
|
||||
|
||||
foreach($this->_getAfterDeps() as $dep_task)
|
||||
get_task($dep_task);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
throw new Exception("Task '{$this->name}' validation error: " . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
function getName()
|
||||
function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function getFile()
|
||||
function getFile() : string
|
||||
{
|
||||
return $this->file;
|
||||
}
|
||||
|
||||
function getLine()
|
||||
function getLine() : int
|
||||
{
|
||||
return $this->line;
|
||||
}
|
||||
|
||||
function getFunc()
|
||||
function getFunc() : \Closure
|
||||
{
|
||||
return $this->func;
|
||||
}
|
||||
|
||||
function getArgs()
|
||||
function getArgs() : array
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
function getAliases()
|
||||
function getAliases() : array
|
||||
{
|
||||
if($this->_aliases === null)
|
||||
$this->_aliases = $this->_parseAliases();
|
||||
return $this->_aliases;
|
||||
}
|
||||
|
||||
function _parseAliases() : array
|
||||
{
|
||||
$alias = $this->getPropOr("alias", "");
|
||||
if(is_array($alias))
|
||||
|
@ -115,6 +107,50 @@ class TaskmanTask
|
|||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return artefact\TaskmanArtefact[]
|
||||
*/
|
||||
function getArtefacts() : array
|
||||
{
|
||||
if($this->_artefacts === null)
|
||||
$this->_artefacts = $this->_parseArtefacts();
|
||||
return $this->_artefacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return artefact\TaskmanArtefact[]
|
||||
*/
|
||||
function _parseArtefacts() : array
|
||||
{
|
||||
$artefacts = array();
|
||||
$specs = $this->getPropOr("artefacts", array());
|
||||
if(is_callable($specs))
|
||||
$specs = $specs();
|
||||
|
||||
if(is_array($specs))
|
||||
{
|
||||
foreach($specs as $dst => $src_spec)
|
||||
$artefacts[] = new artefact\TaskmanArtefact($this, $dst, $src_spec);
|
||||
}
|
||||
|
||||
return $artefacts;
|
||||
}
|
||||
|
||||
function getArtefact(int $idx) : artefact\TaskmanArtefact
|
||||
{
|
||||
return $this->getArtefacts()[$idx];
|
||||
}
|
||||
|
||||
function getFileChanges() : ?TaskmanFileChanges
|
||||
{
|
||||
return $this->file_changes;
|
||||
}
|
||||
|
||||
function isIncrementalBuild() : bool
|
||||
{
|
||||
return $this->file_changes != null;
|
||||
}
|
||||
|
||||
function run($args = array())
|
||||
{
|
||||
global $TASKMAN_CURRENT_TASK;
|
||||
|
@ -128,34 +164,42 @@ class TaskmanTask
|
|||
$this->is_running)
|
||||
return;
|
||||
|
||||
$this->is_running = true;
|
||||
$this->args = $args;
|
||||
$task_result = null;
|
||||
|
||||
try
|
||||
{
|
||||
if($this->getArtefacts() && !$this->_checkIfArtefactsStale())
|
||||
{
|
||||
$this->has_run[$args_str] = true;
|
||||
return;
|
||||
}
|
||||
|
||||
$this->is_running = true;
|
||||
$this->args = $args;
|
||||
|
||||
$TASKMAN_STACK[] = $this;
|
||||
|
||||
$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)
|
||||
{
|
||||
run_many($this->_getBeforeDeps());
|
||||
run_many($this->_getDeps());
|
||||
run_many($this->before_deps);
|
||||
run_many($this->getDeps());
|
||||
}
|
||||
|
||||
$TASKMAN_CURRENT_TASK = $this;
|
||||
|
||||
$bench = microtime(true);
|
||||
|
||||
call_user_func_array($this->func, array($this->args));
|
||||
$task_result = call_user_func_array($this->func, array($this->args, $this));
|
||||
array_pop($TASKMAN_STACK);
|
||||
|
||||
if(!$TASKMAN_NO_DEPS)
|
||||
run_many($this->_getAfterDeps());
|
||||
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;
|
||||
|
@ -169,416 +213,251 @@ class TaskmanTask
|
|||
else
|
||||
throw $e;
|
||||
}
|
||||
|
||||
return $task_result;
|
||||
}
|
||||
|
||||
private function _getBeforeDeps()
|
||||
function addBeforeDep($task)
|
||||
{
|
||||
return $this->_collectRelatedTasks("before");
|
||||
$this->before_deps[] = $task;
|
||||
}
|
||||
|
||||
private function _getAfterDeps()
|
||||
function addAfterDep($task)
|
||||
{
|
||||
return $this->_collectRelatedTasks("after");
|
||||
$this->after_deps[] = $task;
|
||||
}
|
||||
|
||||
private function _collectRelatedTasks($prop_name)
|
||||
function getDeps() : array
|
||||
{
|
||||
$arr = array();
|
||||
foreach(get_tasks() as $task_obj)
|
||||
{
|
||||
if($this->getName() == $task_obj->getName())
|
||||
continue;
|
||||
|
||||
$value = $task_obj->getPropOr($prop_name, "");
|
||||
if($value == $this->getName() || in_array($value, $this->getAliases()))
|
||||
$arr[] = $task_obj;
|
||||
}
|
||||
return $arr;
|
||||
if($this->deps === null)
|
||||
$this->deps = $this->_parseDeps();
|
||||
return $this->deps;
|
||||
}
|
||||
|
||||
private function _getDeps()
|
||||
private function _parseDeps() : array
|
||||
{
|
||||
$deps = $this->getPropOr('deps', "");
|
||||
$deps = $this->getPropOr("deps", "");
|
||||
if(is_array($deps))
|
||||
return $deps;
|
||||
else if($deps && is_string($deps))
|
||||
return _parse_taskstr($deps);
|
||||
return internal\_parse_taskstr($deps);
|
||||
return array();
|
||||
}
|
||||
|
||||
static function extractName($func)
|
||||
{
|
||||
if(strpos($func, "task_") === 0)
|
||||
return substr($func, strlen('task_'), strlen($func));
|
||||
else if(strpos($func, 'taskman\task_') === 0)
|
||||
return substr($func, strlen('taskman\task_'), strlen($func));
|
||||
}
|
||||
|
||||
function getPropOr($name, $def)
|
||||
function getPropOr(string $name, mixed $def) : mixed
|
||||
{
|
||||
return isset($this->props[$name]) ? $this->props[$name] : $def;
|
||||
}
|
||||
|
||||
function getProp($name)
|
||||
function getProp(string $name) : mixed
|
||||
{
|
||||
return $this->getPropOr($name, null);
|
||||
}
|
||||
|
||||
function hasProp($name)
|
||||
function hasProp(string $name) : bool
|
||||
{
|
||||
return isset($this->props[$name]);
|
||||
}
|
||||
|
||||
function getProps()
|
||||
function getProps() : array
|
||||
{
|
||||
return $this->props;
|
||||
}
|
||||
}
|
||||
|
||||
function _collect_tasks()
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
|
||||
$TASKMAN_TASKS = array();
|
||||
$TASKMAN_TASK_ALIASES = array();
|
||||
|
||||
$cands = _get_task_candidates();
|
||||
foreach($cands as $name => $args)
|
||||
private function _checkIfArtefactsStale() : bool
|
||||
{
|
||||
if(isset($TASKMAN_TASKS[$name]))
|
||||
throw new TaskmanException("Task '$name' is already defined");
|
||||
$stale_found = false;
|
||||
|
||||
if(is_array($args))
|
||||
foreach($this->getArtefacts() as $artefact)
|
||||
{
|
||||
$props = array();
|
||||
if(sizeof($args) > 2)
|
||||
$artefact->initSources();
|
||||
|
||||
if(!$stale_found && $artefact->checkAffectedSources())
|
||||
$stale_found = true;
|
||||
|
||||
if($artefact->isStale())
|
||||
{
|
||||
$props = $args[1];
|
||||
$func = $args[2];
|
||||
log(0, "Task '{$this->name}' artefact '{$artefact->getPath()}' (sources at ".implode(',', $artefact->getAffectedSourcesIndices()).") is stale\n");
|
||||
}
|
||||
else
|
||||
$func = $args[1];
|
||||
|
||||
$task = new TaskmanTask($func, $name, $props);
|
||||
}
|
||||
|
||||
return $stale_found;
|
||||
}
|
||||
|
||||
function findAnyStaleArtefact() : ?artefact\TaskmanArtefact
|
||||
{
|
||||
foreach($this->getArtefacts() as $artefact)
|
||||
{
|
||||
if($artefact->isStale())
|
||||
return $artefact;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
class TaskmanFileChanges
|
||||
{
|
||||
const Changed = 1;
|
||||
const Created = 2;
|
||||
const Renamed = 3;
|
||||
const Deleted = 4;
|
||||
|
||||
//file => status
|
||||
private $changed = array();
|
||||
|
||||
static function parse(string $json_or_file)
|
||||
{
|
||||
if($json_or_file[0] == '[')
|
||||
$json = $json_or_file;
|
||||
else
|
||||
throw new Exception("Task '$name' is invalid");
|
||||
|
||||
$TASKMAN_TASKS[$name] = $task;
|
||||
|
||||
foreach($task->getAliases() as $alias)
|
||||
{
|
||||
if(isset($TASKMAN_TASKS[$alias]) || isset($TASKMAN_TASK_ALIASES[$alias]))
|
||||
throw new TaskmanException("Alias '$alias' is already defined for task '$name'");
|
||||
$TASKMAN_TASK_ALIASES[$alias] = $task;
|
||||
$lines = internal\_extract_lines_from_file($json_or_file);
|
||||
$json = '[' . implode(',', $lines) . ']';
|
||||
}
|
||||
}
|
||||
|
||||
foreach($TASKMAN_TASKS as $task)
|
||||
$task->validate();
|
||||
}
|
||||
$decoded = json_decode($json, true);
|
||||
if(!is_array($decoded))
|
||||
throw new Exception('Bad json: ' . $json);
|
||||
|
||||
function _get_task_candidates()
|
||||
{
|
||||
global $TASKMAN_CLOSURES;
|
||||
$changed = array();
|
||||
|
||||
$cands = array();
|
||||
$base_dir = dirname($_SERVER['PHP_SELF']);
|
||||
//for debug
|
||||
//var_dump($decoded);
|
||||
|
||||
//get tasks defined as closures
|
||||
foreach($TASKMAN_CLOSURES as $name => $args)
|
||||
{
|
||||
if(isset($cands[$name]))
|
||||
throw new Exception("Task '$name' is already defined");
|
||||
$cands[$name] = $args;
|
||||
}
|
||||
|
||||
ksort($cands);
|
||||
|
||||
return $cands;
|
||||
}
|
||||
|
||||
function get_task($task)
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
|
||||
if(!is_scalar($task))
|
||||
throw new TaskmanException("Bad task name");
|
||||
|
||||
if(isset($TASKMAN_TASKS[$task]))
|
||||
return $TASKMAN_TASKS[$task];
|
||||
|
||||
if(isset($TASKMAN_TASK_ALIASES[$task]))
|
||||
return $TASKMAN_TASK_ALIASES[$task];
|
||||
|
||||
throw new TaskmanException("Task with name/alias '{$task}' does not exist");
|
||||
}
|
||||
|
||||
function _resolve_callable_prop($name)
|
||||
{
|
||||
$prop = $GLOBALS['TASKMAN_PROP_' . $name];
|
||||
if(!($prop instanceof \Closure))
|
||||
return;
|
||||
$value = $prop();
|
||||
$GLOBALS['TASKMAN_PROP_' . $name] = $value;
|
||||
}
|
||||
|
||||
function get($name)
|
||||
{
|
||||
if(!isset($GLOBALS['TASKMAN_PROP_' . $name]))
|
||||
throw new TaskmanException("Property '$name' is not set");
|
||||
_resolve_callable_prop($name);
|
||||
return $GLOBALS['TASKMAN_PROP_' . $name];
|
||||
}
|
||||
|
||||
function getor($name, $def)
|
||||
{
|
||||
if(!isset($GLOBALS['TASKMAN_PROP_' . $name]))
|
||||
return $def;
|
||||
_resolve_callable_prop($name);
|
||||
return $GLOBALS['TASKMAN_PROP_' . $name];
|
||||
}
|
||||
|
||||
function set($name, $value)
|
||||
{
|
||||
$GLOBALS['TASKMAN_PROP_' . $name] = $value;
|
||||
}
|
||||
|
||||
function setor($name, $value)
|
||||
{
|
||||
if(!isset($GLOBALS['TASKMAN_PROP_' . $name]))
|
||||
$GLOBALS['TASKMAN_PROP_' . $name] = $value;
|
||||
}
|
||||
|
||||
function is($name)
|
||||
{
|
||||
return isset($GLOBALS['TASKMAN_PROP_' . $name]);
|
||||
}
|
||||
|
||||
function del($name)
|
||||
{
|
||||
unset($GLOBALS['TASKMAN_PROP_' . $name]);
|
||||
}
|
||||
|
||||
function props()
|
||||
{
|
||||
$props = array();
|
||||
foreach($GLOBALS as $key => $value)
|
||||
{
|
||||
if(($idx = strpos($key, 'TASKMAN_PROP_')) === 0)
|
||||
foreach($decoded as $items)
|
||||
{
|
||||
$name = substr($key, strlen('TASKMAN_PROP_'));
|
||||
$props[$name] = get($name);
|
||||
}
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
if(count($items) < 2)
|
||||
throw new Exception('Bad entry');
|
||||
list($status, $file) = $items;
|
||||
|
||||
function task($name)
|
||||
{
|
||||
global $TASKMAN_CLOSURES;
|
||||
|
||||
$args = func_get_args();
|
||||
$TASKMAN_CLOSURES[$name] = $args;
|
||||
}
|
||||
|
||||
function get_tasks()
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
return $TASKMAN_TASKS;
|
||||
}
|
||||
|
||||
function current_task()
|
||||
{
|
||||
global $TASKMAN_CURRENT_TASK;
|
||||
return $TASKMAN_CURRENT_TASK;
|
||||
}
|
||||
|
||||
function run($task, array $args = array())
|
||||
{
|
||||
if($task instanceof TaskmanTask)
|
||||
$task_obj = $task;
|
||||
else
|
||||
$task_obj = get_task($task);
|
||||
|
||||
$task_obj->run($args);
|
||||
}
|
||||
|
||||
function run_many($tasks, $args = array())
|
||||
{
|
||||
foreach($tasks as $task_spec)
|
||||
{
|
||||
if(is_array($task_spec))
|
||||
run($task_spec[0], $task_spec[1]);
|
||||
else
|
||||
run($task_spec, $args);
|
||||
}
|
||||
}
|
||||
|
||||
function msg_dbg($msg)
|
||||
{
|
||||
_log($msg, 2);
|
||||
}
|
||||
|
||||
function msg($msg)
|
||||
{
|
||||
_log($msg, 1);
|
||||
}
|
||||
|
||||
function msg_sys($msg)
|
||||
{
|
||||
_log($msg, 0);
|
||||
}
|
||||
|
||||
function _log($msg, $level = 1)
|
||||
{
|
||||
global $TASKMAN_LOG_LEVEL;
|
||||
|
||||
if($TASKMAN_LOG_LEVEL < $level)
|
||||
return;
|
||||
|
||||
$logger = $GLOBALS['TASKMAN_LOGGER'];
|
||||
call_user_func_array($logger, array($msg));
|
||||
}
|
||||
|
||||
function _($str)
|
||||
{
|
||||
if(strpos($str, '%') === false)
|
||||
return $str;
|
||||
|
||||
$str = preg_replace_callback(
|
||||
'~%\(([^\)]+)\)%~',
|
||||
function($m) { return get($m[1]); },
|
||||
$str
|
||||
);
|
||||
return $str;
|
||||
}
|
||||
|
||||
function _isset_task($task)
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
return isset($TASKMAN_TASKS[$task]) || isset($TASKMAN_TASK_ALIASES[$task]);
|
||||
}
|
||||
|
||||
function _get_hints($task)
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
$tasks = array_merge(array_keys($TASKMAN_TASKS), array_keys($TASKMAN_TASK_ALIASES));
|
||||
$found = array_filter($tasks, function($v) use($task) { return strpos($v, $task) === 0; });
|
||||
$found = array_merge($found, array_filter($tasks, function($v) use($task) { $pos = strpos($v, $task); return $pos !== false && $pos > 0; }));
|
||||
return $found;
|
||||
}
|
||||
|
||||
//e.g: run,build,zip
|
||||
function _parse_taskstr($str)
|
||||
{
|
||||
$task_spec = array();
|
||||
$items = explode(',', $str);
|
||||
foreach($items as $item)
|
||||
{
|
||||
$args = null;
|
||||
$task = $item;
|
||||
if(strpos($item, ' ') !== false)
|
||||
@list($task, $args) = explode(' ', $item, 2);
|
||||
|
||||
if($args)
|
||||
$task_spec[] = array($task, explode(' ', $args));
|
||||
else
|
||||
$task_spec[] = $task;
|
||||
}
|
||||
return $task_spec;
|
||||
}
|
||||
|
||||
function _process_argv(&$argv)
|
||||
{
|
||||
global $TASKMAN_LOG_LEVEL;
|
||||
global $TASKMAN_BATCH;
|
||||
global $TASKMAN_NO_DEPS;
|
||||
|
||||
$filtered = array();
|
||||
$process_defs = false;
|
||||
for($i=0;$i<sizeof($argv);++$i)
|
||||
{
|
||||
$v = $argv[$i];
|
||||
|
||||
if($v == '--')
|
||||
{
|
||||
for($j=$i+1;$j<sizeof($argv);++$j)
|
||||
$filtered[] = $argv[$j];
|
||||
break;
|
||||
}
|
||||
else if($v == '-D')
|
||||
{
|
||||
$process_defs = true;
|
||||
}
|
||||
else if($v == '-V')
|
||||
{
|
||||
$TASKMAN_LOG_LEVEL = 2;
|
||||
}
|
||||
else if($v == '-q')
|
||||
{
|
||||
$TASKMAN_LOG_LEVEL = 0;
|
||||
}
|
||||
else if($v == '-b')
|
||||
{
|
||||
$TASKMAN_LOG_LEVEL = -1;
|
||||
}
|
||||
else if($v == '-O')
|
||||
{
|
||||
$TASKMAN_NO_DEPS = true;
|
||||
}
|
||||
else if($v == '-c')
|
||||
{
|
||||
if(!isset($argv[$i+1]))
|
||||
throw new TaskmanException("Configuration file(-c option) is missing");
|
||||
require_once($argv[$i+1]);
|
||||
++$i;
|
||||
}
|
||||
else if($process_defs)
|
||||
{
|
||||
$eq_pos = strpos($v, '=');
|
||||
if($eq_pos !== false)
|
||||
if(strlen($file) > 0)
|
||||
{
|
||||
$def_name = substr($v, 0, $eq_pos);
|
||||
$def_value = substr($v, $eq_pos+1);
|
||||
|
||||
if(in_array(strtolower($def_value), array('yes', 'true'), true/*strict*/))
|
||||
$def_value = true;
|
||||
else if(in_array(strtolower($def_value), array('no', 'false'), true/*strict*/))
|
||||
$def_value = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$def_name = $v;
|
||||
$def_value = 1;
|
||||
if(DIRECTORY_SEPARATOR == '/')
|
||||
{
|
||||
if($file[0] != '/')
|
||||
$file = $base_dir . DIRECTORY_SEPARATOR . $file;
|
||||
}
|
||||
else if(strlen($file) > 1 && $file[1] != ':')
|
||||
$file = $base_dir . DIRECTORY_SEPARATOR . $file;
|
||||
}
|
||||
|
||||
msg_sys("Setting prop $def_name=" . (is_bool($def_value) ? ($def_value ? 'true' : 'false') : $def_value) . "\n");
|
||||
set($def_name, $def_value);
|
||||
|
||||
$process_defs = false;
|
||||
$file = artefact\normalize_path($file);
|
||||
|
||||
if($status == 'Changed')
|
||||
$changed[$file] = self::Changed;
|
||||
else if($status == 'Created')
|
||||
{
|
||||
//let's status for files which were modified and then created
|
||||
if(isset($changed[$file]) && $changed[$file] !== self::Changed)
|
||||
$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);
|
||||
}
|
||||
else
|
||||
$filtered[] = $v;
|
||||
|
||||
return new TaskmanFileChanges($changed);
|
||||
}
|
||||
|
||||
//NOTE: maps: file => status
|
||||
function __construct(array $changed)
|
||||
{
|
||||
$this->changed = $changed;
|
||||
}
|
||||
|
||||
function getStatus(string $file) : ?int
|
||||
{
|
||||
return isset($this->changed[$file]) ? $this->changed[$file] : null;
|
||||
}
|
||||
|
||||
function isChanged(string $file) : bool
|
||||
{
|
||||
return $this->getStatus($file) == self::Changed;
|
||||
}
|
||||
|
||||
function isCreated(string $file) : bool
|
||||
{
|
||||
return $this->getStatus($file) == self::Created;
|
||||
}
|
||||
|
||||
function isDeleted(string $file) : bool
|
||||
{
|
||||
return $this->getStatus($file) == self::Deleted;
|
||||
}
|
||||
|
||||
function isRenamed(string $file) : bool
|
||||
{
|
||||
return $this->getStatus($file) == self::Renamed;
|
||||
}
|
||||
|
||||
function isEmpty() : bool
|
||||
{
|
||||
return count($this->changed) == 0;
|
||||
}
|
||||
|
||||
function matchDirectory(string $dir, array $extensions = array()) : array
|
||||
{
|
||||
$dir = rtrim($dir, '/\\');
|
||||
$dir .= DIRECTORY_SEPARATOR;
|
||||
|
||||
$filtered = [];
|
||||
|
||||
foreach($this->changed as $path => $_)
|
||||
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]))
|
||||
$filtered[] = $file;
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
$argv = $filtered;
|
||||
}
|
||||
|
||||
|
||||
function main($argv = array(), $help_func = null, $proc_argv = true)
|
||||
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)
|
||||
_process_argv($argv);
|
||||
internal\_process_argv($argv);
|
||||
|
||||
$GLOBALS['TASKMAN_SCRIPT'] = array_shift($argv);
|
||||
|
||||
_collect_tasks();
|
||||
internal\_collect_tasks();
|
||||
|
||||
$always_tasks = array();
|
||||
$default_task = null;
|
||||
|
@ -596,14 +475,14 @@ function main($argv = array(), $help_func = null, $proc_argv = true)
|
|||
}
|
||||
|
||||
foreach($always_tasks as $always_task)
|
||||
$always_task->run(array());
|
||||
run($always_task);
|
||||
|
||||
if(sizeof($argv) > 0)
|
||||
{
|
||||
$task_str = array_shift($argv);
|
||||
$tasks = _parse_taskstr($task_str);
|
||||
$tasks = internal\_parse_taskstr($task_str);
|
||||
|
||||
if(count($tasks) == 1 && !_isset_task($tasks[0]))
|
||||
if(count($tasks) == 1 && !internal\_isset_task($tasks[0]))
|
||||
{
|
||||
$pattern = $tasks[0];
|
||||
if($pattern[0] == '~')
|
||||
|
@ -618,104 +497,25 @@ function main($argv = array(), $help_func = null, $proc_argv = true)
|
|||
}
|
||||
else
|
||||
$is_similar = false;
|
||||
$hints = _get_hints($pattern);
|
||||
$hints = internal\_get_hints($pattern);
|
||||
|
||||
if($is_similar && count($hints) == 1)
|
||||
$tasks = $hints;
|
||||
else
|
||||
{
|
||||
printf("ERROR! Task %s not found\n", $tasks[0]);
|
||||
$similars = '';
|
||||
if($hints)
|
||||
{
|
||||
printf("Similar tasks:\n");
|
||||
foreach($hints as $hint)
|
||||
printf(" %s\n", $hint);
|
||||
}
|
||||
exit(1);
|
||||
$similars .= "\nSimilar tasks: " . implode(', ', $hints) . ".";
|
||||
|
||||
throw new Exception("Task '{$tasks[0]}' not found. $similars");
|
||||
}
|
||||
}
|
||||
|
||||
run_many($tasks, $argv);
|
||||
}
|
||||
else if($default_task)
|
||||
$default_task->run($argv);
|
||||
run($default_task, $argv);
|
||||
|
||||
msg_sys("***** All done (".round(microtime(true)-$GLOBALS['TASKMAN_START_TIME'],2)." sec.) *****\n");
|
||||
log(0, "***** All done (".round(microtime(true)-$GLOBALS['TASKMAN_START_TIME'],2)." sec.) *****\n");
|
||||
}
|
||||
|
||||
function usage($script_name = "<taskman-script>")
|
||||
{
|
||||
\_taskman_default_usage($script_name);
|
||||
}
|
||||
|
||||
task('help', function($args = array())
|
||||
{
|
||||
$filter = '';
|
||||
if(isset($args[0]))
|
||||
$filter = $args[0];
|
||||
|
||||
$maxlen = -1;
|
||||
$tasks = array();
|
||||
$all = get_tasks();
|
||||
foreach($all as $task)
|
||||
{
|
||||
if($filter && (strpos($task->getName(), $filter) === false && strpos($task->getPropOr("alias", ""), $filter) === false))
|
||||
continue;
|
||||
|
||||
if(strlen($task->getName()) > $maxlen)
|
||||
$maxlen = strlen($task->getName());
|
||||
|
||||
$tasks[] = $task;
|
||||
}
|
||||
|
||||
if(!$args)
|
||||
{
|
||||
$help_func = $GLOBALS['TASKMAN_HELP_FUNC'];
|
||||
$help_func();
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo "Available tasks:\n";
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
$props_string = '';
|
||||
$pad = $maxlen - strlen($task->getName());
|
||||
foreach($task->getProps() as $name => $value)
|
||||
{
|
||||
$props_string .= str_repeat(" ", $pad) .' @' . $name . ' ' . (is_string($value) ? $value : json_encode($value)) . "\n";
|
||||
$pad = $maxlen + 1;
|
||||
}
|
||||
$props_string = rtrim($props_string);
|
||||
|
||||
echo "---------------------------------\n";
|
||||
$file = $task->getFile();
|
||||
$line = $task->getLine();
|
||||
echo " " . $task->getName() . $props_string . " ($file@$line)\n";
|
||||
}
|
||||
echo "\n";
|
||||
});
|
||||
|
||||
task('props', function($args = [])
|
||||
{
|
||||
$filter = '';
|
||||
if(isset($args[0]))
|
||||
$filter = $args[0];
|
||||
|
||||
$props = props();
|
||||
|
||||
echo "\n";
|
||||
echo "Available props:\n";
|
||||
foreach($props as $k => $v)
|
||||
{
|
||||
if($filter && stripos($k, $filter) === false)
|
||||
continue;
|
||||
|
||||
echo "---------------------------------\n";
|
||||
echo "$k : " . var_export($v, true) . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
});
|
||||
|
||||
} //namespace taskman
|
||||
//}}}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
namespace taskman;
|
||||
use Exception;
|
||||
|
||||
task('help', function($args = array())
|
||||
{
|
||||
$filter = '';
|
||||
if(isset($args[0]))
|
||||
$filter = $args[0];
|
||||
|
||||
$maxlen = -1;
|
||||
$tasks = array();
|
||||
$all = get_tasks();
|
||||
foreach($all as $task)
|
||||
{
|
||||
if($filter && (strpos($task->getName(), $filter) === false &&
|
||||
strpos($task->getPropOr("alias", ""), $filter) === false))
|
||||
continue;
|
||||
|
||||
if(strlen($task->getName()) > $maxlen)
|
||||
$maxlen = strlen($task->getName());
|
||||
|
||||
$tasks[] = $task;
|
||||
}
|
||||
|
||||
if(!$args)
|
||||
{
|
||||
$help_func = $GLOBALS['TASKMAN_HELP_FUNC'];
|
||||
$help_func();
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
echo "Available tasks:\n";
|
||||
foreach($tasks as $task)
|
||||
{
|
||||
$props_string = '';
|
||||
$pad = $maxlen - strlen($task->getName());
|
||||
foreach($task->getProps() as $name => $value)
|
||||
{
|
||||
$props_string .= str_repeat(" ", $pad) .' @' . $name . ' ' . (is_string($value) ? $value : json_encode($value)) . "\n";
|
||||
$pad = $maxlen + 1;
|
||||
}
|
||||
$props_string = rtrim($props_string);
|
||||
|
||||
echo "---------------------------------\n";
|
||||
$file = $task->getFile();
|
||||
$line = $task->getLine();
|
||||
echo " " . $task->getName() . $props_string . " ($file@$line)\n";
|
||||
}
|
||||
echo "\n";
|
||||
});
|
||||
|
||||
task('props', function($args = [])
|
||||
{
|
||||
$filter = '';
|
||||
if(isset($args[0]))
|
||||
$filter = $args[0];
|
||||
|
||||
$props = props();
|
||||
|
||||
echo "\n";
|
||||
echo "Available props:\n";
|
||||
foreach($props as $k => $v)
|
||||
{
|
||||
if($filter && stripos($k, $filter) === false)
|
||||
continue;
|
||||
|
||||
echo "---------------------------------\n";
|
||||
echo "$k : " . var_export($v, true) . "\n";
|
||||
}
|
||||
echo "\n";
|
||||
});
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
<?php
|
||||
namespace taskman;
|
||||
use Exception;
|
||||
|
||||
function get_task(string $task) : TaskmanTask
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
global $TASKMAN_TASK_ALIASES;
|
||||
|
||||
if(!is_scalar($task))
|
||||
throw new TaskmanException("Bad task name");
|
||||
|
||||
if(isset($TASKMAN_TASKS[$task]))
|
||||
return $TASKMAN_TASKS[$task];
|
||||
|
||||
if(isset($TASKMAN_TASK_ALIASES[$task]))
|
||||
return $TASKMAN_TASK_ALIASES[$task];
|
||||
|
||||
throw new TaskmanException("Task with name/alias '{$task}' does not exist");
|
||||
}
|
||||
|
||||
function get($name)
|
||||
{
|
||||
if(!isset($GLOBALS['TASKMAN_PROP_' . $name]))
|
||||
throw new TaskmanException("Property '$name' is not set");
|
||||
internal\_resolve_callable_prop($name);
|
||||
return $GLOBALS['TASKMAN_PROP_' . $name];
|
||||
}
|
||||
|
||||
function getor($name, $def)
|
||||
{
|
||||
if(!isset($GLOBALS['TASKMAN_PROP_' . $name]))
|
||||
return $def;
|
||||
internal\_resolve_callable_prop($name);
|
||||
return $GLOBALS['TASKMAN_PROP_' . $name];
|
||||
}
|
||||
|
||||
function set($name, $value)
|
||||
{
|
||||
$GLOBALS['TASKMAN_PROP_' . $name] = $value;
|
||||
}
|
||||
|
||||
function setor($name, $value)
|
||||
{
|
||||
if(!isset($GLOBALS['TASKMAN_PROP_' . $name]))
|
||||
$GLOBALS['TASKMAN_PROP_' . $name] = $value;
|
||||
}
|
||||
|
||||
function is($name)
|
||||
{
|
||||
return isset($GLOBALS['TASKMAN_PROP_' . $name]);
|
||||
}
|
||||
|
||||
function del($name)
|
||||
{
|
||||
unset($GLOBALS['TASKMAN_PROP_' . $name]);
|
||||
}
|
||||
|
||||
function props()
|
||||
{
|
||||
$props = array();
|
||||
foreach($GLOBALS as $key => $value)
|
||||
{
|
||||
if(($idx = strpos($key, 'TASKMAN_PROP_')) === 0)
|
||||
{
|
||||
$name = substr($key, strlen('TASKMAN_PROP_'));
|
||||
$props[$name] = get($name);
|
||||
}
|
||||
}
|
||||
return $props;
|
||||
}
|
||||
|
||||
function task($name)
|
||||
{
|
||||
global $TASKMAN_CLOSURES;
|
||||
|
||||
if(isset($TASKMAN_CLOSURES[$name]))
|
||||
throw new TaskmanException("Task '$name' is already defined");
|
||||
|
||||
$args = func_get_args();
|
||||
$TASKMAN_CLOSURES[$name] = $args;
|
||||
}
|
||||
|
||||
function get_tasks() : array
|
||||
{
|
||||
global $TASKMAN_TASKS;
|
||||
return $TASKMAN_TASKS;
|
||||
}
|
||||
|
||||
function current_task()
|
||||
{
|
||||
global $TASKMAN_CURRENT_TASK;
|
||||
return $TASKMAN_CURRENT_TASK;
|
||||
}
|
||||
|
||||
function run($task, array $args = array())
|
||||
{
|
||||
if($task instanceof TaskmanTask)
|
||||
$task_obj = $task;
|
||||
else
|
||||
$task_obj = get_task($task);
|
||||
|
||||
return $task_obj->run($args);
|
||||
}
|
||||
|
||||
function run_many($tasks, $args = array())
|
||||
{
|
||||
foreach($tasks as $task_spec)
|
||||
{
|
||||
if(is_array($task_spec))
|
||||
run($task_spec[0], $task_spec[1]);
|
||||
else
|
||||
run($task_spec, $args);
|
||||
}
|
||||
}
|
||||
|
||||
//the lower the level the more important the message: 0 - is the highest priority
|
||||
function log(int $level, $msg)
|
||||
{
|
||||
global $TASKMAN_LOG_LEVEL;
|
||||
|
||||
if($TASKMAN_LOG_LEVEL < $level)
|
||||
return;
|
||||
|
||||
$logger = $GLOBALS['TASKMAN_LOGGER'];
|
||||
call_user_func_array($logger, array($msg));
|
||||
}
|
||||
|
||||
//obsolete
|
||||
function _log(string $msg, int $level = 1)
|
||||
{
|
||||
log($level, $msg);
|
||||
}
|
||||
|
||||
//TODO: obsolete
|
||||
function msg_dbg(string $msg)
|
||||
{
|
||||
log(2, $msg);
|
||||
}
|
||||
|
||||
//TODO: obsolete
|
||||
function msg(string $msg)
|
||||
{
|
||||
log(1, $msg);
|
||||
}
|
||||
|
||||
//TODO: obsolete
|
||||
function msg_sys(string $msg)
|
||||
{
|
||||
log(0, $msg);
|
||||
}
|
||||
|
||||
function _(string $str) : string
|
||||
{
|
||||
if(strpos($str, '%') === false)
|
||||
return $str;
|
||||
|
||||
$str = preg_replace_callback(
|
||||
'~%\(([^\)]+)\)%~',
|
||||
function($m) { return get($m[1]); },
|
||||
$str
|
||||
);
|
||||
return $str;
|
||||
}
|
||||
|
||||
function usage($script_name = "<taskman-script>")
|
||||
{
|
||||
internal\_default_usage($script_name);
|
||||
}
|
||||
|
Loading…
Reference in New Issue