A versatile and lightweight PHP task runner, designed with simplicity in mind.

Overview

Blend

A versatile and lightweight PHP task runner, designed with simplicity in mind.

PHP Version Latest Version on Packagist Total Downloads License Maintenance Travis Build Status

Open in Visual Studio Code

Tweet Star

Table of Contents

About Blend
Installation
Config
Examples
API
Changelog


If you like this project and would like to support its development, giving it a would be appreciated!


Blend Demo


Key Features

  1. Blazing fast
  2. Easy to configure
  3. Dependency free

About Blend

Blend is a versatile and lightweight PHP task runner, designed with simplicity in mind. Blend was created out of frustration of trying to manage multiple CLI Tools and/or Scripts with different interfaces and trying to remember their names, locations, syntax, and options/arguments. With Blend and its intuitive and powerful API you will have to do this only once, it will, well, as the name suggests blend it for you. Blend will present those CLI Tools and/or Scripts the way you like and give you the possibility to access all of them in the form of tasks from a single, beautiful, and insightful interface that will assist you, give you feedback, and suggestions throughout the process.

To keep it as portable and as simple as it can be, the Blend package consists of a single class (TaskRunner), this class does all the magic for you.

Blend was created to be flexible, it can be installed in many ways, each way has its benefits and drawbacks. Choose the installation method that suits you and your needs best. Check out the installation section for more details.

Why does Blend exist?

Blend was developed for personal use in the first place. However, it has come so far that it deserves to be published. It may not be what you are looking for, so check it out carefully.


Installation

Using Composer:

Require Blend through Composer using:

composer require marwanalsoltany/blend

This is the recommended way to install Blend. With this installation method, Blend will be installed just like any normal Composer package. You can interact with it using either the vendor/bin/blend executable with a config file in the current working directory, or by requiring it in a stand-alone file and supplying the config programmatically. You can of course install it globally and let it be system-wide accessible.

Using PHAR:

Download Blend PHAR archive form the releases page or using one of the commands down below:

php -r "copy('https://github.com/MarwanAlsoltany/blend/releases/latest/download/blend.phar', 'blend');"
php -r "copy('https://git.io/JEseO', 'blend');"

With this installation method, you will get Blend as a portable PHAR archive, you can place it anywhere you want or even include it in your PATH for easy access. With this installation method, you have to supply a config file in order to configure/customize Blend. This installation method exists for portability where Blend is not bound to a specific project and a config file is sufficient. Starting from v1.0.3, the PHAR installation method is distinguished from other methods with the task phar:update that will update your PHAR to the latest release available in this repository.

Using Installer:

Download Blend Setup directly from the repository, or using one of the commands down below:

php -r "copy('https://raw.githubusercontent.com/MarwanAlsoltany/blend/master/bin/setup', 'setup');" && php setup
php -r "copy('https://git.io/JEseR', 'setup');" && php setup

Using this method, the Blend executable and source will be installed in the current working directory (to take advantage of IDEs Intellisense when configuring Blend programmatically). With this installation method, you can configure Blend programmatically using the blend executable file or by supplying a config file in CWD. This installation method exists merely for legacy projects, where Composer is not an option and programmable config is required.


Config

Blend can be configured using either of the two available config formats:

#ff6347 Note: Refer to config/blend.config.php to learn more about the expected data types.

PHP Config blend.config.php

 return [
    'autoload' => null,
    'merge' => true,
    'executables' => [
        'php' => [
            './bin/*',
        ],
    ],
    'translations' => [
        'abc' => 'xyz',
    ],
    'ansi' => true,
    'quiet' => false,
    'tasks' => [
        'some:task' => [
            'name' => 'some:task',
            'description' => 'Some task',
            'executor' => 'shell',
            'executable' => 'ls',
            'arguments' => '-lash',
            'hidden' => false,
            'disabled' => false,
        ],
    ],
];

JSON Config blend.config.json (Recommended)

{
    "autoload": null,
    "merge": true,
    "executables": {
        "php": [
            "./bin/*"
        ]
    },
    "translations": {
        "abc": "xyz"
    },
    "ansi": true,
    "quiet": false,
    "tasks": {
        "some:task": {
            "name": "some:task",
            "description": "Some task",
            "executor": "shell",
            "executable": "ls",
            "arguments": "-lash",
            "hidden": false,
            "disabled": false
        }
    }
}

How Does Config Loading Work?

Blend will try to load the config from the current working directory, if nothing is to be found there, it will go one level upwards and look in the parent directory and so on until it reaches the root directory. if it does not find anything there either, Blend will start without config.

#1e90ff Fact: Although JSON config format is recommended, PHP config has precedence. This means, if the two config formats are to be found in the same directory, the PHP config will get loaded instead of the JSON one. This is merely because the PHP config can be executed and is, therefore, more powerful.


Examples

A basic Blend executable:



use MAKS\Blend\TaskRunner as Blend;


$blend = new Blend();
$blend->start();

A more advanced Blend executable:

[ './php/bin/*', ], // files in "./js/bin" with the JS extension will be loaded as tasks and get executed using Node 'node' => [ './js/bin/*.js', ], ]); $blend->setName('My Task Runner'); $blend->setVersion('vX.X.X'); // these tasks are for demonstration purposes only $blend->addShellTask('ls', 'Lists content of CWD or the passed one.', 'ls', '-lash'); $blend->addCallbackTask('whoami', null, function () { /** @var Blend $this */ $this->say('@task'); // using the @task placeholder to get a string representation of the task object }); $blend->disableTask('whoami'); // preventing the task from being ran $blend->hideTask('whoami'); // preventing the task from being listed $blend->addCallbackTask('server:start', 'Starts a PHP Development Server in CWD', function () { /** @var Blend $this */ $cwd = getcwd(); if (file_exists("{$cwd}/.pid.server")) { $this->say('An already started PHP Development Server has been found.'); return Blend::FAILURE; } $pid = $this->exec("php -S localhost:8000 -t {$cwd}", true); // passing true runs the command asynchronously $this->say("Started a PHP Development Server in the background with PID: [{$pid}]"); file_put_contents("{$cwd}/.pid.server", $pid); return Blend::SUCCESS; }); $blend->addCallbackTask('server:stop', 'Stops a started PHP Development Server in CWD', function () { /** @var Blend $this */ $cwd = getcwd(); if (!file_exists("{$cwd}/.pid.server")) { $this->say('No started PHP Development Server has been found.'); return Blend::FAILURE; } $pid = trim(file_get_contents("{$cwd}/.pid.server")); $this->exec(PHP_OS === 'WINNT' ? "tskill {$pid}" : "kill -15 {$pid}"); $this->say("Stopped PHP Development Server with PID: [{$pid}]"); unlink("{$cwd}/.pid.server"); return Blend::SUCCESS; }); $blend->addCallbackTask('server:restart', 'Restarts the started PHP Development Server in CWD', function () { /** @var Blend $this */ $this->say('Restarting the PHP Development Server'); $this ->setQuiet(true) // disable output temporarily ->run('server:stop') ->run('server:start') ->setQuiet(false); // enable output again // use the runTask() method instead to get the return value of the called task // return $this->runTask('server:stop') & $this->runTask('server:start'); }); $blend->sort(); $blend->start(); ">


use MAKS\Blend\TaskRunner as Blend;


$blend = new Blend([
    // files in "./php/bin" will be loaded as tasks and get executed using PHP
    'php' => [
        './php/bin/*',
    ],
    // files in "./js/bin" with the JS extension will be loaded as tasks and get executed using Node
    'node' => [
        './js/bin/*.js',
    ],
]);

$blend->setName('My Task Runner');
$blend->setVersion('vX.X.X');

// these tasks are for demonstration purposes only

$blend->addShellTask('ls', 'Lists content of CWD or the passed one.', 'ls', '-lash');

$blend->addCallbackTask('whoami', null, function () {
    /** @var Blend $this */
    $this->say('@task'); // using the @task placeholder to get a string representation of the task object
});
$blend->disableTask('whoami'); // preventing the task from being ran
$blend->hideTask('whoami'); // preventing the task from being listed

$blend->addCallbackTask('server:start', 'Starts a PHP Development Server in CWD', function () {
    /** @var Blend $this */
    $cwd = getcwd();

    if (file_exists("{$cwd}/.pid.server")) {
        $this->say('An already started PHP Development Server has been found.');

        return Blend::FAILURE;
    }

    $pid = $this->exec("php -S localhost:8000 -t {$cwd}", true); // passing true runs the command asynchronously
    $this->say("Started a PHP Development Server in the background with PID: [{$pid}]");

    file_put_contents("{$cwd}/.pid.server", $pid);

    return Blend::SUCCESS;
});

$blend->addCallbackTask('server:stop', 'Stops a started PHP Development Server in CWD', function () {
    /** @var Blend $this */
    $cwd = getcwd();

    if (!file_exists("{$cwd}/.pid.server")) {
        $this->say('No started PHP Development Server has been found.');

        return Blend::FAILURE;
    }

    $pid = trim(file_get_contents("{$cwd}/.pid.server"));

    $this->exec(PHP_OS === 'WINNT' ? "tskill {$pid}" : "kill -15 {$pid}");
    $this->say("Stopped PHP Development Server with PID: [{$pid}]");

    unlink("{$cwd}/.pid.server");

    return Blend::SUCCESS;
});

