Here’s two quick stories about providing native Windows support for pestle.
Home Directory
The first issue boiled down to our using the following code to get a user’s home directory
$home = trim(`echo ~`);
if(!is_dir($home)) {
throw new Exception("Could not find home directory with echo ~");
}
This works for the *nix family of operating systems, but doesn’t for Windows. We’ll probably end up doing something like this instead
$home = trim(`echo ~`);
if(!is_dir($home)) {
$home = trim(`echo %HOMEPATH%`);
}
if(!is_dir($home)) {
throw new Exception("Could not find home directory with echo ~");
}
Also of note: This problem was harder to diagnose because I’d failed to import PHP’s top level Exception
class into the local namespace, and so the throw
was trying to throw a Pulsestorm\Pestle\Config\Exception
— which doesn’t exist. Despite ten plus years of PHP namespaces I still regularly do this when throwing an exception.
Git Bash
The second problem was a bit subtler. Pestle’s autoloader is a bit — strange? non-standard? — in that it needs to operate differently whether you’re running code from a pestle executable/phar, the test suite, or regular old PHP. Back when I started the project I’d hoped to make the individual function importing work seamlessly across all three enviornments, but my time and attention ended up elsewhere and this autoloader hack remained in place.
So this bit of code is how we detect whether the user’s invoking things via one of the pestle executables or via regular PHP.
global $argv;
if(isset($argv[0]))
{
$parts = explode(DIRECTORY_SEPARATOR, $argv[0]);
$last = strToLower(array_pop($parts));
if(in_array($last, ['pestle', 'pestle_dev', 'pestle.phar']))
{
return;
}
}
This code splits the full executable path (/path/to/pestle.phar
) by the path separator. It even makes sure to use DIRECTORY_SEPARATOR
so that the windows path separator (a backslash \\
) is the thing we’re splitting on.
The works great, unless someone’s using Git Bash. Git Bash is a feature of Git for Windows that gives you an emulated bash shell. This shell is still using Windows executables — it just looks and behaves like a unix enviornment.
This means the value of $argv[0]
is something like /path/to/pestle.phar
, but the DIRECTORY_SEPARATOR
variable is still a backslash — \\
. TL;DR; this makes the detection fail, which means pestle ends up trying to double load function definitions.
Retro
I remember when I wrote the echo ~
code that part of me thought “this will probably fail somewhere” — shelling out to the environment usually results in less portable code. But I also thought “I don’t want to spend a few days spinning up different OS environments and investigating libraries just to get the user’s home directory”, so let’s see how it goes.
The DIRECTORY_SEPARATOR
code though — that was a deliberate attempt to think about both windows and unix enviornments and handle both. I only stumbled across this problem when I was trying to get Windows setup to debug the first problem, and discovered it had already been reported as a separate issue. A good reminder of why reproduction steps are so important when reporting bugs.
Thinking about how to prevent these sorts of bugs — I always come back to user testing being the only way if you want to keep any sort of velocity on your project (i.e. ship things). It’s far more important to get working code out fast, and be setup to respond to user feedback in a relatively reasonable amount of time than it is to spend weeks on small tiny details that may end up not mattering.