How to ignore directories with Composer? - composer-php

I'd like to release a PHP library and submit it on Packagist to have it installable via Composer.
My library has the following structure:
lib/
tests/
composer.json
README.md
Basically, whenever I include this library in a project's composer.json, I'd like everything to be copied with the exception of the tests directory, which is cumbersome and is only needed when developing the library itself. It's just a waste of space otherwise (especially when packaging the project for production).
Is it possible to exclude this directory from the library's composer.json?

This is not possible in Composer. However, there are some ways to do it:
When you run the update or install command with --prefer-dist, Composer tries to download the archive on github. You can remove the test directory from the archives by putting this in a .gitattributes file in the root directory of your project:
Tests/ export-ignore
Composer will only use the tags on github. Just temporary remove the tests directory when creating a tag will also do the trick.

It's possible to control the archive creation by adding exclude patterns in the composer.json file within the archive key. See https://getcomposer.org/doc/04-schema.md#archive for details.
The example given (cited from above URL):
{
"archive": {
"exclude": ["/foo/bar", "baz", "/*.test", "!/foo/bar/baz"]
}
}
The example will include /dir/foo/bar/file, /foo/bar/baz, /file.php, /foo/my.test but it will exclude /foo/bar/any, /foo/baz, and /my.test.
That way you have about the same control that .gitattributes would give you, without having to use Git or affecting any processes that require different settings in said file.

This has been possible since Nov 11, 2015 with https://getcomposer.org/doc/04-schema.md#exclude-files-from-classmaps
Source: https://github.com/composer/composer/issues/4456#issuecomment-155825777
EDIT: Misinterpretation. The above only lets the autoloader ignore the specified paths, it does not actually prevent them from being copied to the filesystem upon install.

This can be automated with post-update-cmd the composer.json file within the scripts key:
"scripts": {
"post-update-cmd": [
"rm -rf vendor/aura/intl/tests vendor/cakephp/cakephp/tests"
],
},
Or use pattern to remove directories:
"scripts": {
"post-update-cmd": [
"find vendor/ -type d -regextype posix-extended -iregex '.*/(doc|docs|example|examples|test|tests|tmp)' -print -exec rm -r {} +"
],
},

Related

Is there a way to use one Vendor for multiple projects with different seeder

i was having issues on how vendor take too much place. Since my host has a limit on number of files and folders (INODES). So i found a solution to use one Vendor for multiple project in laravel through the following link : Using one Vendor Folder for Multiple Projects in Laravel 5.2.
In the following lines I put the vendor in projectA, then link the others projects to it.
In projectA everything works well when i do php artisan migrate:fresh --seed
When i try the same thing to projectB for example, the above command works till it arrives where the seeders should be executed. There, some error occur due to the fact that the command is trying to launch a seeder of projectA in the projectB as shown in the following screenshot.
Seeder Error Screenshot
So i want to know if there's a way to make the seeder separately.
I tried to create a symlink on the composer.json file as it was done for the vendor folder, but it doesn't work.
I'm using Laravel 8
I thínk this is a terrible idea, except in the case that both projects share exact same codebase.
Composer use composer.json as you know. How does your B project composer file determines how to resolve PSR4 autoload entries in Laravel, If it is symlinked to A project? That is probably the reason why your seed command is trying to locate Classes in A project.
Composer is clever enough to cache downloaded packages and reuse them, but I think that every project has its own dependencies and state, which is maintained by composer.json in the first case and composer.lock on the state case.
What happen if you update composer in A but not in B, will B work?
And last, composer autoload file reference all satisfied dependencies in your project, and in this case that (unique) autoload file will be loaded in both projects but what happen if your required packages are not exactly the same? ie You have Laravel Debug Bar in one project but not in the other. The autoload generated file will reference that package that will not exist on your other project.
Is not this the way composer work? Am I wrong?
In Composer the Vendor Directory (vendor in the project tree by default) is per project.
You ask about how to use one vendor folder for different projects.
Now first of all, this is absolutely not what Composer expects nor how it works. See Manuel Glez answer. In short a terrible idea.
When it comes to Composer, the place to share the actual PHP code across projects is not in the vendor directory but in repositories.
And as long as the dependencies are compatible, you could make one project depend on another and use its vendor/<vendor>/<name> folders as repositories. The remarks in Manuel Glez answer are still the same, this need to be same compatible versions across the board.
But to give the example, see Composer Path Repository which has this layout:
...
├── apps
│ └── my-app
│ └── composer.json
├── packages
│ └── my-package
│ └── composer.json
...
{
"repositories": [
{
"type": "path",
"url": "../../packages/my-package"
}
]
}
It can be adopted for each ../../project/A/vendor/<pkg-vendor>/<pkg-name> in ../../project/B/composer.json so that the vendor folder in project/A can act as a path repository for project/B.
As dependencies composer.json files normally do not contain the version, the documented remarks about repositories.options.versions apply:
When the version cannot be inferred from the local VCS repository, or when you want to override the version, you can use the versions option when declaring the repository:
{
"repositories": [
{
"type": "path",
"url": "../../packages/my-package",
"options": {
"versions": {
"my/package": "4.2-dev"
}
}
}
]
}
To prevent the duplication of the files the default strategy for Composer is to symlink the package directories. Ensure it works, then you only have one symbolic link per dependency in project B.
Okay how cool is that? Well IMHO while you still give up much of what Composer can do for you for dependency management, this at least makes use of local Composer repositories which I'd recommend for sharing instead of completely symlinking the overall vendor folder. Each project still have its own vendor/composer setup and overall what is done is much more well defined and in line with Composer itself.
Whether this works or not depends on the individual case. Key point here is as these local repositories only provide a single version per each package, you can only have that one. So these versions must all be version compatible on API level.
The system where it runs needs to support (relative) symbolic links, this should be commonly available for the situation described.
You could then automate the production of the repositories configuration and adopt it to the file-system layout. You could even generate the repositories and update them in the global configuration file so that each project would automatically prefer those packages from local.
$ echo "$(composer config --global home)/config.json"
/home/user/.config/composer/config.json
(compare: COMPOSER_HOME/config.json (Composer docs))
Take care all projects and their dependencies have a portable path-profile and then I'd say this should be quite straight forward shell processing.
To obtain the actual versions of the dependencies installed check per each vendor folder inside vendor/composer/*installed* files.
$ (echo "PACKAGE VERSION"; find .. -type f -path '*/vendor/composer/installed.json' -exec jq -r '.packages[] | .name + " " + .version_normalized ' {} \; | sort -u | sort -k 1b,2V) | cols
PACKAGE VERSION
composer/ca-bundle 1.3.2.0
composer/composer 2.3.7.0
composer/metadata-minifier 1.0.0.0
composer/pcre 3.0.0.0
composer/semver 3.3.2.0
composer/spdx-licenses 1.5.7.0
composer/xdebug-handler 3.0.3.0
...
phar-io/manifest 1.0.1.0
phar-io/manifest 1.0.3.0
phar-io/manifest 2.0.1.0
phar-io/manifest 2.0.3.0
...
(very old installations don't have the packages keyword, you'll likely want to filter)
Finally you may want to have something to smoke-test the setup easily so that you can have guards against the dependency incompatibility problems when you take notice of them.

npm publish (using also lerna) is ignoring ts definition file

Hi all I am creating this public library
https://github.com/kristijorgji/winstonjs-utils using ts+lerna monorepo
My issue is that although having specified in every package.json
"files": [
"./dist"
],
The file dist/index.d.ts is ignored by the publish command
When I build typescript , the dist folder has two files
But in the published package under dist exists only index.js
I do not have any .npmignore file as you can also see in the public repo I shared.
In all packages packages.json I have specified the typings as well
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"./dist"
],
Any idea why index.d.ts is excluded from the published packages ? Thanks
I managed to find one solution although might not be the best one.
Nevertheless I am posting in lack of an answer to help everyone facing same issue as me
Solution: I used .npmignore instead of files in package.json
files key seem broken because it ignores index.d.ts files
I used a .npmignore file that excludes unecessary things like
__tests__
coverage
src
tasks
.eslintrc.js
jest.config.js
nodemon.debug.json
nodemon.json
tsconfig.json
then publishing the package worked great with same result as I intended, having only dist folder with index.js index.d.ts inside and package.json and readme.md

Why did composer install oauth2-client with different directory names and files

I am new to composer and I used it to install the oauth2-client. I think I am having some sort of misunderstanding about how this is supposed to work.
From thephpleague github page I installed from the command line using
composer require league/oauth2-client
This added files to /usr/local/bin/vendor/league/oauth2-client.
The file structure looks the same as it does on github, except I don't have all the same files.
And the php in the files is looking for files in \League\OAuth2, so I am getting errors that it can't find included files, because I don't have that directory.
Did I do it wrong, or am I just not getting something?
The backslash is the PHP namespace separator, not the directory separator.
In the composer.json for oauth2 from TheLeague, this is the autoload directive:
"autoload": {
"psr-4": {
"League\\OAuth2\\Client\\": "src/"
}
},
It says that the code inside of src directory is in the League\OAuth2\Client namespace.
Composer follows PSR-4 with regards to namespacing and autoloading, so check that out if you want to know what goes on.
UPDATE:
If you've installed other League extensions, like oauth2-facebook, it will install itself into the same src directory - because of the autoload directive in composer.json.
Why?
Well, because of the namespace, you will find 'Facebook' in the League\OAuth2\Client\Provider namespace.
Because of PSR-4, this means that they need to go into the same directory, even though they are different packages.
That is the reason why you'll see Facebook.php in src/Providers directory. Check the oauth2-facebook repository
You probably have required oauth2-facebook and oauth2-google, or one of your other required packages requires it. It rarely just add themselves. :)

Composer private package issue

I have created a private composer package in packagist.com but when I use
composer require command to fetch it. My package coming under vendor folder which is on root.
But I want it to be in app/code folder. Is there any parameter for composer.json where I can set app/code, so it will come under app/code/.
Yes there is. According to the composer documentation, if your project uses the PSR-4 specification for loading classes, then adding the snippet below to the composer.json file would work.
NB: You will need to change ProjectNameSpace to the base namespace for your project.
...
"autoload": {
"psr-4": {
"ProjectNameSpace\\": "app/code"
}
},
...
Theoretically. You can't composer will always place the code in vendor directory. The code is external and therefore can be updated only by composer. It must not be in app/code as only code you modify for the project should be in app/code.
If you wish to make a Magento project, you should have the fallowing files in the versioning tool.
app/*
composer.json
composer.lock
.htaccess
index.php
The other files will be handled by composer.
But if you really need to do it, but I don't see any reason to do so, then you could use a post-update & post-install script to move the code. But it's a very bad idea.

How to set custom folder path for sub folders in vendor when installing a package?

I want to install a package into my local project.For that I'm creating a composer.json file in my project folder is given below, it gives the total vendor folder of that package into my custom folder in my project. Its working fine.....
{
"config": {
"vendor-dir": "/var/www/html/Test2/Testing/Down"
},
}
It gives the package into 'Down' folder.
But, now I want the sub folders or files in that packages to be installed in my custom folders like js/css folders in my project.
For example i want jquery.js file into my local folder path
/var/www/html/Test2/Testing/assests/js
From the package "frameworks/jquery".
For that, what changes are needed in my composer.json file?
Composer is used to bring in packages to support the PHP code of a project, here is how they describe it on the Composer website:
Composer is a tool for dependency management in PHP. It allows you to
declare the libraries your project depends on and it will manage
(install/update) them for you.
In other words, if you need to do logging in your PHP code and decide to use the publicly available monolog package, you use composer to bring that package into your project, then in your PHP code, you can call monolog functions.
Using config to rename the vendor directory is trying to use Composer in a way that doesn't fit the intent of the tool. The vendor directory is used to hold the packages brought in (such as the monolog code). The vendor-dir value is simply renaming that directory.
Since you have GitHub listed as a tag, you could possibly use cloning to get your files to your website directory.
I've modified my composer.json file, it looks like the below:
{
"config": {
"vendor-dir": "/var/www/html/Test2/Testing/Down"
},
"require": {
},
"scripts": {
"post-package-install": [
"php -r \"exec('cp -r /var/www/html/Test2/Testing/Down/frameworks/jquery/* /var/www/html/Test2/Testing/assets/js');\""
]
}
}
It will gives all selected files in a package to my local folder.
Briefly the files in the folder 'frameworks/jquery' are copied into my local 'assets/js' folder.

Resources