-
-
Notifications
You must be signed in to change notification settings - Fork 14.2k
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
PHP: add new builder for PHP projects #225401
Conversation
68e751a
to
3413405
Compare
3413405
to
cd28cd8
Compare
a41c99d
to
0af55b5
Compare
a3c858c
to
7bce023
Compare
2d00f67
to
a965083
Compare
01338af
to
da64d1d
Compare
It has been suggested more than once to split this huge PR in two. One containing the new builder, and another one containing the updated derivation. This is now (almost) done:
I will now close this PR and update this post when the second PR will be done. |
Are you going to update the derivations to the new builder? :) Would be a huge improvement! Or is this already done? |
@onny Yes, that's the plan... some derivations switched to the new builder already, the first one being Composer. |
Introducing a new builder for PHP Composer-Based Applications
Ensuring reproducibility and stability of outputs is required even when using an external dependency manager (Composer). As such, we've explored several possible solutions.
The first attempt of this PR was using a Fixed Output Derivation strategy, using the Composer cache. Although this solution rectified numerous issues, it was not entirely secure, as it was heavily dependent on Composer. If Composer implemented even a minor structural alteration in the cache structure, it could break all derivations based on this builder. As a result, we concluded that this solution wasn't ideal.
Our second attempt involved the use of fossar/composition-c4. This project reads the
composer.lock
file and constructs a local Composer repository, which is then used to install the dependencies. However, as Import From Derivation (IFD) is not permitted innixpkgs
, this approach didn't serve as a feasible solution. Moreover,path
type repositories are currently unsupported, adding another roadblock.A proof-of-concept led to the creation of our last and final attempt; a custom Composer plugin,
drupol/composer-local-repo-plugin
providing a new command. It mirrors the functionalities offossar/composition-c4
and is written in PHP. It relies entirely on Composer to create a local Composer repository, thus emerging as a solid solution.Although this plugin is currently hosted under my own name, there is a consideration to host it elsewhere, a decision yet to be made.
Overcoming Challenges
A major challenge encountered while creating local Composer repositories was that Composer reads the
composer.lock
file and downloads all the packages, including anydev
dependencies. We had no way of discerning whether a dependency was required from therequire
orrequire-dev
section.For instance, dependencies like
phpstan/phpstan
took roughly 10 minutes (1.3Gb) to download, as the plugin usesgit
to create the local Composer repository. As a result, the creation of a derivation was time-consuming and not particularly environmentally friendly.I was running out of ideas and patience. I abandoned the PR for a while and at some point, during a hot shower, I had the idea to nuke the
require
section fromcomposer.json
andpackages-dev
fromcomposer.lock
(usingjq
). Although it substantially modifies the source files (in the derivation only) which is something we aim to minimize but in the end turned out to be a fix for many issues.As a result, this is now implemented in this PR. Essentially, this new builder will never download any development dependency from any PHP project, which, upon reflection, makes perfect sense. Derivations built with this new wrapper are smaller and we only download what we need to run the application, nothing else.
25 May 2023
Yesterday evening while "half-watching" the TV, I have discovered an improved method for creating a local composer repository utilizing the Composer API only, the
composer install
step is not required anymore (special thanks to @Seldaek for his assistance!). The plugin greatly simplifies the process of deciding whether or not to download dev dependencies, making it both easier and safer. Additionally, we've eliminated the need to manually modify thecomposer.lock
andcomposer.json
files withjq
, streamlining the process further.Here's a diagram overview on how the new builder is working
This PR includes the following changes:
mkDerivation
wrappers)php.buildComposerProject
php.mkComposerRepository
php.composerHooks.composerRepositoryHook
php.composerHooks.composerInstallHook
drush
)drush-launcher
: init at 0.10.2phpbench
: init at 1.2.10phpDocumentor
: init at 3.3.1 (+ upstream patch at feat: add support forAPP_CACHE_DIR
andAPP_LOG_DIR
phpDocumentor/phpDocumentor#3518)robo
: init at 4.0.4This new helpers significantly simplifies the process of integrating applications such as Symfony App, Wordpress or even Drupal into Nix, streamlining development and deployment.
Below is a practical example demonstrating how to efficiently package Drupal using this approach:
Or magento2:
This PR offers substantial improvements, allowing the majority of PHP derivations that rely on PHAR-based distribution to be replaced with direct source code. As Nix builds and runs software in an isolated environment, it ensures there will be no conflicts, resulting in a more efficient and reliable system.
Now, the amount of PHP PHAR based softwares in Nix now: Just one!
Remarks
phpcbf
is now merged inphpcs
derivationSince it is now using the new builder which is able to create the symlinks automatically, installing phpcs installs at the same time
phpcs
andphpcbf
. Therefore,phpcbf
derivation is not needed anymore.I noticed that Deployer has a unique release workflow, which involves making a commit, applying a tag to that commit, cleaning the repository, and committing the PHAR file on that same commit. Development then continues from the parent of that tagged commit. This process is illustrated in the attached image.
As a result, we cannot directly use the tagged version in the
src.rev
attribute. Instead, we have to use the parent commit of the tagged version. For example, in the case of tag 7.3.1, the parent commit is d99377d7, which is precisely the revision I have used for thesrc.rev
attribute. If you believe there is a better way to handle this situation, please feel free to suggest an alternative approach. I look forward to hearing your thoughts on this matter. This is now fixed by usingrev = "v${f.version}^";
, thanks @jtojnar !Not so related commits
robo
task runner (https://robo.li/)drush
as a standalon tool anymore, see Add minimum required dependencies drush-ops/drush#5537 and adddrush-launcher
as an alternative as suggestedUpcoming PRs
Ask each maintainers of these PHP programs to let the
composer.lock
file live in their projectAutomatically parse
composer.json
for extensions and instantiate thephp
attribute with these extensions enabled. This has already been done in https://github.com/loophp/nix-shell/, we just need to formalize it in here.