Skip to content
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

Use composer InstalledRepository to determine install dir #51

Merged
merged 5 commits into from
Apr 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion phpstan.neon.dist
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ parameters:
-
message: '~^Constant RCMAIL_VERSION not found\.$~'
path: 'src/ExtensionInstaller.php'
count: 3
count: 1
97 changes: 53 additions & 44 deletions src/ExtensionInstaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,81 @@
use Composer\Installer\LibraryInstaller;
use Composer\Package\PackageInterface;
use Composer\Package\Version\VersionParser;
use Composer\Repository\InstalledRepository;
use Composer\Repository\InstalledRepositoryInterface;
use Composer\Repository\RootPackageRepository;
use Composer\Util\Filesystem;
use Composer\Util\ProcessExecutor;
use React\Promise\PromiseInterface;

abstract class ExtensionInstaller extends LibraryInstaller
{
/** @var string|null */
private $roundcubemailInstallPath;

/** @var string */
protected $composer_type;

protected function getRoundcubemailInstallPath(): string
protected function setRoundcubemailInstallPath(InstalledRepositoryInterface $installedRepo): void
{
$rootPackage = $this->composer->getPackage();
if ($rootPackage->getName() === 'roundcube/roundcubemail') {
// https://github.com/composer/composer/discussions/11927#discussioncomment-9116893
$rootPackage = clone $this->composer->getPackage();
$installedRepo = new InstalledRepository([
$installedRepo,
new RootPackageRepository($rootPackage),
]);
Comment on lines +26 to +30
Copy link
Contributor Author

@mvorisek mvorisek Apr 20, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI: inspired by https://github.com/composer/composer/blob/2.7.3/src/Composer/Command/CheckPlatformReqsCommand.php#L77 which clones the root package, /wo clone, an exception is thrown


$roundcubemailPackages = $installedRepo->findPackagesWithReplacersAndProviders('roundcube/roundcubemail');
assert(count($roundcubemailPackages) === 1);
$roundcubemailPackage = $roundcubemailPackages[0];

if ($roundcubemailPackage === $rootPackage) { // $this->getInstallPath($package) does not work for root package
$this->initializeVendorDir();

return dirname($this->vendorDir);
$this->roundcubemailInstallPath = dirname($this->vendorDir);
} else {
$this->roundcubemailInstallPath = $this->getInstallPath($roundcubemailPackage);
}
}

$roundcubemailPackage = $this->composer
->getRepositoryManager()
->findPackage('roundcube/roundcubemail', '*');

return $this->getInstallPath($roundcubemailPackage);
protected function getRoundcubemailInstallPath(): string
{
return $this->roundcubemailInstallPath;
}

public function getInstallPath(PackageInterface $package)
{
if (!$this->supports($package->getType())) {
if (
!$this->supports($package->getType())
|| $this->roundcubemailInstallPath === null // install path is not known at download phase
) {
return parent::getInstallPath($package);
}

$vendorDir = $this->getVendorDir();

return sprintf('%s/%s', $vendorDir, $this->getPackageName($package));
return $vendorDir . \DIRECTORY_SEPARATOR
. str_replace('/', \DIRECTORY_SEPARATOR, $this->getPackageName($package));
}

public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
private function initializeRoundcubemailEnvironment(): void
{
// initialize Roundcube environment
if (!defined('INSTALL_PATH')) {
define('INSTALL_PATH', $this->getRoundcubemailInstallPath() . '/');
}
require_once INSTALL_PATH . 'program/include/iniset.php';
}

public function install(InstalledRepositoryInterface $repo, PackageInterface $package)
{
$this->setRoundcubemailInstallPath($repo);
$this->initializeRoundcubemailEnvironment();
$this->rcubeVersionCheck($package);

$postInstall = function () use ($package) {
$config_file = $this->rcubeConfigFile();
$package_name = $this->getPackageName($package);
$package_dir = $this->getVendorDir() . \DIRECTORY_SEPARATOR . $package_name;
$package_dir = $this->getInstallPath($package);
$extra = $package->getExtra();

if (is_writable($config_file) && \PHP_SAPI === 'cli' && $this->confirmInstall($package_name)) {
Expand Down Expand Up @@ -83,12 +108,7 @@ public function install(InstalledRepositoryInterface $repo, PackageInterface $pa
if ($sqldir = realpath($package_dir . \DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) {
$this->io->write("<info>Running database initialization script for {$package_name}</info>");

$roundcube_version = self::versionNormalize(RCMAIL_VERSION);
if (self::versionCompare($roundcube_version, '1.2.0', '>=')) {
\rcmail_utils::db_init($sqldir);
} else {
throw new \Exception('Database initialization failed. Roundcube 1.2.0 or above required.');
}
\rcmail_utils::db_init($sqldir);
}
}

Expand All @@ -113,31 +133,28 @@ public function install(InstalledRepositoryInterface $repo, PackageInterface $pa

public function update(InstalledRepositoryInterface $repo, PackageInterface $initial, PackageInterface $target)
{
// initialize Roundcube environment
if (!defined('INSTALL_PATH')) {
define('INSTALL_PATH', $this->getRoundcubemailInstallPath() . '/');
}
require_once INSTALL_PATH . 'program/include/iniset.php';

$this->setRoundcubemailInstallPath($repo);
$this->initializeRoundcubemailEnvironment();
$this->rcubeVersionCheck($target);

$extra = $target->getExtra();
$fs = new Filesystem();

// backup persistent files e.g. config.inc.php
$package_name = $this->getPackageName($initial);
$package_dir = $this->getVendorDir() . \DIRECTORY_SEPARATOR . $package_name;
$package_dir = $this->getInstallPath($initial);
$temp_dir = $package_dir . '-' . sprintf('%010d%010d', mt_rand(), mt_rand());

// make a backup of existing files (for restoring persistent files)
$fs->copy($package_dir, $temp_dir);

$postUpdate = function () use ($target, $extra, $fs, $temp_dir) {
$package_name = $this->getPackageName($target);
$package_dir = $this->getVendorDir() . \DIRECTORY_SEPARATOR . $package_name;
$package_dir = $this->getInstallPath($target);

// restore persistent files
$persistent_files = !empty($extra['roundcube']['persistent-files']) ? $extra['roundcube']['persistent-files'] : ['config.inc.php'];
$persistent_files = !empty($extra['roundcube']['persistent-files'])
? $extra['roundcube']['persistent-files']
: ['config.inc.php'];
foreach ($persistent_files as $file) {
$path = $temp_dir . \DIRECTORY_SEPARATOR . $file;
if (is_readable($path)) {
Expand All @@ -156,12 +173,7 @@ public function update(InstalledRepositoryInterface $repo, PackageInterface $ini
if ($sqldir = realpath($package_dir . \DIRECTORY_SEPARATOR . $extra['roundcube']['sql-dir'])) {
$this->io->write("<info>Updating database schema for {$package_name}</info>");

$roundcube_version = self::versionNormalize(RCMAIL_VERSION);
if (self::versionCompare($roundcube_version, '1.2.0', '>=')) {
\rcmail_utils::db_update($sqldir, $package_name);
} else {
throw new \Exception('Database update failed. Roundcube 1.2.0 or above required.');
}
\rcmail_utils::db_update($sqldir, $package_name);
}
}

Expand All @@ -186,18 +198,15 @@ public function update(InstalledRepositoryInterface $repo, PackageInterface $ini

public function uninstall(InstalledRepositoryInterface $repo, PackageInterface $package)
{
// initialize Roundcube environment
if (!defined('INSTALL_PATH')) {
define('INSTALL_PATH', $this->getRoundcubemailInstallPath() . '/');
}
require_once INSTALL_PATH . 'program/include/iniset.php';
$this->setRoundcubemailInstallPath($repo);
$this->initializeRoundcubemailEnvironment();

$config = $this->composer->getConfig()->get('roundcube');

$postUninstall = function () use ($package, $config) {
// post-uninstall: deactivate package
$package_name = $this->getPackageName($package);
$package_dir = $this->getVendorDir() . \DIRECTORY_SEPARATOR . $package_name;
$package_dir = $this->getInstallPath($package);

$this->rcubeAlterConfig($package_name, false);

Expand Down Expand Up @@ -380,7 +389,7 @@ private function rcubeRunScript($script, PackageInterface $package)
{
$package_name = $this->getPackageName($package);
$package_type = $package->getType();
$package_dir = $this->getVendorDir() . \DIRECTORY_SEPARATOR . $package_name;
$package_dir = $this->getInstallPath($package);

// check for executable shell script
if (($scriptfile = realpath($package_dir . \DIRECTORY_SEPARATOR . $script)) && is_executable($scriptfile)) {
Expand All @@ -404,7 +413,7 @@ private function rcubeRunScript($script, PackageInterface $package)
}

/**
* normalize Roundcube version string.
* Normalize Roundcube version string.
*/
private static function versionNormalize(string $version): string
{
Expand Down
8 changes: 6 additions & 2 deletions src/PluginInstaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ protected function confirmInstall($package_name)

protected function getConfig($package_name, $config, $add)
{
$cur_config = !empty($config['plugins']) ? ((array) $config['plugins']) : [];
$cur_config = !empty($config['plugins'])
? ((array) $config['plugins'])
: [];
$new_config = $cur_config;

if ($add && !in_array($package_name, $new_config, true)) {
Expand All @@ -36,7 +38,9 @@ protected function getConfig($package_name, $config, $add)
}

if ($new_config !== $cur_config) {
$config_val = count($new_config) > 0 ? "[\n\t'" . implode("',\n\t'", $new_config) . "',\n];" : '[];';
$config_val = count($new_config) > 0
? "[\n\t'" . implode("',\n\t'", $new_config) . "',\n];"
: '[];';
$result = ['plugins', $config_val];
} else {
$result = false;
Expand Down
8 changes: 6 additions & 2 deletions src/SkinInstaller.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ protected function confirmInstall($package_name)

protected function getConfig($package_name, $config, $add)
{
$cur_config = !empty($config['skin']) ? $config['skin'] : null;
$cur_config = !empty($config['skin'])
? $config['skin']
: null;
$new_config = $cur_config;

if ($add && $new_config !== $package_name) {
Expand All @@ -36,7 +38,9 @@ protected function getConfig($package_name, $config, $add)
}

if ($new_config !== $cur_config) {
$config_val = !empty($new_config) ? "'{$new_config}';" : null;
$config_val = !empty($new_config)
? "'{$new_config}';"
: null;
$result = ['skin', $config_val];
} else {
$result = false;
Expand Down