Open QwertyZW opened 7 years ago
This one's more an explanation/context for why this happens -- as much to get it written down somewhere as anything else. As of right now "the right" way to invoke pestle from the command line is via the pestle_dev script.
One of pestle's goals is to implement a python-like import system for PHP -- something that organizes code into individual modules, and allows users to import specific functions into their modules. Implementing this meant some Reflection and building up lists of functions in the /tmp/pestle_cache
folder, and we're actively thinking of different/better ways to handle this. Those tradeoffs were acceptable to use for running this code via pestle.phar
.
However -- if someone wants to use a pestle function in their own project -- the whole /tmp/pestle_cache
folder seems like a burden too far. For this "pestle as PHP/Composer library" context, we generate an all.php
file that contains the entire pestle library as a single include, with functions namespaced. Then, we have this library function included via a second PHP file, via the composer autoload feature
"autoload": {
"files": ["library/autoload.php"]
},
All a user needs to do is include pestle via the composer file, and then can reuse any of our functions. Again, this is a crude, initial approach that we may change over time.
The problem this created: We want all.php
loaded for folks who include this project in theirs, but for pestle.phar, pestle_dev, unit tests, etc., we do not want this all.php
loaded. Instead we want the "only imports single functions" behavior.
That's why library/autoload.php has a number of early return checks that attempt to detect the context of the current request. For example -- this checks if the current context is a PHPUnit run
$backtrace = debug_backtrace();
$top = array_pop($backtrace);
$file = '';
if(isset($top['file']))
{
$file = strToLower($top['file']);
}
$parts = explode('/', $file);
$last = array_pop($parts);
if(strpos($last, 'phpunit') !== false)
{
return;
}
If it is, the file returns. There's other checks as well -- but if none of them reach their respective return
statements, we assume this is just some random PHP project that wants a pestle function, and we pull in all.php
include __DIR__ . '/all.php';
The Problem in this Issue: The runner.php
script invokes pestle in its "real" mode, where pestle_import imports individual functions via the /tmp/pestle_cache
business. However, there's not a check in autoload.php
that checks if you're running runner.php
directly. There are checks to see if you're invoking things via pestle
, pestle.phar
, or pestle_dev
//running as pestle_dev, pestle.phar, or pestle
global $argv;
if(isset($argv[0]))
{
$parts = explode('/', $argv[0]);
$last = strToLower(array_pop($parts));
if(in_array($last, ['pestle', 'pestle_dev', 'pestle.phar']))
{
return;
}
}
When you're see the following error
PHP Fatal error: Cannot redeclare Pulsestorm\Pestle\Library\exitWithErrorMessage() (previously declared in /root/pestle/library/all.php:10393) in
/root/pestle/modules/pulsestorm/pestle/library/module.php on line 10
PHP Stack trace:
That's PHP complaining exitWithErrorMessage
was already defined when the all.php
file was included.
So, that's where things stand. Less a deliberate design and more a series of small steps. The pestle_import
mechanism may be overhauled when we implement things like importing multiple functions are once, or an entire module's worth of functions. At that time we'll probably revisit the whole "running in pestle.phar mode vs. running in "normal composer library mode"" question.
Given all this is due for a major refactoring anyway, I'm not super wild about endlessly adding more special cases into autoload.php
-- although if a pull request came in that was able to special case a direct call to runner from a "pestle as library" context I'd be open to that.
I see...
I think there several ways this problem can be approached
1) How about declaring/defining a special namespace/function within runner.php and then checking for that in library/autoload.php? (with this you can name the invoking command anything you like!)
2) runner.php can check if it was called from pestle_dev and if not exec pestle_dev (hacky/short sighted approach?)
I think this part of the readme could use an update if ['pestle', 'pestle_dev', 'pestle.phar'] become the only three officially supported entry points
But I'm not sure if having the command be dependent of its name ($argv[0]) is a good idea all together like you've already mentioned
If you're interested in working on the framework itself, you can use the runner.php in the project root. I personally use it by dropping the following in my ~/bin.
#File: ~/bin/pestle_dev
#!/usr/bin/env php
<?php
require_once('/Users/alanstorm/Documents/github/astorm/pestle/runner.php');
From a fresh master checkout.
Invoking runner.php directly produces a stack trace where as using pestle_dev doesn't. I'm not really sure why this is happening.