仓库
本章将解释包和仓库的概念、可用的仓库类型以及它们的工作原理。
在我们了解现有的不同类型的代码库之前,我们需要理解Composer所基于的一些基本概念。
Composer是一个依赖管理工具。它在本地安装包。包本质上是一个包含某些内容的目录。在这种情况下,它是PHP代码,但理论上可以是任何东西。并且它包含一个具有名称和版本的包描述。名称和版本用于识别该包。
实际上,在内部,Composer 会将每个版本视为一个独立的包。虽然在使用 Composer 时,这种区别并不重要,但当你想要对其进行更改时,这一点就非常关键了。
除了名称和版本之外,还有一些有用的元数据。与安装最相关的信息是源定义,它描述了从何处获取包内容。包数据指向包的内容。这里有两个选项:dist(发行版)和source(源代码)。
**发行版:**发行版是软件包数据的打包版本。通常是已发布的版本,通常为稳定版本。
**来源:**来源用于开发。它通常源自源代码仓库,例如git。当你想要修改下载的包时,可以获取它。
软件包可以提供其中一种,甚至两种都提供。根据某些因素,例如用户提供的选项和软件包的稳定性,会优先选择其中一种。
仓库是一个包源。它是一个包/版本的列表。Composer会在你所有的仓库中查找你的项目所需的包。
默认情况下,只有Packagist.org仓库在Composer中注册。你可以通过在composer.json中声明更多仓库来将它们添加到你的项目中。
仓库仅对根包可用,并且在您的依赖项中定义的仓库将不会被加载。如果您想了解原因,请阅读FAQ条目。
解析依赖项时,会从上到下从各个仓库中查找包,默认情况下,一旦在某个仓库中找到包,Composer就会停止在其他仓库中查找。有关更多详细信息以及如何更改此行为,请阅读仓库优先级文章。
Composer
Section titled “Composer”主要的仓库类型是composer仓库。它使用一个包含所有包元数据的packages.json文件。
这也是packagist所使用的仓库类型。要引用composer仓库,请提供packages.json文件之前的路径。就packagist而言,该文件位于/packages.json,因此仓库的URL为repo.packagist.org。对于example.org/packages.json,仓库的URL为example.org。
{ "repositories": [ { "type": "composer", "url": "https://example.org" } ]}唯一必填字段是packages。JSON结构如下:
{ "packages": { "vendor/package-name": { "dev-master": { @composer.json }, "1.0.x-dev": { @composer.json }, "0.0.1": { @composer.json }, "1.0.0": { @composer.json } } }}@composer.json标记将是该包版本中composer.json的内容,至少应包含:
- 名称
- 版本
- 分发或源
以下是一个最小化的包定义:
{ "name": "smarty/smarty", "version": "3.1.7", "dist": { "url": "https://www.smarty.net/files/Smarty-3.1.7.zip", "type": "zip" }}它可能包含模式中指定的任何其他字段。
notify-batch
Section titled “notify-batch”notify-batch字段允许你指定一个URL,每当用户安装软件包时,该URL都会被调用。此URL可以是绝对路径(将使用与仓库相同的域名),也可以是完整的URL。
示例值:
{ "notify-batch": "/downloads/"}对于包含monolog/monolog包的example.org/packages.json,这会向example.org/downloads/发送一个POST请求,请求体包含以下JSON内容:
{ "downloads": [ {"name": "monolog/monolog", "version": "1.2.1.0"} ]}version字段将包含版本号的标准化表示形式。
此字段为可选。
metadata-url、available-packages 和 available-package-patterns
Section titled “metadata-url、available-packages 和 available-package-patterns”metadata-url字段允许你提供一个URL模板,以服务存储库中的所有包。它必须包含占位符%package%。
此字段是Composer v2中的新增字段,如果同时存在provider-includes和providers-url字段,此字段的优先级更高。为了同时兼容Composer v1和v2,理想情况下,你应该同时提供这两个字段。不过,新的仓库实现可能只需要支持v2。
示例:
{ "metadata-url": "/p2/%package%.json"}每当Composer查找某个包时,它会将%package%替换为包名,并获取该URL。如果允许该包使用开发稳定性版本,它还会再次加载带有$packageName~dev的URL(例如,/p2/foo/bar~dev.json用于查找foo/bar的开发版本)。
包含包版本的foo/bar.json和foo/bar~dev.json文件必须仅包含foo/bar包的版本,格式为{"packages":{"foo/bar":[ ... versions here ... ]}}。
缓存是通过使用If-Modified-Since头部来实现的,因此请确保返回Last-Modified头部,并且这些头部信息是准确的。
版本数组也可以选择使用来自composer/metadata-minifier的Composer\MetadataMinifier\MetadataMinifier::minify()进行压缩。如果这样做,你应该在顶层添加一个"minified": "composer/2.0"键,以向Composer表明它必须将版本列表扩展回原始数据。示例请参见https://repo.packagist.org/p2/monolog/monolog.json。
任何不存在的请求包都必须返回404状态码,这将向Composer表明该包在你的仓库中不存在。确保404响应速度快,以避免阻塞Composer。避免重定向到其他404页面。
如果你的仓库只包含少量包,并且你想避免404请求,你也可以在packages.json中指定一个"available-packages"键,该键应该是一个包含你的仓库中所有包名称的数组。或者,你可以指定一个"available-package-patterns"键,它是一个包名称模式的数组(其中*匹配任何字符串,例如vendor/*会让Composer在这个仓库中查找所有匹配的包名称)。
此字段为可选。
providers-api
Section titled “providers-api”providers-api字段允许您提供一个URL模板,用于提供所有提供特定包名的包,但不包括具有该名称的包(即使它存在)。该模板必须包含占位符%package%。
例如,https://packagist.org/providers/psr/log-implementation.json 列出了一些对 psr/log-implementation 有“provide”规则的包。
{ "providers-api": "https://packagist.org/providers/%package%.json",}此字段为可选。
list字段允许返回与给定筛选条件匹配的包名称(如果没有筛选条件,则返回所有名称)。它应接受一个可选的?filter=xx查询参数,其中可以包含*作为通配符,以匹配任何子字符串。
此处不应考虑替换/提供规则。
它必须返回一个包名称数组:
{ "packageNames": [ "a/b", "c/d" ]}例如,参见https://packagist.org/packages/list.json?filter=composer/*。
此字段为可选。
provider-includes 和 providers-url
Section titled “provider-includes 和 providers-url”provider-includes字段允许您列出一组文件,这些文件列出了此存储库提供的包名称。在这种情况下,哈希值应为文件的sha256值。
providers-url 描述了如何在服务器上找到提供程序文件。它是从存储库根目录开始的绝对路径。它必须包含占位符 %package%</b1 和 %hash%</b2。
这些字段供Composer v1使用,或者在您的仓库未设置metadata-url字段时使用。
示例:
{ "provider-includes": { "providers-a.json": { "sha256": "f5b4bc0b354108ef08614e569c1ed01a2782e67641744864a74e788982886f4c" }, "providers-b.json": { "sha256": "b38372163fac0573053536f5b8ef11b86f804ea8b016d239e706191203f6efac" } }, "providers-url": "/p/%package%$%hash%.json"}这些文件包含用于验证文件完整性的包名称和哈希值列表,例如:
{ "providers": { "acme/foo": { "sha256": "38968de1305c2e17f4de33aea164515bc787c42c7e2d6e25948539a14268bb82" }, "acme/bar": { "sha256": "4dd24c930bd6e1103251306d6336ac813b563a220d9ca14f4743c032fb047233" } }}上述文件声明,通过加载providers-url所引用的文件,并将%package%替换为供应商命名空间的包名称,将%hash%替换为sha256字段,即可在该仓库中找到acme/foo和acme/bar。这些文件本身包含如上文所述的包定义。
这些字段是可选的。对于你自己的自定义仓库,你可能不需要它们。
cURL 或流选项
Section titled “cURL 或流选项”可以通过cURL(启用了ext-curl的Composer 2)或PHP流来访问该代码库。你可以使用options参数设置额外选项。对于PHP流,你可以设置任何有效的PHP流上下文选项。有关更多信息,请参阅上下文选项和参数。使用cURL时,只能配置有限的http和ssl选项。
{ "repositories": [ { "type": "composer", "url": "https://example.org", "options": { "http": { "timeout": 60 } } } ], "require": { "acme/package": "^1.0" }}VCS是版本控制系统的缩写。这包括git、svn、fossil或hg等版本控制系统。Composer有一个存储库类型,用于从这些系统安装包。
从VCS仓库加载包
Section titled “从VCS仓库加载包”这有几个使用场景。最常见的是维护第三方库的个人分支。如果你在项目中使用某个库,并且决定对该库进行一些修改,你会希望自己的项目使用这个经过修改的版本。如果该库托管在GitHub上(大多数情况下都是如此),你可以在那里创建它的分支,并将你的修改推送到自己的分支。之后,更新项目的composer.json即可。你只需将自己的分支添加为一个仓库,并更新版本约束以指向你的自定义分支。仅在composer.json中,你应该在自定义分支名称前加上"dev-"(不要将其作为实际分支名称的一部分)。有关版本约束的命名约定,请参阅库以获取更多信息。
假设你在 bugfix 分支中修补了 monolog 以修复某个 bug 的示例:
{ "repositories": [ { "type": "vcs", "url": "https://github.com/igorw/monolog" } ], "require": { "monolog/monolog": "dev-bugfix" }}当你运行php composer.phar update时,你应该会得到修改后的monolog/monolog版本,而不是来自packagist的版本。
请注意,除非你真的打算长期派生该包,并完全脱离原始包,否则不应重命名该包。由于自定义仓库的优先级高于packagist,Composer会正确选择你的包而不是原始包。如果你想重命名该包,应该在默认(通常是master)分支中进行,而不是在功能分支中,因为包名称是从默认分支获取的。
还要注意,如果你在派生仓库的composer.json文件中修改了name属性,覆盖将无法生效,因为该属性需要与原始属性匹配才能使覆盖生效。
如果其他依赖项依赖于你分叉的包,可以对其进行内联别名处理,使其符合原本不符合的约束条件。有关更多信息,请参阅别名文章。
使用私有仓库
Section titled “使用私有仓库”完全相同的解决方案允许您处理GitHub和Bitbucket上的私有仓库:
{ "repositories": [ { "type": "vcs", "url": "git@bitbucket.org:vendor/my-private-repo.git" } ], "require": { "vendor/my-private-repo": "dev-master" }}唯一的要求是为git客户端安装SSH密钥。
Git 替代方案
Section titled “Git 替代方案”Git并非VCS仓库支持的唯一版本控制系统。支持的系统如下:
- Git: git-scm.com
- Subversion:subversion.apache.org
- Mercurial: mercurial-scm.org
- 化石:fossil-scm.org
要从这些系统获取包,你需要安装它们各自的客户端。这可能不太方便。出于这个原因,系统对GitHub和Bitbucket提供了特殊支持,它们利用这些网站提供的API来获取包,而无需安装版本控制系统。版本控制系统仓库为它们提供了dist,这些发行版以压缩包的形式获取包。
- GitHub: github.com(Git)
- 钻头桶:bitbucket.org(G it)
将根据URL自动检测要使用的VCS驱动程序。不过,若因任何原因需要指定一个驱动程序,你可以使用bitbucket、github、gitlab、perforce、fossil、git、svn或hg作为存储库类型,而非vcs。
如果你在GitHub仓库中将no-api键设置为true,它会像克隆其他任何git仓库一样克隆该仓库,而不是使用GitHub API。但与直接使用git驱动不同,Composer仍会尝试使用GitHub的zip文件。
请注意:
- 要让Composer选择使用哪个驱动程序,需要将仓库类型定义为“vcs”
- 如果您已经使用过私有仓库,这意味着Composer应该已经将其克隆到缓存中。如果您想安装带有驱动程序的相同包,请记住先执行命令composer clearcache,然后执行命令composer update,以更新Composer缓存并从发行版安装该包。
- VCS驱动程序
git-bitbucket已被弃用,建议使用bitbucket
Bitbucket 驱动配置
Section titled “Bitbucket 驱动配置”请注意,Bitbucket的仓库端点需要是https而不是git。
设置好你的Bitbucket仓库后,你还需要设置身份验证。
Subversion 选项
Section titled “Subversion 选项”由于Subversion本身没有分支和标签的概念,Composer默认假设代码位于$url/trunk、$url/branches和$url/tags。如果你的仓库有不同的布局,可以修改这些值。例如,如果你使用大写名称,可以这样配置仓库:
{ "repositories": [ { "type": "vcs", "url": "http://svn.example.org/projectA/", "trunk-path": "Trunk", "branches-path": "Branches", "tags-path": "Tags" } ]}如果没有分支或标签目录,你可以通过将branches-path或tags-path设置为false来完全禁用它们。
如果包位于子目录中,例如/trunk/foo/bar/composer.json和/tags/1.0/foo/bar/composer.json,那么你可以通过将"package-path"选项设置为该子目录,让Composer访问它,在这个例子中,设置应为"package-path": "foo/bar/"。
如果你有一个私人的Subversion代码库,可以在配置的http-basic部分保存凭据(参见配置):
{ "http-basic": { "svn.example.org": { "username": "username", "password": "password" } }}如果您的Subversion客户端默认配置为存储凭据,这些凭据将为当前用户保存,并且该服务器现有的已保存凭据将被覆盖。要更改此行为,请在您的仓库配置中设置"svn-cache-credentials"选项:
{ "repositories": [ { "type": "vcs", "url": "http://svn.example.org/projectA/", "svn-cache-credentials": false } ]}如果你想使用一个无法通过上述任何方式支持Composer的项目,你仍然可以通过使用package仓库来自行定义该包。
基本上,你需要定义与composer仓库的packages.json中包含的相同信息,但仅针对单个包。同样,最低要求的字段是name、version,以及dist或source中的任意一个。
以下是Smarty模板引擎的示例:
{ "repositories": [ { "type": "package", "package": { "name": "smarty/smarty", "version": "3.1.7", "dist": { "url": "https://www.smarty.net/files/Smarty-3.1.7.zip", "type": "zip" }, "source": { "url": "http://smarty-php.googlecode.com/svn/", "type": "svn", "reference": "tags/Smarty_3_1_7/distribution/" }, "autoload": { "classmap": ["libs/"] } } } ], "require": { "smarty/smarty": "3.1.*" }}通常情况下,你可以省略源部分,因为你其实并不需要它。
如果包含源密钥,引用字段应指向将要安装的版本。当类型字段为git时,该引用将是提交ID、分支或标签名称。
注意:不建议将git分支名称用于引用字段。虽然这是有效的,因为
git checkout支持它,但分支名称是可变的,因此无法锁定。
当类型字段为svn时,引用字段应包含在运行svn co时附加到URL的引用。
注意:这种仓库类型存在一些限制,应尽可能避免使用:
- 除非你更改
version字段,否则Composer不会更新该包。- Composer不会更新提交引用,所以如果你使用
master作为引用,你将不得不删除该包以强制更新,并且还得处理一个不稳定的锁定文件。
包仓库中的"package"键可以设置为一个数组,以定义一个包的多个版本:
{ "repositories": [ { "type": "package", "package": [ { "name": "foo/bar", "version": "1.0.0", ... }, { "name": "foo/bar", "version": "2.0.0", ... } ] } ]}虽然大多数时候你可能希望将自己的包放在Packagist上,但在某些情况下,托管自己的代码库也是有必要的。
- **私营公司软件包:**如果您所在的公司在内部使用Composer管理其软件包,您可能希望将这些软件包设为私有。
- **独立的生态系统:**如果你有一个拥有自身生态系统的项目,且其包实际上无法被更广泛的PHP社区复用,那么你可能希望将它们与packagist分开存放。WordPress插件就是一个例子。
如果要托管您自己的包,建议使用原生的composer类型仓库,它能提供最佳性能。
有一些工具可以帮助你创建一个composer仓库。
Private Packagist
Section titled “Private Packagist”私有 Packagist 是一款托管式或自托管应用程序,提供私有包托管以及 GitHub、Packagist.org 和其他包仓库的镜像服务。
查看 Packagist.com</b0 以获取更多信息。
Satis 是一个静态的 composer 仓库生成器。它有点像一个超轻量级、基于静态文件的 packagist 版本。
你给它一个包含仓库(通常是版本控制系统和包仓库定义)的composer.json文件。它会获取所有被require的包,并生成一个packages.json文件,这就是你的composer仓库。
查看satis GitHub 仓库和处理私有包的文章以获取更多信息。
在某些情况下,无法将前面提到的任何一种仓库类型(甚至是VCS类型)置于在线状态。一个典型的例子是通过构建制品进行跨组织的库交换。当然,大多数情况下这些都是私有的。要直接使用这些归档文件,可以使用artifact类型的仓库,该仓库包含一个文件夹,里面存放着这些私有包的ZIP或TAR归档文件:
{ "repositories": [ { "type": "artifact", "url": "path/to/directory/with/zips/" } ], "require": { "private-vendor-one/core": "15.6.2", "private-vendor-two/connectivity": "*", "acme-corp/parser": "10.3.5" }}每个 zip 制品都是一个 ZIP 归档文件,其根文件夹中包含 composer.json:
unzip -l acme-corp-parser-10.3.5.zipcomposer.json...如果存在两个包含同一软件包不同版本的归档文件,它们都会被导入。当在工件文件夹中添加了一个包含更新版本的归档文件,并且你运行update时,该版本也会被导入,而Composer将更新到最新版本。
除了制品仓库外,你还可以使用路径方式,这允许你依赖本地目录,无论是绝对路径还是相对路径。在处理单体仓库时,这可能会特别有用。
例如,如果你的代码仓库中有以下目录结构:
...├── apps│ └── my-app│ └── composer.json├── packages│ └── my-package│ └── composer.json...然后,要将包my/package添加为依赖项,你可以在apps/my-app/composer.json文件中使用以下配置:
{ "repositories": [ { "type": "path", "url": "../../packages/my-package" } ], "require": { "my/package": "*" }}如果该包是本地版本控制系统(VCS)仓库,版本可能会通过当前检出的分支或标签来推断。否则,版本应在该包的composer.json文件中明确定义。如果通过这些方式无法解析版本,则默认其为dev-master。
当无法从本地版本控制系统(VCS)仓库中推断出版本,或者你想要覆盖该版本时,可以在声明仓库时使用versions选项:
{ "repositories": [ { "type": "path", "url": "../../packages/my-package", "options": { "versions": { "my/package": "4.2-dev" } } } ]}如果可能,本地包将被符号链接,此时控制台中的输出将显示Symlinking from ../../packages/my-package。如果无法创建符号链接,将复制该包。在这种情况下,控制台将输出Mirrored from ../../packages/my-package。
你可以使用"symlink": true强制使用符号链接,或者使用"symlink": false选项强制使用镜像,而不是使用默认的回退策略。从单体仓库部署或生成包时,强制镜像可能会很有用。
**注意:**在Windows系统上,目录符号链接是通过NTFS连接点实现的,因为非管理员用户也可以创建它们。在Windows 7以下版本或
proc_open已被禁用的情况下,将始终使用镜像功能。
{ "repositories": [ { "type": "path", "url": "../../packages/*", "options": { "symlink": false } } ]}前导波浪号会扩展为当前用户的主文件夹,环境变量会以Windows和Linux/Mac两种符号格式进行解析。例如,~/git/mypackage会自动从/home/<username>/git/mypackage加载mypackage克隆,这等同于$HOME/git/mypackage或%USERPROFILE%/git/mypackage。
注意: 仓库路径也可以包含通配符,如
*和?。有关详细信息,请参阅 PHP glob 函数。
您可以配置包的发行版引用(出现在composer.lock文件中)的构建方式。
存在以下模式:
none- 引用将始终为 null。这有助于减少锁定文件中的冲突,但会降低清晰度,无法知晓上次更新的时间以及包是否处于最新状态。config- 引用基于包的composer.json和仓库配置的哈希值构建auto(默认使用)- 引用基于类似config的哈希构建,但如果包文件夹包含git仓库,则使用HEAD提交的哈希作为引用。
{ "repositories": [ { "type": "path", "url": "../../packages/*", "options": { "reference": "config" } } ]}禁用Packagist.org
Section titled “禁用Packagist.org”你可以通过在你的composer.json中添加以下内容来禁用默认的Packagist.org仓库:
{ "repositories": [ { "packagist.org": false } ]}您可以使用全局配置标志全局禁用Packagist.org:
php composer.phar config -g repo.packagist.org false