$blend->addCallbackTask('server:restart', 'Restarts the started PHP Development Server in CWD', function () {
    /** @var Blend $this */
    $this->say('Restarting the PHP Development Server');

    $this
        ->setQuiet(true) // disable output temporarily
        ->run('server:stop')
        ->run('server:start')
        ->setQuiet(false); // enable output again

    // use the runTask() method instead to get the return value of the called task
    // return $this->runTask('server:stop') & $this->runTask('server:start');
});

$blend->sort();
$blend->start();

#ff6347 Note: Blend gets its ID from the executable name that contains it ($argv[0]). So if you were to rename the file that contains it to something else, all Blend output will reflect this new change (help message, suggestions, etc...). The environment variable and the config file name will also be expected to match the new name.

#32cd32 Advice: The TaskRunner class is well documented, if you have any questions about Blend API, refer to the DocBlocks of its methods, you will probably find your answer there.


API

Here is the full API of Blend (TaskRunner class).

Constants

Constant Description
VERSION Package version. (public)
EXECUTABLES Default executables. (public)
TRANSLATIONS Default task name translations. (public)
CONFIG Default config. (public)
SUCCESS Task success code. (public)
FAILURE Task failure code. (public)
CALLBACK_TASK Task type callback. (public)
SHELL_TASK Task type shell. (public)
INTERNAL_TASK Task type internal. (protected)

Properties

Property Description
$argc A reference to the $argc global variable. (public)
$argv A reference to the $argv global variable. (public)
$args An array of the arguments that could be passed to the executed task. (public)
$envVar Environment variable. (private)
$path Task runner path. (protected)
$id Task runner ID. (protected)
$name Task runner name. (protected)
$version Task runner version. (protected)
$task The current task name passed to the task runner. (protected)
$tasks Task runner tasks. (protected)
$methods Magic methods added via self::extend(). (protected)
$executables The executables that will be loaded. (protected)
$translations The translations that will be applied to tasks names. (protected)
$config The currently loaded configuration. (protected)
$ansi Whether or not to turn on ANSI colors for the output. (protected)
$quiet Whether or not to turn on the output. (protected)

Public Methods

Method Description
extend() Extends the class with a magic method using the passed callback.
exec() Executes a shell command synchronously or asynchronous and prints out its result if possible.
addCallbackTask() Adds a task that executes the passed callback.
addShellTask() Adds a task that can be executed by the used shell (Bash for example).
addTask() Adds a new task.
removeTask() Removes a task from the available tasks.
hideTask() Hides a task by preventing it from being listed. The task can still get ran though.
disableTask() Disables a task by preventing it from being ran. The task will still get listed, but will be obfuscated.
getTask() Returns a task.
getTasks() Returns all tasks.
runTask() Runs a task.
run() Runs a task or starts the runner if no parameter is specified or the task is not found.
say() Writes a message out to the console.
sort() Sorts the tasks alphabetically.
start() Starts the task runner.
getName() Returns the task runner name.
setName() Sets the task runner name.
getVersion() Returns the task runner version.
setVersion() Sets the task runner version.
isAnsi() Returns whether the task runner output is currently using ANSI colors or not.
setAnsi() Sets the task runner ANSI output value.
isQuiet() Returns whether the task runner output is currently quiet or not.
setQuiet() Sets the task runner quiet output value.

Protected Methods

Method Description
terminate() Terminates the task runner by exiting the script.
bootstrap() Bootstraps the task runner by adding predefined tasks.
load() Loads tasks from the specified executables array.
translate() Translates the passed string using the specified translations.
format() Formats a string like *printf() functions with the ability to add ANSI colors.
write() Writes out a formatted text block from the specified lines and format value.
displayHelp() Prints out a help message listing all tasks of the task runner.
displayHint() Prints out a hint message listing tasks matching the current task of the task runner.
displayList() Prints out a list of all available tasks of the task runner.
displayExec() Prints out a the result of executing the current argument of the task runner.
listTasks() Prints out a list of the passed tasks.
getUser() Returns the task runner user.

Private Methods

Method Description
registerHandlers() Registers error handler, exception handler and the shutdown function.
restoreHandlers() Restores the error handler and the exception handler.
checkEnvironment() Checks the environment for TR_* variable, validates its pattern and updates class internal state.
checkConfiguration() Checks the CWD or its parent(s) for a configuration file, validates its entries and updates class internal state.

Magic Methods

Method Description
handleError() Error handler function. (public)
handleException() Exception handler function. (public)
shutdown() Shutdown function. This method is abstract, implement it using self::extend(). (public)

