Add a readonly mode to the cache, fixes #9150
parent
875a4784ed
commit
90332f1dbd
|
@ -85,11 +85,11 @@ gitlab.com the domain names must be also specified with the
|
|||
|
||||
## gitlab-token
|
||||
|
||||
A list of domain names and private tokens. Private token can be either simple
|
||||
string, or array with username and token. For example using `{"gitlab.com":
|
||||
A list of domain names and private tokens. Private token can be either simple
|
||||
string, or array with username and token. For example using `{"gitlab.com":
|
||||
"privatetoken"}` as the value of this option will use `privatetoken` to access
|
||||
private repositories on gitlab. Using `{"gitlab.com": {"username": "gitlabuser",
|
||||
"token": "privatetoken"}}` will use both username and token for gitlab deploy
|
||||
"token": "privatetoken"}}` will use both username and token for gitlab deploy
|
||||
token functionality (https://docs.gitlab.com/ee/user/project/deploy_tokens/)
|
||||
Please note: If the package is not hosted at
|
||||
gitlab.com the domain names must be also specified with the
|
||||
|
@ -204,6 +204,10 @@ downloads. When the garbage collection is periodically ran, this is the maximum
|
|||
size the cache will be able to use. Older (less used) files will be removed
|
||||
first until the cache fits.
|
||||
|
||||
## cache-read-only
|
||||
|
||||
Defaults to `false`. Whether to use the Composer cache in read-only mode.
|
||||
|
||||
## bin-compat
|
||||
|
||||
Defaults to `auto`. Determines the compatibility of the binaries to be installed.
|
||||
|
|
|
@ -237,6 +237,10 @@
|
|||
"type": ["string", "integer"],
|
||||
"description": "The cache max size for the files cache, defaults to \"300MiB\"."
|
||||
},
|
||||
"cache-read-only": {
|
||||
"type": ["boolean"],
|
||||
"description": "Whether to use the Composer cache in read-only mode."
|
||||
},
|
||||
"bin-compat": {
|
||||
"enum": ["auto", "full"],
|
||||
"description": "The compatibility of the binaries, defaults to \"auto\" (automatically guessed) and can be \"full\" (compatible with both Windows and Unix-based systems)."
|
||||
|
|
|
@ -30,19 +30,22 @@ class Cache
|
|||
private $enabled = true;
|
||||
private $allowlist;
|
||||
private $filesystem;
|
||||
private $readOnly;
|
||||
|
||||
/**
|
||||
* @param IOInterface $io
|
||||
* @param string $cacheDir location of the cache
|
||||
* @param string $allowlist List of characters that are allowed in path names (used in a regex character class)
|
||||
* @param Filesystem $filesystem optional filesystem instance
|
||||
* @param bool $readOnly whether the cache is in readOnly mode
|
||||
*/
|
||||
public function __construct(IOInterface $io, $cacheDir, $allowlist = 'a-z0-9.', Filesystem $filesystem = null)
|
||||
public function __construct(IOInterface $io, $cacheDir, $allowlist = 'a-z0-9.', Filesystem $filesystem = null, $readOnly = false)
|
||||
{
|
||||
$this->io = $io;
|
||||
$this->root = rtrim($cacheDir, '/\\') . '/';
|
||||
$this->allowlist = $allowlist;
|
||||
$this->filesystem = $filesystem ?: new Filesystem();
|
||||
$this->readOnly = (bool) $readOnly;
|
||||
|
||||
if (!self::isUsable($cacheDir)) {
|
||||
$this->enabled = false;
|
||||
|
@ -59,6 +62,22 @@ class Cache
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $readOnly
|
||||
*/
|
||||
public function setReadOnly($readOnly)
|
||||
{
|
||||
$this->readOnly = (bool) $readOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isReadOnly()
|
||||
{
|
||||
return $this->readOnly;
|
||||
}
|
||||
|
||||
public static function isUsable($path)
|
||||
{
|
||||
return !preg_match('{(^|[\\\\/])(\$null|nul|NUL|/dev/null)([\\\\/]|$)}', $path);
|
||||
|
@ -90,7 +109,7 @@ class Cache
|
|||
|
||||
public function write($file, $contents)
|
||||
{
|
||||
if ($this->enabled) {
|
||||
if ($this->enabled && !$this->readOnly) {
|
||||
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file);
|
||||
|
||||
$this->io->writeError('Writing '.$this->root . $file.' into cache', true, IOInterface::DEBUG);
|
||||
|
@ -128,7 +147,7 @@ class Cache
|
|||
*/
|
||||
public function copyFrom($file, $source)
|
||||
{
|
||||
if ($this->enabled) {
|
||||
if ($this->enabled && !$this->readOnly) {
|
||||
$file = preg_replace('{[^'.$this->allowlist.']}i', '-', $file);
|
||||
$this->filesystem->ensureDirectoryExists(dirname($this->root . $file));
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ EOT
|
|||
continue;
|
||||
}
|
||||
$cache = new Cache($io, $cachePath);
|
||||
$cache->setReadOnly($config->get('cache-read-only'));
|
||||
if (!$cache->isEnabled()) {
|
||||
$io->writeError("<info>Cache is not enabled ($key): $cachePath</info>");
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ class Config
|
|||
'cache-ttl' => 15552000, // 6 months
|
||||
'cache-files-ttl' => null, // fallback to cache-ttl
|
||||
'cache-files-maxsize' => '300MiB',
|
||||
'cache-read-only' => false,
|
||||
'bin-compat' => 'auto',
|
||||
'discard-changes' => false,
|
||||
'autoloader-suffix' => null,
|
||||
|
@ -236,6 +237,7 @@ class Config
|
|||
return (($flags & self::RELATIVE_PATHS) == self::RELATIVE_PATHS) ? $val : $this->realpath($val);
|
||||
|
||||
// booleans with env var support
|
||||
case 'cache-read-only':
|
||||
case 'htaccess-protect':
|
||||
// convert foo-bar to COMPOSER_FOO_BAR and check if it exists since it overrides the local config
|
||||
$env = 'COMPOSER_' . strtoupper(strtr($key, '-', '_'));
|
||||
|
|
|
@ -187,7 +187,7 @@ class FileDownloader implements DownloaderInterface, ChangeReportInterface
|
|||
$url = reset($urls);
|
||||
$cacheKey = $url['cacheKey'];
|
||||
|
||||
if ($cache) {
|
||||
if ($cache && !$cache->isReadOnly()) {
|
||||
$self->lastCacheWrites[$package->getName()] = $cacheKey;
|
||||
$cache->copyFrom($cacheKey, $fileName);
|
||||
}
|
||||
|
|
|
@ -477,6 +477,7 @@ class Factory
|
|||
$cache = null;
|
||||
if ($config->get('cache-files-ttl') > 0) {
|
||||
$cache = new Cache($io, $config->get('cache-files-dir'), 'a-z0-9_./');
|
||||
$cache->setReadOnly($config->get('cache-read-only'));
|
||||
}
|
||||
|
||||
$fs = new Filesystem($process);
|
||||
|
|
|
@ -130,6 +130,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
$this->baseUrl = rtrim(preg_replace('{(?:/[^/\\\\]+\.json)?(?:[?#].*)?$}', '', $this->url), '/');
|
||||
$this->io = $io;
|
||||
$this->cache = new Cache($io, $config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->url), 'a-z0-9.$~');
|
||||
$this->cache->setReadOnly($config->get('cache-read-only'));
|
||||
$this->versionParser = new VersionParser();
|
||||
$this->loader = new ArrayLoader($this->versionParser);
|
||||
$this->httpDownloader = $httpDownloader;
|
||||
|
@ -1071,7 +1072,7 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
$data = $response->decodeJson();
|
||||
HttpDownloader::outputWarnings($this->io, $this->url, $data);
|
||||
|
||||
if ($cacheKey) {
|
||||
if ($cacheKey && !$this->cache->isReadOnly()) {
|
||||
if ($storeLastModifiedTime) {
|
||||
$lastModifiedDate = $response->getHeader('last-modified');
|
||||
if ($lastModifiedDate) {
|
||||
|
@ -1155,7 +1156,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
$data['last-modified'] = $lastModifiedDate;
|
||||
$json = json_encode($data);
|
||||
}
|
||||
$this->cache->write($cacheKey, $json);
|
||||
if (!$this->cache->isReadOnly()) {
|
||||
$this->cache->write($cacheKey, $json);
|
||||
}
|
||||
|
||||
return $data;
|
||||
} catch (\Exception $e) {
|
||||
|
@ -1238,7 +1241,9 @@ class ComposerRepository extends ArrayRepository implements ConfigurableReposito
|
|||
$data['last-modified'] = $lastModifiedDate;
|
||||
$json = JsonFile::encode($data, JsonFile::JSON_UNESCAPED_SLASHES | JsonFile::JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
$cache->write($cacheKey, $json);
|
||||
if (!$cache->isReadOnly()) {
|
||||
$cache->write($cacheKey, $json);
|
||||
}
|
||||
$repo->freshMetadataUrls[$filename] = true;
|
||||
|
||||
return $data;
|
||||
|
|
|
@ -60,6 +60,7 @@ abstract class BitbucketDriver extends VcsDriver
|
|||
$this->repository,
|
||||
))
|
||||
);
|
||||
$this->cache->setReadOnly($this->config->get('cache-read-only'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -75,6 +75,7 @@ class GitDriver extends VcsDriver
|
|||
$this->getBranches();
|
||||
|
||||
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $cacheUrl));
|
||||
$this->cache->setReadOnly($this->config->get('cache-read-only'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,6 +58,7 @@ class GitHubDriver extends VcsDriver
|
|||
$this->originUrl = 'github.com';
|
||||
}
|
||||
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->owner.'/'.$this->repository);
|
||||
$this->cache->setReadOnly($this->config->get('cache-read-only'));
|
||||
|
||||
if ( $this->config->get('use-github-api') === false || (isset($this->repoConfig['no-api']) && $this->repoConfig['no-api'] ) ){
|
||||
$this->setupGitDriver($this->url);
|
||||
|
|
|
@ -105,6 +105,7 @@ class GitLabDriver extends VcsDriver
|
|||
$this->repository = preg_replace('#(\.git)$#', '', $match['repo']);
|
||||
|
||||
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.$this->originUrl.'/'.$this->namespace.'/'.$this->repository);
|
||||
$this->cache->setReadOnly($this->config->get('cache-read-only'));
|
||||
|
||||
$this->fetchProject();
|
||||
}
|
||||
|
|
|
@ -78,6 +78,7 @@ class SvnDriver extends VcsDriver
|
|||
}
|
||||
|
||||
$this->cache = new Cache($this->io, $this->config->get('cache-repo-dir').'/'.preg_replace('{[^a-z0-9.]}i', '-', $this->baseUrl));
|
||||
$this->cache->setReadOnly($this->config->get('cache-read-only'));
|
||||
|
||||
$this->getBranches();
|
||||
$this->getTags();
|
||||
|
|
Loading…
Reference in New Issue