mozart
mozart copied to clipboard
Root directories can not be deleted
Hi,
Wondered if you could help?
Currently installing Mozart to our Project but every time I run vendor/bin/mozart compose
I keep getting the following:
In Filesystem.php line 248:
Root directories can not be deleted.
compose
Im using WIndiows with VSCode and Git Bash. This is the composer file:
"scripts": {
"post-install-cmd": [
"\"vendor/bin/mozart\" compose",
"COMPOSER=composer-premium.json composer dump-autoload"
],
"post-update-cmd": [
"\"vendor/bin/mozart\" compose",
"COMPOSER=composer-premium.json composer dump-autoload"
]
},
"extra": {
"mozart": {
"dep_namespace": "Vendor\\",
"dep_directory": "/dist/",
"classmap_directory": "/classes/dependencies/",
"classmap_prefix": "UDP_",
"packages": [
"aws/aws-sdk-php"
]
}
}
I couldn't find much on google. Any help is appreciated.
I think I've seen that when running Mozart from the vendor/bin directory without setting the current working directory to be the project root. In my case through a PhpStorm run configuration on MacOS. I can't reproduce now and that doesn't sound like your problem, anyway.
Filesystem.php:248 is the throw
here:
public function deleteDir($dirname)
{
$dirname = Util::normalizePath($dirname);
if ($dirname === '') {
throw new RootViolationException('Root directories can not be deleted.');
}
$dirname
is your composer.json's dep_directory
and classmap_prefix
.
So Util::normalizePath must be returning an empty string.
I've set a breakpoint in PhpStorm and I'm not able to reproduce.
Try create a file 43.php
in your project root containing:
<?php
use League\Flysystem\Util;
require_once './vendor/league/flysystem/src/Util.php';
$dep_directory = "/dist/";
$classmap_directory = "/classes/dependencies/";
echo 'Input: ' . $dep_directory . ' Output: ' . Util::normalizePath($dep_directory) . "\n";
echo 'Input: ' . $classmap_directory . ' Output: ' . Util::normalizePath($classmap_directory) . "\n";
Then php -f 43.php
My output is:
Input: /dist/ Output: dist
Input: /classes/dependencies/ Output: classes/dependencies
The other suspicion I had (but doesn't really make sense after reading the code) is that Windows is actually trying to delete a root dir so you should just change "dep_directory": "/dist/"
to "dep_directory": "dist/"
.
@BrianHenryIE Thank you very much for the detailed reply.
So I added the script and ran it and I get the following:
php -f 43.php
Input: /dist/ Output: dist
Input: /classes/dependencies/ Output: classes/dependencies
Which Looked Identical to yours. SO I tweaked the dep_directory to "dep_directory": "dist/"
and exactly the same:
"vendor/bin/mozart" compose
In Filesystem.php line 248:
Root directories can not be deleted.
compose
Script "vendor/bin/mozart" compose handling the post-install-cmd event returned with error code 1
composer install failed. Aborting.
Im pretty sure its something Windows based but cant for the life of me figure out why its doing it
Post your full composer.json, the smallest possible to reproduce it, and I'll try again.
@BrianHenryIE I figured out the error, I was missing "delete_vendor_directories": false
however, I appeared to have come into another error:
vendor/bin/mozart compose
Fatal error: Uncaught Error: Class 'Symfony\Component\Finder\Finder' not found in vendor\coenjacobs\mozart\src\Mover.php:54
Stack trace:
#0 vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(96): CoenJacobs\Mozart\Mover->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#1 vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(92): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#2 vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(92): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#3 vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(69): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#4 vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(49): CoenJacobs\Mozart\Console\Commands\Compose->movePackages(Array)
#5 D: in vendor\coenjacobs\mozart\src\Mover.php on line 54
This is now my Composer file:
{
"type": "project",
"autoload": {
"classmap": [ "vendor/symfony/event-dispatcher/", "vendor/psr/log/" ]
},
"extra": {
"mozart": {
"dep_namespace": "Mozart\\",
"dep_directory": "/dist/vendor/",
"classmap_directory": "/dist/vendor/",
"classmap_prefix": "UDP_",
"packages": [
"aws/aws-sdk-php"
],
"delete_vendor_directories": false
}
},
"require": {
"eher/oauth": "^1.0",
"rackspace/php-opencloud": "1.12.2",
"aws/aws-sdk-php": "2.8.*",
"guzzle/guzzle": "3.9.3",
"phpseclib/phpseclib": "1.0.*",
"components/jquery-blockui": "*",
"coenjacobs/mozart": "*"
},
"require-dev": {
"squizlabs/php_codesniffer": "3.5.*",
"phpcompatibility/php-compatibility": "9.3.*",
"wp-coding-standards/wpcs": "2.1.*",
"dealerdirect/phpcodesniffer-composer-installer": "0.5.*",
"sirbrillig/phpcs-variable-analysis": "2.7.*"
},
"prefer-stable" : true
}
Any Idea?
@BrianHenryIE An Update to what I posted, Looks like running vendor/bin/mozart compose
removed the entire vendor folder even when "delete_vendor_directories": false
is set. How odd.
Update:
Found that Issue too. I have a specific Composer file called composer-premium.json
and I run it like this:
COMPOSER=composer-premium.json composer install
Looks Like Mozart is Expecting a composer.json
file instead. without creating one, is there a way to specify to the composer file?
Im Still seeing this error as it appears to be removing the vendor folder (when using composer.json
while testing):
$ mozart-compose
Fatal error: Uncaught Error: Class 'Symfony\Component\Finder\Finder' not found in D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Mover.php:54
Stack trace:
#0 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(96): CoenJacobs\Mozart\Mover->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#1 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(92): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#2 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(69): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#3 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(49): CoenJacobs\Mozart\Console\Commands\Compose->movePackages(Array)
#4 D:\work\wp-optimize\vendor\symfony\console\Command\Command.php(258): CoenJacobs\Mozart\Console\Commands\Compose->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony\C in D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Mover.php on line 54
Are you sure you're on the latest beta? I think unless you set "minimum-stability": "dev"
(maybe "beta", but "dev" works) in your composer.json, an update will continue just installing 0.5.1 right now. Easiest to specify the version outright rather than rely on *
.
I did do some testing the other day (the day before your last post) but I still wasn't able to reproduce your issue. Again, I'm on MacOS. Although maybe this will mostly boil down to delete_vendor_directories
.
Thank you @BrianHenryIE , I have added the "minimum-stability": "dev" to composer so that the latest version is updated.
I THINk you right that something is up with delete_vendor_directories
as Regardless if I set it to true or false, it will always be removed.
However, Part of diagnosing that issue I THINK I found the Original issue when using Mozart that returned the following:
In Filesystem.php line 248:
Root directories can not be deleted.
compose
With a lot of diagnostic work, I figured out the issue. Basically you HAVE to use composer.json
and not any other form. For some reason, Mozart, even though specifying the composer file, doesn't take it into consideration and of course, if composer.json
, it isn't going to work.
New Issue
After figuring out you can only use composer.json
I created the file with just the bits for Mozart to work.
When running I kept facing this issue:
Fatal error: Uncaught Error: Class 'Symfony\Component\Finder\Finder' not found in D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Mover.php:57
Stack trace:
#0 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(126): CoenJacobs\Mozart\Mover->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#1 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(122): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#2 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(99): CoenJacobs\Mozart\Console\Commands\Compose->movePackage(Object(CoenJacobs\Mozart\Composer\Package))
#3 D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Console\Commands\Compose.php(77): CoenJacobs\Mozart\Console\Commands\Compose->movePackages(Array)
#4 D:\work\wp-optimize\vendor\symfony\console\Command\Command.php(258): CoenJacobs\Mozart\Console\Commands\Compose->execute(Object(Symfony\Component\Console\Input\ArgvInput), Object(Symfony in D:\work\wp-optimize\vendor\coenjacobs\mozart\src\Mover.php on line 57
Regardless if I set delete_vendor_directories
to true or false, it appears it is removing the vendor directory and of course, removing Mozart (Along with Symfony etc.).
So I thought MAYBE if I set up the packages I wanted to replaCE WITH Mozart outside of vendor, perhaps that would resolve it.
One of the Packages we want to resolve is Pimple, SO I added that into a new folder called src/vendor
(originally it was in vendor
) and ran Mozart:
In Finder.php line 589:
The "D:\WorkProject/src/vendor/Pimple/" directory does not exist.
compose
Again, when running, even though delete_vendor_directories
is set to false, it removes the files and then complains it's not there. Of course, it isn't, its moved and which is quite odd.
So that I wasnt going mad, I ran this on the Gitlab server (Is uses this Docker Image) too and could re-create the same output.
The One Thing I did notice (mainly from my local setup) is the path as it starts off Windows Based. Would this be the issue why everything gets removed?
This is now my composer.json
file:
{
"name": "updraftplus/mozart",
"type": "project",
"extra": {
"mozart": {
"dep_namespace": "WPO\\pimple",
"dep_directory": "/src/vendor/",
"classmap_directory": "/classes/dependencies/",
"classmap_prefix": "WPO_",
"packages": [
"pimple/pimple"
],
"delete_vendor_directories": false
}
},
"require-dev": {
"coenjacobs/mozart": "*"
},
"minimum-stability": "dev"
}
Thank you for the amazing help so far, at least i feel we are getting somewhere!
Hey @BrianHenryIE Looks like I have jit a wall with Mozart. I just cant get it going at all. I have tried many ways to do this including keeping the Mozart install Separate from the Other Vendor files as they keep on getting removed (even though delete_vendor_directories
is set to false) and nothing is being processed.
Is it the fact I am on Windows and I cant set it up in that environment?
This is now my composer.json
file:
{
"name": "updraftplus/mozart",
"type": "project",
"config": {
"vendor-dir": "mozart/vendor"
},
"extra": {
"mozart": {
"dep_namespace": "udp\\",
"dep_directory": "dist/vendor/",
"classmap_directory": "classes/vendor/",
"classmap_prefix": "UDP_",
"delete_vendor_directories": false,
"packages": [
"aws/aws-sdk-php"
]
}
},
"require-dev": {
"coenjacobs/mozart": "0.4.0"
}
}
Keeping it away from the main composer file so it doesn't remove itself (Mozart kept on disappearing if ran inside the vendor folder).
When I run this, this is the error I get:
Running Mozart ...
In Filesystem.php line 389:
File not found at path: D:/work/updraftplus/vendor/symfony/event-dispatcher/CHANGELOG.md
compose
I have tried the latest beta version, Master and an older version. Nothing. Im missing something simple im sure but it just doesnt run.
@BrianHenryIE So I have dug deeper in this issue and I managed to get one of the members of the team (who has a Mac) to try my exact same setup and you know what? Worked first time without issues for him.
So there must be a bug somewhere for a Windows setup like im using that it basically ignores a lot of stuff including not to delete vendor etc.
Do you mind me digging in the code? see if I can notice something that may help?
I made a patch that replaces all /
with PHP's DIRECTORY_SEPARATOR
which might be what's needed. You can test by adding this to your composer.json
:
"require-dev": {
"cweagans/composer-patches": "~1.0",
},
"extra": {
"patches": {
"coenjacobs/mozart": {
"DIRECTORY_SEPARATOR": "https://github.com/coenjacobs/mozart/pull/61.patch"
}
}
}
@BrianHenryIE Thank you for the patch but...Didnt work :/
So Ive been trying to diagnose what on earth is going on under the windows directory and so far I have gone to mozart\src\Mover.php
under function movePackage
inside if ($autoloader instanceof NamespaceAutoloader) {
and when It comes to $finder->files()->in($source_path);
the path has been removed (Yet I never specified for it to be removed) and get the following error:
In Finder.php line 589:
The "vendor\psr/container\src/" directory does not exist.
Im going to try and drill down see if I can find why its deleting before it gets to this point but something odd is happening with the paths
@BrianHenryIE To add to my testing etc. today, This fix you made worked for our Gitlab Ci service running an Alpine Linux Docker image.
However, I just cant get it to work for Windows at all (Via Windows Git Bash). At least I can carry on via gitlab for now.
So vendor\psr/container\src/
is maybe the telling piece in the puzzle. The PHP DIRECTORY_SEPARATOR
constant (?) is there because Windows uses \
and everyone else uses /
. My previous commit was trying to address that but from your post it seems I didn't cover every instance. I've pushed another commit for Mover.php
which I think should use the correct \
//
in the case of psr/container
. Give it a go and let me know how you get on.
By "give it a go" you shouldn't have to change anything, composer-patches
freshly applies patches every time you run composer install
/update
@BrianHenryIE Yes! thats it, it worked :)
I tried going through it myself and I found a few but didnt get there but that update has done the job.
Phew! thank you so much for that!
When will this be in the release @BrianHenryIE oir is it just keep an eye out?
Also, I wondered if you have anything special you used to get aws/aws-sdk-php working (if you have tried). After going through Mozart, it just doesnt appear to work :/
I expect its the way AWS is setup :)
I'm not a maintainer of this project, just I use it a lot. Half the problems I've helped with are ones I've already dealt with myself, but then have taken the time to PR. Others are ones that have been easier for me to figure because I've read the code more than most, and helping is fun.
So it's up to @coenjacobs 's timeline when #61 gets merged. It's a relatively easy to read PR but there's a couple of spots open to improvement. And no tests (I don't even know how to write cross-platform tests).
Regards AWS, I haven't used it in any project myself (I have one AWS SNS project but it doesn't need the SDK), but on a quick glance, I see there is a files
entry in the sdk's autoload
key. I don't think Mozart handles an autoloader of type files
. Best bet would be to start a new issue with minimal composer.json and hopefully it suits someone to look into it soon.
Thank you for the reply @BrianHenryIE and thought you were one of the main people on the project as you have been very helpful :)
So yes, https://github.com/coenjacobs/mozart/pull/61 has solved this issues problem and shall wait on @coenjacobs but not the end of the world as Im pulling in the changes anyway which is cool.
With AWS yes, I noticed that too when digging around and seems to be a no go at the moment. I think I will raise another issue, see if we can dig deeper and look at whats going on
@darthvader666uk You are correct, @BrianHenryIE is an amazing help to this project. I'll have a look over the next few days, as a couple PRs and issues are requiring my attention. I'll see to releasing everything in the next beta of 0.6.0 and get that into a stable release as soon as I deem things to be stable enough. Really glad this got sorted!
@coenjacobs & @BrianHenryIE So Oddly, after the Patch got merged, I had this issue again:
In Filesystem.php line 389:
File not found at path: D:/work/wp-optimize/dist/vendor/marcusschwarz/lesserphp/vendor/marcusschwarz/lesserphp/lessc.inc.php
With it being Windows and how Paths can be funky, I have done alot of digging and I think I finally come up with a solution (working locally).
In src\Console\Commands\Compose.php on like 38 there is $this->workingDir = $workingDir;
. I replace it with $this->workingDir = DIRECTORY_SEPARATOR;
and it worked.
I had no issues at all. I think the combo with the updates from DIRECTORY_SEPARATOR seemed to have resolve almost all issues and I think that was the final piece.
Problem is, as its my Fork I got no way of testing it on out CI on Gitlab. I can make a Pull request but I expect you would want to check first etc.
What are your thoughts?
Edit: I did a pull request but this can alway be removed if your not happy but Im doing full test as we speak.
I'm pretty sure the test suite won't pass with that change because I need to set the current working directory to a temporary directory to execute composer install
and then test parts of Mozart in. Conceptually, getcwd()
makes sense for $workingDir
and I'm not exactly sure why \
is working even on Windows. I could see .
working.
Anyway, this issue looks to be the same as #90, where str_replace
was not matching because of cases where DIRECTORY_SEPARATOR
was still not applied and consecutive slashes maybe also affected the match.
I posted some code in that issue to replace in Mover::moveFile()
and I've expanded it a bit, so would you mind trying to replace your entire moveFile()
function in Move.php:167
with the following:
public function moveFile(Package $package, $autoloader, $file, $path = '')
{
/**
* For Windows & Unix file paths' compatibility.
*
* * Removes duplicate `\` and `/`.
* * Trims them from each end.
* * Replaces them with the OS agnostic DIRECTORY_SEPARATOR.
*
* @param string $path A full or partial filepath.
*
* @return string
*/
$clean = function ($path) {
return trim(preg_replace('/[\/\\\\]+/', DIRECTORY_SEPARATOR, $path), DIRECTORY_SEPARATOR);
};
// The relative path to the file from the project root.
$sourceFilePath = $clean(str_replace($this->workingDir, '', $file->getPathname()));
$namespacePath = $clean($package->config->name);
if ($autoloader instanceof NamespaceAutoloader) {
$namespacePath = $clean($autoloader->getNamespacePath());
// TODO: $path should come from the NameSpaceAutoloader object.
$packageVendorPath = 'vendor' . DIRECTORY_SEPARATOR . $namespacePath
. DIRECTORY_SEPARATOR . $clean($path);
$mozartDepPath = $clean($this->config->dep_directory) . DIRECTORY_SEPARATOR . $namespacePath;
$targetFilePath = str_ireplace($packageVendorPath, $mozartDepPath, $sourceFilePath);
} else {
$classmapDirectory = $clean($this->config->classmap_directory);
$packageVendorPath = 'vendor' . DIRECTORY_SEPARATOR . $namespacePath;
$mozartClassesPath = $classmapDirectory . DIRECTORY_SEPARATOR . $namespacePath;
$targetFilePath = str_ireplace($packageVendorPath, $mozartClassesPath, $sourceFilePath);
}
$this->filesystem->copy($sourceFilePath, $targetFilePath);
return $targetFilePath;
}
There's still some DIRECTORY_SEPARATOR
cases outside that function to look at, but I think this might be what you need.
The following appears correct:
{
"minimum-stability": "dev",
"prefer-stable" : true,
"require": {
"aws/aws-sdk-php": "2.8.31"
},
"require-dev": {
"coenjacobs/mozart": "dev-master",
"cweagans/composer-patches": "*"
},
"extra": {
"patches": {
"coenjacobs/mozart": {
"Do not confuse classnames with namespaces": "https://github.com/coenjacobs/mozart/pull/100.patch",
"Directory separator and its duplicates": "https://github.com/coenjacobs/mozart/pull/103.patch"
}
},
"mozart": {
"dep_namespace": "Mozart\\",
"dep_directory": "/dep_directory/",
"classmap_directory": "/classmap_directory/",
"classmap_prefix": "Mozart_",
"delete_vendor_directories": false,
"override_autoload": {
"guzzle/guzzle": {
"psr-4": {
"Guzzle": "src/"
}
}
}
}
}
}
The override_autoload
~~maybe~~ would be unnecessary if I finished #63.