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
Execute post-install/post-update scripts of dependencies #1193
Comments
There are moderate security concerns with doing that, but we just did not do it because we were not sure whether it was a good idea. We named the events in a way that we can add a That said, I don't think it's a huge drawback that users of your lib must add the scripts to their own composer.json.. It is one extra step but at least it makes it very obvious what is executed, and it's easy to remain in control as a user, so I would still favor the status quo. |
That's fair enough. In this circumstance, my workplace has around 40 individual Composer packages, so the 'one' extra step is immediately multiplied into lots of copy-paste/redundant tedium (not all of them would use this feature, but still, there's a few). Perhaps in the future, like you suggested, an event that fires when a package is installed would be a useful addition. |
Do you have concrete examples you can share of what you actually do with those scripts? |
The intention is to have a composer package that handles compilation of CoffeeScript and JavaScript libraries into production-ready minified javascript versions. We call this package In order to do this, In a more general sense, it's quite common for PHP devs to use some client-side scripting in their projects. Allowing Composer packages to bring in their own NPM dependencies seems like a good idea to me, whether it be baked into Composer or possible through a post-install script type arrangement. |
I see, but I'd rather try to support NPM in time than allow hacks to appear, because then we need to support hacks forever. In the meantime workarounds can usually be found, even though they're a bit more painful to use than the hacks we avoid, but that means if a good solution pops up people will have an incentive to migrate away from the workarounds. |
@ezzatron Quickly looking at your bridge app it looks like it's basically just a PHP wrapper around executing Would my PR's functionality fulfill all the reasons your |
I think your PR would be capable of doing what my bridge component currently does, but what I'm really after is for it to work for dependencies and not just root projects. So unless your PR addresses that aspect of Composer's scripts system, it doesn't solve the use case I mentioned in my previous comment. Having said that, if scripts were executed for dependencies too, your PR would probably then do everything I need. |
I need too that composer send child commands after the installation process, but after thinking about that, i demand me what script should be launch and in what order. It exists 4 phases for 3 commands :
Should the pre-install-cmd be launch before the parent pre-install-cmd or after, same question for update and unintall commands. In my mind the order could be one of theres
Note: I volontary omit cases ( parent_pre>parent_post>child_pre>child_post and child_pre>child_post>parent_pre>parent_post) Personally i prefer the third which is more semantically exact (first arrived first out, and a dependency exists before the dependents packages) The fith is just a variation on the requires, easiest to implement mainly if the requires are accessibles and acceded as a tree and not as a flat list.
|
I have received the problem that @ezzatron described also and I agree with him: I have expected the all event handlers to be called for dependent packages however they were not called. The use case: there is https://github.com/myak/framework/blob/master/composer.json file and there are event handlers described there, I expect for the following composer.json: {
"require": {
"myak/framework": "0.*"
},
"minimum-stability": "dev"
} The \Myak\Deploy\Deployer::postInstall() or postUpdate() to be called. The logic that Composer can use can be simple: after installation of the package all event handlers for this package must be called. Every package just need call of its event handlers, no need to worry about parent/child event handlers because it can lead to very complex logic with ambiguity. The reason why this have to be done: if we have 100 dependent packages and every package has event handlers defined in its composer.json file, developer/user need to find all these files, copy and paste the "scripts" section into the root composer.json file. Obviously it is not what is expected. |
@hinikato I'm really against this, because it removes the control from the users and places it in the hands of package authors. It's a good thing for metadata like autoloading because that makes things easier for everyone, but in this case, executing stuff is something that is best done by the root package, where you can control what is executed and in what order. |
@Seldaek, I understand, it makes sense, if consider this logic from this point of view - due some bug in some event handler all packages can be in not working state. |
@Seldaek, are you saying that supporting of running scripts in dependencies will not be supported now or in future? We are preparing to use Composer in connection with MediaWiki/SemanticMediaWiki and while we can educate people to update the MediaWiki composer.json with something like:
I would not expect a user to search the Semantic MediaWiki composer.json file, look for "scripts": {
"post-install-cmd": "SMW\\Maintenance\\ComposerInstaller::postInstallEvent"
} We do an effort to make the migration to use Composer in connection with MW/SMW as easy as possible but making a user understand to edit a json file by hand is certainly rather difficult. |
@Seldaek "removes the control from the users and places it in the hands of package authors." : maybe a composer_key could resolve this problem, a key like : authorized_sub_commands : without_confirmation, true or false |
Yes maybe we could add this with an optional flag. I'm still not sure it's very needed. You could have a custom installer allowing hooks in packages it installs, or maybe even with a plugin if we add the given hook. I feel it'd be best than to add this in composer itself. |
I ran into this issue as well. I'd like to see it...Its useful for github enterprise users. A key like "authorize_vendor_scripts":true would work? |
+1 for an ability to enable this. Npm allows it afaik. |
As the ticket creator, I can say with confidence that I no longer need this feature. Others who find this thread should probably consider whether the Composer plugin system fits their needs instead. For instance, I managed to implement the use case I originally stated in the ticket as a plugin (composer-npm-bridge). |
+1 for this. I need to patch other packages from dependency packages - since I have too weak bargaining power to impose my patches upon upstream framework vendor.
|
@mcd-php you shouldn't need bargaining power IMO if you are doing sensible things you should be able to get it in, unless upstream is crazy but then maybe it's time to work with another project. And anyway hot-patching code on install really sounds like a bad idea. You could tell users of your lib that they should require your fork of yii2 if they want to work with your package, but IMO that's a poor proposal as well.. imagine if everyone relied on their own forks the whole ecosystem falls apart. |
Just a quick note about the reference I just posted: one use-case for this feature is conditional requirements. |
So, here is our use case. We would like to use composer to be able to install our framework, and individual packages that are plugins to the framework. As part of the installation process, we want to copy specific stub files that we just installed out of the vendor directory and into a user editable space so that the user can edit them and not worry about composer stomping on those edits on the next update. We are trying to use scripts to do the copy of those files. With the current architecture, I need to tell these users to make certain 'scripts' entries to the composer.json file. HOWEVER, if there is already a 'scripts' entry there because of other dependencies, we need to tell them to MERGE the entries into what is already there. If they remove our framework, they will have to un-merge by hand. Now, our users are not all experts. I would like to avoid the requirement of needing to know how to hand-edit a .json file before being able to use our framework. Explaining how to do this hand-editing, and to be careful of every little comma and bracket can lead to quite a bit of frustration that will be a barrier to entry for our beginning developers. With the current architecture, I can't tell them to just execute 'composer require'. I guess I don't understand your point about losing user control. If I require a package in my top level composer.json file, I want that package to install. If that package fires off some scripts during installation, as a user of that package, I WANT that. I could easily inspect that package's composer.json file to see what it is trying to do if something goes wrong. The package creator can communicate in its documentation that it is firing off scripts at install and update time. Composer could notify the user during the composer execution process by outputing "Executing xyz script from package ABC" as part of the messages it sends out. Composer could have some options to not execute package scripts, or even have an interactive option to ask for confirmation on each script it finds. All of these would give the user sufficient control in the very unlikely event that the user would want that. If you still don't agree, then perhaps at a minimum have the
Don't both of these options require a bunch of work by the developer, and the user has to create special entries in the top-level composer.json file? And these packages are then allowed to fire custom scripts on their own. I don't see how doing more work is better, when the end result is basically the same thing, that a package that was installed is firing a script at install time. I don't see how calling it a 'composer-plugin' means that the user has more control than the scenario that any required package could fire off scripts. |
@spekary Thank you!
I totally agree. If at the end of the day I still need to edit some JSON files by hand to get my dependencies to work then why bother with composer in the first place? |
The point is that use cases described here are kind of abusing what composer is for. It is not a boostrapping tool for framework-based projects. |
The script simply checks to see if the file is there, and if it is already there, it will not over-write it. Its not that difficult. So, perhaps this should become an open issue debate on what IS composer. The dev team sometimes calls it a dependency manager, and sometimes an installer. Whether the dev team knows it or not, Composer has become the defacto way to install PHP libraries and even whole frameworks for people who want to use those things to develop websites. The PHP developer community expects all PHP libraries and frameworks to be Composer installable. As such, there is a certain amount of responsibility the dev team has to make it easy to use for novice PHP developers. Admittedly, Composer has a little bit become a victim of its own success. I am not asking for Composer to be a complete solution for all bootstrapping. However, I AM asking that package developers be given the ability to configure their own composer.json files in such a way that Composer is 99% there. Script launching is the missing piece. The issue has come up over and over, I would think the message is pretty clear. @Seldaek gave some principles for why dependencies should not launch scripts. Mainly, he said users would lose control of the installation process. I assume he means that since a script isn't explicitly called out in the top-level composer.json file, it is therefore hidden and therefore there is some loss of user control. I think there are lots of ways of mitigating this and I gave some. However, I think he is trying to protect users from something they don't want protection from. I think the primary problem is a misunderstanding of your audience. There seems to be an assumption that all users of composer are accomplished programmers and .json editors. I would say most composer users are at the level of struggling to just get composer installed, and they follow a set of commands or instructions to use composer to get some PHP thing installed. They do NOT want to know the inner workings and they would like to avoid editing a .json file as much as possible. The The principle I would recommend going by is "Give the people with the problem the ability to solve their own problem." The dev team tried to do that with plugins and custom installers, but unless I am mistaken (and I easily could be, I don't totally understand how a user configures a composer.json file to use a package's custom installer), there is no way for package developers that need some extra installation steps to tell users to just |
Also +1. About security concerns and backwards compatibility: wouldn't it be enough if the feature has to be explicitly enabled in the root composer.json file? |
I'm ashamed to be looking for the same thing. Please forget I was here ;) |
Also have this need :( |
Best option is to have people use "composer create-project" Then you get git clone and composer install which can do the installation process for them. That was the best alternative in my case. |
What about a package such as this one that needs to set permissions of bundled binaries after installation? I tried this and it doesn't work. The I could set the I don't understand the security concerns around this? I mean, I can just set my package type as |
Another hacky work-around would be to use composer-locator and the Bottom line is there are plenty of hacky ways to do this, so why not provide an official way to do it? If security is the only reason, we have a slew of features already that are dangeous anyway... don't we? |
I just don't see the problem at all for this package.. Git supports setting permissions in the file metadata, which will propagate fine on unix systems and is kinda ignored on windows but there it's irrelevant anyway. Why not just set the binaries to be executable in git and be done with it? |
I had no idea that was possible. I'll try. |
|
That works, thanks! Sorry for taking up your time, but I tried everything I could find, I just had no idea this was even possible with Git in the first place. |
I don't mind if someone learned something ;) |
As this has been a requested feature for 5 years now, with people still requesting it (myself now included) can this not be implemented as a My use case is migrating a database. We have packages that are grouped together in a meta composer repo. We then install this single repository onto the API infrastructure. I was hoping to have composer auto-run the package post install scripts, which would run the relevant database migrations for each required package. If I can't do this, has anyone any suggestions how to do it? I really haven't the time to learn the composer plugin architecture to achieve something I thought possible already (and therefore haven't accounted sprint time for). A simple
Thoughts? |
Contact me @johnrobertporter. As Composer has good reasons not to do this. It's probably not that hard to provide a plugin for this with the config you describe. Merge plugin already does similar stuff. Althouh it might require a re-run on initial install of the plugin. Unless you put it globally. verbruggenalex-at-gmail-dot-com. |
Don't execute dependency code automatically, as then you'll run into this: |
The suggestion from @johnrobertporter is exactly what I need. We have packages that we're writing ourselves that are used across multiple projects, it would be great to be able to whitelist them in this way, including their scripts. |
Blocking dependency update event scripts wouldn't help prevent that. A compromised package could just as easily run malicious code at runtime. |
@uphlewis but you can have a chance to review the install code before the runtime. For code running at installation time, it runs before you could look at it. |
@kurtfoster @stof Don't know about you guys but I never look at source code after I composer require but before running the application if the code is from a reputable source. If anything, I would review it in github before running composer require. I feel like running dependency scripts would be extremely helpful without introducing much more risk then what's already there when installing a 3rd party dependency. |
Why not a bin export? "bin" : ["bin/mypackage-setup"] if you have a freamworky system with a lot of other component packages then you can just have one bin from your framework detect and setup other components. Would be so easy to also make your setup command edit the users composer.json for them and add a scripts entry so it happens for every install/update command they do in future. For npm dependencies can use npm-bridge but you can just as easily commit your node_modules folder instead. Since bridge will duplicate all the npm dependencies in each vendore/package/node_modules folder anyway then why not make it easy on yourself and also prevent users form breaking your package with npm updates. |
@b-hayes bin export won't help to automatically run such a script after the installation, regardless of any framework or anything else, and that's what this feature request is about: define a way to run a script defined by a dependency without any further interaction |
@NicoHaase yeah I know I. But there is no way to automatically run scripts and its probably not coming anytime soon, or ever. So just offering a simple work around. It's only one command line after they run composer require. Not very hard for a user to do. |
I was looking for the same feature and made a composer library which is implementing the proposed solution from the 14 Feb 2018. In order to avoid security breaches, only PackageEvents raised by a package will be forwarded to scripts matching the event in its package. Pushed code here : https://github.com/mathias-meyer/composer-package-updater I'm about to have it handled by packagist as well. Mathias |
Now available in packagist under |
Well, I did something very similar to allow dependencies to perform post-install compilation tasks. The permission model was initially pretty flat (eg on/off switch - with an interactive prompt to get permission on first run), but it looked like the "whitelist" approach had a lot of buy-in here, so I switched to a whitelist. Currently, it's tagged as v0.3. In a library package (upstream POV), the {
"name": "test/gnocchi",
"require": {
"civicrm/composer-compile-plugin": "@dev",
"scssphp/scssphp": "1.2.0",
"padaliyajay/php-autoprefixer": "~1.2"
},
"autoload": {"psr-4": {"ScssExample\\": "src"}},
"extra": {
"compile": [{"php-method": "\\ScssExample\\ScssExample::make"}]
}
} During installation on the root-package (downstream POV), More details at https://github.com/civicrm/composer-compile-plugin |
Is there a valid reason why scripts are not executed for dependencies? I'm sure this has been discussed before, but I couldn't find an issue here.
I have a use case. I have written a component that allows NPM packages to be installed/updated at the same time as Composer's dependencies by using the scripts system.
The component works great for end projects, but obviously cannot be used for dependencies currently, which is where it would actually be useful.
Even if it's not something that will be implemented, it would be nice to know why it's not possible or desirable.
The text was updated successfully, but these errors were encountered: