Skip to content

Unable to retrieve the good alias for PHP_CodeSniffer package by API #458

@llaville

Description

@llaville

Hello @theseer

Perharps you can help me to confirm or not that the Phive API calls are on right sequence !

Hope it will be enough ? Tell me if you need more info !

Current Context

As author of package https://github.com/llaville/captainhook-bin-plugin (a CaptainHook Plugin), before to release officially the first version on Composer, I wanted to add support for PHIVE too !

Actually if a Composer package is not installed the action is skipped by my plugin (auto-detection).
I wanted to have the same feature with PHIVE.

I've tried many solutions, and found a possible good one, but I'm not sure (if I used the good API calls): Could you check the sequence please ?

Source Code is provide at end of report.

Expected behaviour

Package is auto-detected (see my solution at end of this report with source code provided), respect version constraint, and command ./tools/phpcs is run !

Note

PHP_CodeSniffer is well detected and run as expected (I've put a var_dump not well indented that raise the error)

Image

Current behaviour

Without my "patch", the Package is not detected as installed (even if it's TRUE : see phive status), and action is skipped (my plugin goal).

Caution

PHP_CodeSniffer is not detected because the first alias retrieved by \PharIo\Phive\SourcesList::getAliasForComposerAlias is phpcbf (and not phpcs)
See https://github.com/phar-io/phive/blob/0.16.0/src/shared/sources/SourcesList.php#L66 only the first alias as provided

Image

PHIVE installation

I've locally installed the PHP_CodeSniffer as follow :

phive install --target ./tools phpcs@^4.0

The local .phive/phars.xml file contents is :

<?xml version="1.0" encoding="UTF-8"?>
<phive xmlns="https://phar.io/phive">
  <phar name="phpcs" version="^4.0" installed="4.0.1" location="././tools/phpcs" copy="false"/>
</phive>

Important

Here the alias (phpcs) is the one that expected !

Confirmed by phive status command :

Phive 0.16.0 - Copyright (C) 2015-2026 by Arne Blankerts, Sebastian Heuer and Contributors
PHARs configured in project:

Alias/URL    Version Constraint    Installed    Location                                                       Key Ids

phpcs        ^4.0                  4.0.1        /shared/backups/bartlett/captainhook-bin-plugin/tools/phpcs    97B02DD8E5071466

Source Code

Now, after a long introduction (sorry, but I want to be clear as much as possible), the code (PHIVE API calls , I used to auto-detect that the tool is correctly installed).

As for Composer Condition the key to check is the package identifier. For example : squizlabs/php_codesniffer for PHPCS

Tip

My Solution to by-pass the not found alias name candidate :

      if (in_array('phpcbf', $aliases, true)) {
           // "squizlabs/php_codesniffer" is the only Composer package that provide two aliases (for current Phive v0.16)
           // but only the first one is retrieved by \PharIo\Phive\SourcesList::getAliasForComposerAlias
           // @see https://github.com/phar-io/phive/blob/0.16.0/src/shared/sources/SourcesList.php#L66
           $aliases[] = 'phpcs';
       }
Source Code

<?php

declare(strict_types=1);


namespace Bartlett\CaptainHookBinPlugin\Condition;

use CaptainHook\App\Console\IO;
use CaptainHook\App\Hook\Condition;
use Composer\InstalledVersions;
use Composer\Semver\Semver;
use PharIo\Phive\Cli\Request;
use PharIo\Phive\ComposerAlias;
use PharIo\Phive\EnvironmentLocator;
use PharIo\Phive\Factory;
use PharIo\Phive\LocalPhiveXmlConfig;
use PharIo\Phive\PhiveXmlConfigFileLocator;
use PharIo\Phive\StatusCommandConfig;
use PharIo\Phive\XmlFile;
use PharIo\Version\VersionConstraintParser;
use SebastianFeldmann\Git\Repository;
use Throwable;
use function in_array;
use const PHP_OS;

class PharInstalled implements Condition
{
    public function __construct(private string $packageName, private string $constraint = '*')
    {
    }

    public function isTrue(IO $io, Repository $repository): bool
    {
        $isPhiveAvailable = InstalledVersions::isInstalled('phar-io/phive');

        if (!$isPhiveAvailable) {
            $io->write(
                '  <fg=cyan>Applied: PHIVE is not installed</>',
                true,
                IO::VERBOSE,
            );
            return false;
        }

        $request = new Request([]);

        $factory = new Factory($request);

        // \PharIo\Phive\Factory::getEnvironment
        $environment = (new EnvironmentLocator())->getEnvironment(PHP_OS);

        // \PharIo\Phive\Factory::getConfig
        $config = $factory->getConfig();

        // \PharIo\Phive\Factory::getOutput
        $output = $factory->getOutput();

        // \PharIo\Phive\Factory::getPhiveXmlConfigFileLocator
        $xmlConfigFileLocator = new PhiveXmlConfigFileLocator(
            $environment,
            $config,
            $output
        );

        $xmlConfig = new LocalPhiveXmlConfig(
            new XmlFile(
                $xmlConfigFileLocator->getFile(),
                'https://phar.io/phive',
                'phive'
            ),
            new VersionConstraintParser(),
            $environment
        );

        $pharRegistry = $factory->getPharRegistry();

        $statusCommandConfig = new StatusCommandConfig(
            $request->getOptions(),
            $xmlConfig,
            $pharRegistry
        );

        // \PharIo\Phive\Factory::getSourcesList
        $sourcesList = $factory->getRemoteSourcesListFileLoader()->load();

        $isApplied = false;
        $aliases = [];

        try {
            $aliases[] = $sourcesList->getAliasForComposerAlias(new ComposerAlias($this->packageName));

            if (in_array('phpcbf', $aliases, true)) {
                // "squizlabs/php_codesniffer" is the only Composer package that provide two aliases (for current Phive v0.16)
                // but only the first one is retrieved by \PharIo\Phive\SourcesList::getAliasForComposerAlias
                // @see https://github.com/phar-io/phive/blob/0.16.0/src/shared/sources/SourcesList.php#L66
                //$aliases[] = 'phpcs';
            }

            foreach ($statusCommandConfig->getPhars() as $phar) {
                if (!in_array($phar->getName(), $aliases, true)) {
                    continue;
                }
                if (!$phar->isInstalled()) {
                    continue;
                }
                $versionInstalled = $phar->getInstalledVersion();
           \var_dump($versionInstalled->getOriginalString(), $phar->getVersionConstraint()->asString());
                $isApplied = Semver::satisfies($versionInstalled->getOriginalString(), $phar->getVersionConstraint()->asString());
                if ($isApplied) {
                    break;
                }
            }
        } catch (Throwable $exception) {
        }

        $io->write(
            sprintf(
                '  <fg=cyan>Applied: Package %s</> %s (with constraint "%s")',
                $isApplied ? 'installed' : 'not installed',
                $this->packageName,
                $this->constraint
            ),
            true,
            IO::VERBOSE,
        );

        return $isApplied;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions