-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Subcommands #303
Comments
Can vendor binaries solve the "easy to provide" requirement? Here's how it works for PHPUnit: Definition by PHPUnitcomposer.json {
"name": "phpunit/phpunit",
...
"bin": [
"phpunit"
],
"config": {
"bin-dir": "bin"
}
} #!/usr/bin/env php
// ...
foreach (array(__DIR__ . '/../../autoload.php', __DIR__ . '/vendor/autoload.php') as $file) {
if (file_exists($file)) {
define('PHPUNIT_COMPOSER_INSTALL', $file);
break;
}
}
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
echo 'You need to set up the project dependencies using the following commands:' . PHP_EOL .
'wget http://getcomposer.org/composer.phar' . PHP_EOL .
'php composer.phar install' . PHP_EOL;
die(1);
}
require PHPUNIT_COMPOSER_INSTALL;
PHPUnit_TextUI_Command::main(); Generated codevendor/bin/phpunit #!/usr/bin/env sh
SRC_DIR="`pwd`"
cd "`dirname "$0"`"
cd "../phpunit/phpunit"
BIN_TARGET="`pwd`/phpunit"
cd "$SRC_DIR"
"$BIN_TARGET" "$@" vendor/bin/phpunit.bat @ECHO OFF
SET BIN_TARGET=%~dp0/../phpunit/phpunit/phpunit
php "%BIN_TARGET%" %* 👎 Won't work directly for two reasons:
|
Inner workingsThis is how an XP runner works in pseudo-code. ##
# Returns the command line via xp.ini / environment
# E.g. /usr/bin/php5.5 -dinclude_path=src/main/php -ddate.timezone=Europe/Berlin
cmdline(args):
cmd = find_exe($config.rt | $ENV{XP_RT} | "php")
cmd += include_path(from: $config.use_xp | $ENV{USE_XP} | ".")
cmd += ini_settings(from: $config)
<- cmd
##
# Returns the runner based on ??? - currently always "!default", xpws
# uses "!wait" (and maybe "!daemon" in the future).
runner():
if (???):
<- new Runner.default(class, run(proc) = {
proc.start()
proc.wait()
<- proc.exit
})
else if (???)
<- new Runner.wait(class, run(proc) = {
proc.start()
Console.readln()
proc.kill($SIG{TERM})
<- proc.exit
})
else if (???)
<- new Runner.daemon(class, run(proc) = {
switch (subcommand):
start: proc.pid >>> file($name.pid)
status: Console.writeln(file($name.pid) | "Not running")
stop: Process.get(file($name.pid)).kill()
<- 0
})
<- "Unknown runner type"
##
# Entry point -> command line
# E.g. "class-main.php xp.reflect.Command"
entry(runner):
cmd = ""
cmd += runner.entry_point # Either "class-main.php" or "web-main.php"
cmd += runner.entry_class # E.g. xp.scriptlet.Runner
<- cmd
##
# Execute command / args, e.g. "xp test src/test/php" = "test", ["src/test/php"]
# Returns exitcode
execute(subcommand, options, arguments)
runner = runner(subcommand)
<- runner(new Process(cmdline(options) + entry(runner) + arguments) Basic subcommand parsingBefore invoking execute(), the command line is parsed: $ xp -cp lib run Test 1 2 --verbose
# subcommand := "run"
# options := [ "-cp" => lib ]
# arguments := ["Test", "1", "2", "--verbose"] Next, locate "xp-run" subcommand, invoke it w/ options and arguments. If no subcommand can be found, default it to "xp-run" (BC case, see above!) ChallengesWe need to get this right
|
💡 So maybe the
The file "xp-test" itself would contain the necessary configuration, which the runner would parse. If invoked directly by PHP, it could display an error message: "please invoke by using xp $command". |
💡 The other idea is to compile the runner on first use, so using xp-test.ini: runner=default
[default]
class=unittest.cli.Runner From this we could generate code, compile it (saving it to the filesystem for the next run) and finally include it: C# implementation var declaration = new Net.XpFramework.Runner.Ini(subcommand + ".ini");
var unit = new CodeSnippetCompileUnit(@"
using System;
using System.Collections.Generic;
class {{name}} : Default
{
public {{name}}(string name): base(name) { }
override public string Class() { return ""{{class}}""; }
override public string Entry() { return ""class""; }
}
"
.Replace("{{name}}", subcommand)
.Replace("{{class}}", declaration.Get("default", "class"))
);
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("Runner.dll");
parameters.GenerateExecutable = false;
parameters.OutputAssembly = subcommand + ".dll";
var provider = new CSharpCodeProvider();
var results = provider.CompileAssemblyFromDom(parameters, unit);
if (results.Errors.Count > 0)
{
Console.Error.WriteLine("*** Cannot compile `{0}'", subcommand);
foreach (var error in results.Errors)
{
Console.WriteLine(" {0}", error.ToString());
}
return 0xff;
} Bash implementation TODO |
_There is now a reference implementation available at https://github.com/xp-runners/reference_. Re the above ideas: Its plugin architecture use Composer scripts' filenames to determine the necessary information.
|
_The first official plugin subcommand is now Installation: Timm@slate ~
$ composer global require xp-framework/unittest
Changed current directory to C:/Users/Timm/AppData/Roaming/Composer
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
- Removing xp-framework/unittest (dev-master 7d2659b)
- Installing xp-framework/unittest (v6.8.0)
Downloading: 100%
Writing lock file
Generating autoload files Invoking: |
Creates a command named "cmd" - the new xpcli is "xp cmd" See xp-framework/rfc#303
xp-framework/rfc#303 is bringing some major changes
* xp-framework/rfc#303: THIS! IS! VERSIOOOOON * xp-framework/rfc#307: Extract XPCLI from core * xp-framework/rfc#301: Extract logging from core * xp-framework/rfc#293: Extract unittest from core * xp-framework/rfc#296: Further minimize the framework * xp-framework/rfc#297: Rebase
Links inside help output, using the correct Terminal, are clickable! Source: xp-framework/core#127 |
Scope of Change
This RFC intends to change the XP runners to a single entry point with multiple subcommands. E.g., instead of writing
unittest src/test/php
, we'd writexp test src/test/php
.Rationale
There are a couple of problems with the current implementation, especially in conjunction with the splitting of the framework:
unittest
will not work if you don't have the unittest library in your class path once Remove unittests from core core#95 is merged. You can already see this withxcc
, for example.unittest
in your class path, the command will not work because the unittest runner classes are loaded too late on.Functionality
General idea:
Basic functionality
$ xp run Test $ xp ar cvf app.xar src/main/php=. $ xp ar xvf app.xar $ xp eval {code} $ xp version $ xp write {code} $ xp dump {code}
From other packages
Providing subcommands
Libraries should be able to provide subcommands in an easy way. Inside a project, we usually state our dependencies by using Composer, therefore being able to provide subcommands via its infrastructure would be awesome.
These kinds of subcommands exist:
Security considerations
Speed impact
Dependencies
The form
xp Test
which runsTest::main($argv)
must continue to work, as an alias forxp run Test
.Related documents
The text was updated successfully, but these errors were encountered: