Context¶
For every task that Castor run, it uses a Context object. This object
contains the default values for a bunch of built-in functions like run(), watch(),
capture(), etc.
It configures working directory of the command, environment variables, PTY, TTY,
timeout, etc...
It also contains custom values that can be set by the user and reused in tasks.
The context is immutable, which means that every time you change a value, a new context is created.
Using the context¶
The context() function¶
You can get the initial context thanks to the context() function:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\io;
use function Castor\run;
#[AsTask()]
function foo(): void
{
$context = context();
io()->writeln($context->workingDirectory); // will print the directory of the castor.php file
$context = $context->withWorkingDirectory('/tmp'); // will create a new context where the current directory is /tmp
run('pwd', context: $context); // will print "/tmp"
}
The variable() function¶
Castor also provides a variable() function to get the value of a variable
stored in the Context:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\variable;
#[AsTask()]
function foo(): void
{
$foobar = variable('foobar', 'default value');
// Same as:
$context = context();
try {
$foobar = $context['foobar'];
} catch (\OutOfBoundsException) {
$foobar = 'default value;
}
}
Creating a new context¶
You can create a new context by declaring a function with
the Castor\Attribute\AsContext attribute:
use Castor\Attribute\AsContext;
use Castor\Attribute\AsTask;
use Castor\Context;
use function Castor\run;
#[AsContext()]
function my_context(): Context
{
return new Context(environment: ['FOO' => 'BAR']);
}
#[AsTask()]
function foo(): void
{
run('echo foo=$FOO');
}
Note
If you only define one context in your project, it will be used by default for all tasks. See the next chapter to learn how to set a default context.
So when you run the foo task, you will get:
$ castor foo
foo=BAR
Working with several contexts¶
Defining multiple contexts can be useful to represent different environments
(e.g. dev, staging, prod, etc.) or different configurations (e.g. docker, local, etc.).
You can define as many contexts as you want in your project by declaring multiple
functions with the #[AsContext] attribute:
use Castor\Attribute\AsContext;
use Castor\Context;
#[AsContext()]
function dev_context(): Context
{
return new Context(environment: ['APP_ENV' => 'dev']);
}
#[AsContext()]
function test_context(): Context
{
return new Context(environment: ['APP_ENV' => 'test']);
}
You can then choose which context to use when running a task by using the
--context option:
castor foo --context=dev_context
Tip
The -c option is a shortcut for the --context option in order to make it
easier to type.
castor foo -c dev_context
Overriding the context name¶
You can override the context name by setting the name argument of the
#[AsContext] attribute:
use Castor\Attribute\AsContext;
use Castor\Context;
use function Castor\run;
#[AsContext(name: 'dev')]
function dev_context(): Context
{
return new Context(environment: ['APP_ENV' => 'dev']);
}
Setting a default context¶
You may want to set a default context for all your tasks. You can do that by
setting the default argument to true in the #[AsContext] attribute:
use Castor\Attribute\AsContext;
use Castor\Attribute\AsTask;
use Castor\Context;
use function Castor\run;
#[AsContext(default: true, name: 'default')]
function default_context(): Context
{
return new Context();
}
#[AsContext(name: 'my_context')]
function other_context(): Context
{
return new Context(environment: ['FOO' => 'BAR']);
}
#[AsTask()]
function foo(): void
{
run('echo foo=$FOO');
}
By default the foo task will only print foo= as the FOO environment
variable is not set:
$ castor foo
foo=
If you want to use your other context, you can use the --context option:
$ castor foo --context=my_context
foo=BAR
Note
You can also define the environment variable CASTOR_CONTEXT at runtime to
override the default context to be used when no --context option is
provided.
CASTOR_CONTEXT=my_context castor foo
Context features¶
Failure¶
By default, Castor will throw an exception if the process fails. You can disable
that by using the withAllowFailure method:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('a_command_that_does_not_exist', context: context()->withAllowFailure());
}
Working directory¶
By default, Castor will execute the process in the same directory as
the castor.php file. You can change that by using the withWorkingDirectory
method. It can be either a relative or an absolute path:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('pwd', context: context()->withWorkingDirectory('../')); // run the process in the parent directory of the castor.php file
run('pwd', context: context()->withWorkingDirectory('/tmp')); // run the process in the /tmp directory
}
Environment variables¶
By default, Castor will use the same environment variables as the current
process. You can add or override environment variables by using the
withEnvironment() method:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('echo $FOO', context: context()->withEnvironment(['FOO' => 'bar'])); // will print "bar"
}
Timeout¶
By default, Castor allow your run() calls to go indefinitly.
If you want to tweak that you need to use the withTimeout method.
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('my-script.sh', context: context()->withTimeout(120));
}
This process will have a 2 minutes timeout.
PTY & TTY¶
By default, Castor will use a pseudo terminal (PTY) to run the underlying process,
which allows to have nice output in most cases.
For some commands, you may want to disable the PTY and use a TTY instead. You can
do that by using the withTty method:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('echo "bar"', context: context()->withTty());
}
Warning
When using a TTY, the output of the command is empty in the process object
(when using getOutput() or getErrorOutput()).
You can also disable the pty by using the withPty method. If withTty
and withPty are both used with false, the standard input will not be forwarded to
the process:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('echo "bar"', context: context()->withPty(false)->withTty(false)); // print nothing
}
Passing verbose arguments¶
Castor allow you to pass verbose arguments (like the universal -v option) to
the underlying process. You can do that by using the withVerboseArguments method:
use Castor\Attribute\AsTask;
use function Castor\context;
use function Castor\run;
#[AsTask()]
function foo(): void
{
run('php bin/console do:some:task', context: context()->withVerboseArguments(['--verbose']));
}
By default, Castor will not pass any verbose arguments to the command. However,
if you run castor in verbose mode
(for example with castor foo -v), it will pass the verbose arguments you configured to this command.
Additionally, if this command fails when Castor is not in verbose mode, it will ask you if you want to retry the command with the verbose arguments.
Advanced usage¶
See this documentation for more usage about contexts.