Fix custom PHP binary deleted when binary path is the app root#117
Fix custom PHP binary deleted when binary path is the app root#117simonhamp wants to merge 6 commits into
Conversation
Trim the configured binary package path before pruning so values that normalize to a no-op (./, ., /, trailing /.) no longer collapse to the app root and delete the entire built app. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
@bmckay959 would you mind trying this fix out when you get a chance? |
| | Tests | ||
| |-------------------------------------------------------------------------- | ||
| */ | ||
| it('removes the custom php binary package directory', function () use ($buildPath, $command) { |
There was a problem hiding this comment.
I'm a bit confused by this test....why do we want the custom binary removed? Feels like this test is introducing the bug the opposite direction? Basically, we don't want to delete the directory where the NATIVEPHP_PHP_BINARY points....or am I missing something?
There was a problem hiding this comment.
Understandable confusion. The binary is moved to a location in the app bundle itself during build. So leaving it in the source directory would include it twice 👍🏻
|
LGTM. Happy to merge pending passing CI. |
|
|
||
| expect("$buildPath/app/php-bin")->not->toBeDirectory(); | ||
| expect("$buildPath/app/index.php")->toBeFile(); | ||
| })->after(fn () => putenv('NATIVEPHP_PHP_BINARY_PATH')); |
There was a problem hiding this comment.
Looks like we're not currently able to support the ->after() method here.
| $command->pruneVendorDirectory(); | ||
|
|
||
| expect("$buildPath/app/index.php")->toBeFile(); | ||
| expect("$buildPath/app/bin/win/x64/php.exe")->toBeFile(); |
There was a problem hiding this comment.
Based on @gwleuverink comment from above, do we actually want the /app/bin/win/x64/php.exe to be removed? So basically add the expect("$buildPath/app/bin")->not->toBeDirectory()?
I can confirm this solved the bug, but I believe this is now including ALL the PHP versions with the app this way(So my build goes from 127MB to 212MB). So, if the binary is getting copied to a 'special' place inside the electron app(?), then can we not have the /bin directory also removed?
There was a problem hiding this comment.
Good point. I may have misinterpreted the test. I'll have a another look at it to confirm
|
Dug into this a bit more. The PR fixes the crash, but Ben's spotted a second thing worth handling before we merge: the binaries are still ending up in the bundle, which is the 127 to 212MB jump he measured. What's happening is The wrinkle on my side is that we don't own $binDir = $this->buildPath('app/'.$this->binaryPackageDirectory().'bin');
$filesystem->remove(glob("{$binDir}/*/*/php-*.zip"));For @simonhamp happy to push this onto the branch and tweak the test to match if you're good with it. Or we iterate the os/arch matrix instead of the glob if you'd prefer, though |
|
Thanks for digging in more...as I mentioned in my initial issue, I'm still pretty new on the native php side of things, so I haven't fully wrapped my arms around the build process/order/when things get injected. This feels like the right approach to me. |
|
Wouldn't have spotted it without your keen eye! @bmckay959 🙏🏻 Here's my suggested fix for review #121 This targets only the archives we manage, at their fixed bin/{os}/{arch}/php-*.zip location, never the containing directory. so if you happen to keep other files in |
|
The failing tests seem unrelated to this PR. Looks like the PendingRequest contract has broken backwards compat in a minor release. (Only happens with L13 - prefer-stable) |
Laravel 13.13.0 tightened the HTTP client's header casting to throw on non-scalar values. The X-NativePHP-Secret header is set from config('nativephp-internal.secret'), which is null when NATIVEPHP_SECRET is unset, so every request blew up with an InvalidArgumentException.
Casting to a string keeps null as an empty string, which the client accepts. This is what older Laravel versions did implicitly.
|
Does it still work with absolute directory path ? |
Summary
Fixes #115.
When
NATIVEPHP_PHP_BINARY_PATHis set to a value that points at the project root (e.g../),native:builddeletes the entire built app right before electron-builder packages it.Root cause
In
PrunesVendorDirectory::pruneVendorDirectory(), the configured binary package directory was interpolated naively into"app/{$binaryPackageDirectory}". When the value normalizes to a no-op (./,.,/, or a trailing/.),Path::join('/build', 'app/./')collapses to/build/app, so the prune step removes the whole app directory. The previous! empty()guard did not catch this because strings like./are non-empty.native:runwas unaffected because it does not run the prune step.Fix
Trim the configured path of surrounding dots, slashes, and whitespace, then skip removal entirely when nothing meaningful remains:
Tests
Added
tests/Build/PruneVendorDirectoryTest.php:php-bin/) is still pruned../) no longer wipes the built app (regression test for Custom PHP binary gets deleted if in root of project #115).Verified the regression test fails against the old code and passes with the fix. Full suite (114 tests) passes and Pint is clean.
🤖 Generated with Claude Code