License

Blend is an open-source project licensed under the MIT license.
Copyright (c) 2021 Marwan Al-Soltany. All rights reserved.

You might also like...
Task Scheduling with Cron Job in Laravel

About Laravel Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experie

 Laravel-Tasks is a Complete Build of Laravel 5.2 with Individual User Task Lists
Laravel-Tasks is a Complete Build of Laravel 5.2 with Individual User Task Lists

An app of tasks lists for each individual user. Built on Laravel 5.2, using 5.2 authentication and middleware. This has robust verbose examples using Laravel best practices.

Laravel Cron Scheduling - The ability to run the Laravel task scheduler using different crons

Laravel Cron Scheduling Laravel Task Scheduling is a great way to manage the cron. But the documentation contains the following warning: By default, m

Reset the live preset for debug settings with a task
Reset the live preset for debug settings with a task

Debug Settings Task This TYPO3 extension resets TYPO3 debug settings to the »live« preset on production using a scheduler task. Vision “Better safe th

PHP port of resque (Workers and Queueing)

php-resque: PHP Resque Worker (and Enqueue) Resque is a Redis-backed library for creating background jobs, placing those jobs on one or more queues, a

Manage all your cron jobs without modifying crontab. Handles locking, logging, error emails, and more.

Jobby, a PHP cron job manager Install the master jobby cron job, and it will manage all your offline tasks. Add jobs without modifying crontab. Jobby

A unified front-end for different queuing backends. Includes a REST server, CLI interface and daemon runners.

PHP-Queue A unified front-end for different queuing backends. Includes a REST server, CLI interface and daemon runners. Why PHP-Queue? Implementing a

Schedule and unschedule eloquent models elegantly without cron jobs
Schedule and unschedule eloquent models elegantly without cron jobs

Laravel Schedulable Schedule and Unschedule any eloquent model elegantly without cron job. Salient Features: Turn any Eloquent Model into a schedulabl

A course database lookup tool and schedule building web application for use at Rochester Institute of Technology.

CSH ScheduleMaker A course database lookup tool and schedule building web application for use at Rochester Institute of Technology. Built, maintained

Owner
Marwan Al-Soltany
Known as "MAKS", a developer & polyglot. From Mesopotamia, currently in Germany. ● @MarwanAlsoltany
Marwan Al-Soltany
Modern task runner for PHP

RoboTask Modern and simple PHP task runner inspired by Gulp and Rake aimed to automate common tasks: writing cross-platform scripts processing assets

Consolidation 2.6k Jan 3, 2023
Pure PHP task runner

task/task Got a PHP project? Heard of Grunt and Gulp but don't use NodeJS? Task is a pure PHP task runner. Leverage PHP as a scripting language, and a

null 184 Sep 28, 2022
Modern task runner for PHP

RoboTask Modern and simple PHP task runner inspired by Gulp and Rake aimed to automate common tasks: writing cross-platform scripts processing assets

Consolidation 2.6k Dec 28, 2022
Awesome Task Runner

Bldr Simplified Build System/Task Runner Uses Yaml, JSON, XML, PHP, or INI for configs Quick Usage To develop, run ./script/bootstrap, and then ./scri

null 223 Nov 20, 2022
Yii application runner

Yii application runner The package defines Yii application runner. Requirements PHP 7.4 or higher. Installation The package could be installed with co

Yii Software 9 Oct 15, 2022
xcron - the souped up, modernized cron/Task Scheduler for Windows, Mac OSX, Linux, and FreeBSD server and desktop operating systems.

xcron is the souped up, modernized cron/Task Scheduler for Windows, Mac OSX, Linux, and FreeBSD server and desktop operating systems. MIT or LGPL.

CubicleSoft 7 Nov 30, 2022
Manage your Laravel Task Scheduling in a friendly interface and save schedules to the database.

Documentation This librarian creates a route(default: /schedule) in your application where it is possible to manage which schedules will be executed a

Roberson Faria 256 Dec 21, 2022
🐺 Asynchronous Task Queue Based on Distributed Message Passing for PHP.

?? Asynchronous Task Queue Based on Distributed Message Passing for PHP.

Ahmed 36 Aug 11, 2022
A PHP implementation of a bare task loop.

TaskLoop A PHP implementation of a bare task loop. Installation. $ composer require thenlabs/task-loop 1.0.x-dev Usage. The file example.php contains

ThenLabs 1 Oct 17, 2022
Flow Framework Task Scheduler

This package provides a simple to use task scheduler for Neos Flow. Tasks are configured via settings, recurring tasks can be configured using cron syntax. Detailed options configure the first and last executions as well as options for the class handling the task.

Flowpack 11 Dec 21, 2022