<commit_before><?php

/*
 * This file is part of Composer.
 *
 * (c) <NAME> <<EMAIL>>
 *     <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Repository;

use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Package\Version\VersionParser;
use Composer\DependencyResolver\Pool;
use Composer\Json\JsonFile;
use Composer\Cache;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\RemoteFilesystem;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PreFileDownloadEvent;
use Composer\EventDispatcher\EventDispatcher;

/**
 * @author <NAME> <<EMAIL>>
 */
class ComposerRepository extends ArrayRepository
{
    protected $config;
    protected $options;
    protected $url;
    protected $baseUrl;
    protected $io;
    protected $rfs;
    protected $cache;
    protected $notifyUrl;
    protected $searchUrl;
    protected $hasProviders = false;
    protected $providersUrl;
    protected $loadedMap = array();
    protected $lazyProvidersUrl;
    protected $providerListing;
    protected $loader;
    protected $rootAliases;
    protected $allowSslDowngrade = false;
    protected $eventDispatcher;
    protected $sourceMirrors;
    protected $distMirrors;
    private $degradedMode = false;
    private $rootData;

    public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
    {
        if (!preg_match('{^[\w.]+\??://}', $repoConfig['url'])) {
            // assume http as the default protocol
            $repoConfig['url'] = 'http://'.$repoConfig['url'];
        }
        $repoConfig['url'] = rtrim($repoConfig['url'], '/');

        if ('https?' === substr($repoConfig['url'], 0, 6)) {
            $repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
        }

        $urlBits = parse_url($repoConfig['url']);
        if ($urlBits === false || empty($urlBits['scheme'])) {
            throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
        }

        if (!isset($repoConfig['options'])) {
            $repoConfig['options'] = array();
        }
        if (isset($repoConfig['allow_ssl_downgrade']) && true === $repoConfig['allow_ssl_downgrade']) {
            $this->allowSslDowngrade = true;
        }

        $this->config = $config;
        $this->options = $repoConfig['options'];
        $this->url = $repoConfig['url'];
        $this->baseUrl = rtrim(preg_replace('{^(.*)(?:/[^/\\]+.json)?(?:[?#].*)?$}', '$1', $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->loader = new ArrayLoader();
        $this->rfs = new RemoteFilesystem($this->io, $this->config, $this->options);
        $this->eventDispatcher = $eventDispatcher;
    }

    public function setRootAliases(array $rootAliases)
    {
        $this->rootAliases = $rootAliases;
    }

    public function getRootAliases()
    {
        return $this->rootAliases;
    }

    public function loadRecursively(array $packageNames, $acceptableCallback)
    {
        $workQueue = new \SplQueue;

        foreach ($packageNames as $packageName) {
            $workQueue->enqueue($packageName);
        }

        $loadedPackages = array();

        while (!$workQueue->isEmpty()) {
            $packageName = $workQueue->dequeue();
            if (isset($this->loadedMap[$packageName])) {
                continue;
            }

            $this->loadedMap[$packageName] = true;

            $packages = $this->loadName($packageName, $acceptableCallback);

            foreach ($packages as $package) {
                $loadedPackages[] = $package;
                $requires = $package->getRequires();
                foreach ($requires as $link) {
                    $workQueue->enqueue($link->getTarget());
                }
            }
        }

        return $loadedPackages;
    }

    protected function loadName($name, $acceptableCallback, $exactMatch = true)
    {
        // skip platform packages
        if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) {
            return array();
        }

        if (null === $this->providerListing) {
            $this->loadProviderListings($this->loadRootServerFile());
        }

        if ($this->lazyProvidersUrl && !isset($this->providerListing[$name])) {
            $hash = null;
            $url = str_replace('%package%', $name, $this->lazyProvidersUrl);
            $cacheKey = false;
        } elseif ($this->providersUrl) {
            // package does not exist in this repo
            if (!isset($this->providerListing[$name])) {
                return array();
            }

            $hash = $this->providerListing[$name]['sha256'];
            $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl);
            $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
        } else {
            // BC handling for old providers-includes
            $url = 'p/'.$name.'.json';

            // package does not exist in this repo
            if (!isset($this->providerListing[$url])) {
                return array();
            }
            $hash = $this->providerListing[$url]['sha256'];
            $cacheKey = null;
        }

        if ($cacheKey && $this->cache->sha256($cacheKey) === $hash) {
            $packages = json_decode($this->cache->read($cacheKey), true);
        } else {
            $packages = $this->fetchFile($url, $cacheKey, $hash);
        }

        $loadedPackages = array();
        foreach ($packages['packages'] as $versions) {
            foreach ($versions as $version) {
                if ($exactMatch && $version['name'] !== $name) {
                    continue;
                }

                if ($acceptableCallback && !call_user_func(
                    $acceptableCallback, strtolower($version['name']), VersionParser::parseStability($version['version'])
                )) {
                    continue;
                }

                // load acceptable packages in the providers
                $package = $this->createPackage($version, 'Composer\Package\Package');
                $this->addPackage($package);

                $loadedPackages[] = $package;

                if ($package instanceof AliasPackage) {
                    $loadedPackages[] = $package->getAliasOf();
                }
            }
        }

        return $loadedPackages;
    }

    /**
     * {@inheritDoc}
     */
    public function findPackage($name, $version)
    {
        if (!$this->hasProviders()) {
            return parent::findPackage($name, $version);
        }
        // normalize version & name
        $versionParser = new VersionParser();
        $version = $versionParser->normalize($version);
        $name = strtolower($name);

        foreach ($this->getProviderNames() as $providerName) {
            if ($name === $providerName) {
                $packages = $this->loadName($providerName, null, false);
                foreach ($packages as $package) {
                    if ($name == $package->getName() && $version === $package->getVersion()) {
                        return $package;
                    }
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function findPackages($name, $version = null)
    {
        if (!$this->hasProviders()) {
            return parent::findPackages($name, $version);
        }
        // normalize name
        $name = strtolower($name);

        // normalize version
        if (null !== $version) {
            $versionParser = new VersionParser();
            $version = $versionParser->normalize($version);
        }

        $packages = array();

        foreach ($this->getProviderNames() as $providerName) {
            if ($name === $providerName) {
                $packages = $this->loadName($providerName, null, false);
                foreach ($packages as $package) {
                    if ($name == $package->getName() && (null === $version || $version === $package->getVersion())) {
                        $packages[] = $package;
                    }
                }
            }
        }

        return $packages;
    }

    public function getPackages()
    {
        if ($this->hasProviders()) {
            throw new \LogicException('Composer repositories that have providers can not load the complete list of packages, use getProviderNames instead.');
        }

        return parent::getPackages();
    }

    /**
     * {@inheritDoc}
     */
    public function search($query, $mode = 0)
    {
        $this->loadRootServerFile();

        if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) {
            $url = str_replace('%query%', $query, $this->searchUrl);

            $hostname = parse_url($url, PHP_URL_HOST) ?: $url;
            $json = $this->rfs->getContents($hostname, $url, false);
            $results = JsonFile::parseJson($json, $url);

            return $results['results'];
        }

        if ($this->hasProviders()) {
            $results = array();
            $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';

            foreach ($this->getProviderNames() as $name) {
                if (preg_match($regex, $name)) {
                    $results[] = array('name' => $name);
                }
            }

            return $results;
        }

        return parent::search($query, $mode);
    }

    public function getProviderNames()
    {
        $this->loadRootServerFile();

        if (null === $this->providerListing) {
            $this->loadProviderListings($this->loadRootServerFile());
        }

        if ($this->lazyProvidersUrl) {
            // Can not determine list of provided packages for lazy repositories
            return array();
        }

        if ($this->providersUrl) {
            return array_keys($this->providerListing);
        }

        // BC handling for old providers-includes
        $providers = array();
        foreach (array_keys($this->providerListing) as $provider) {
            $providers[] = substr($provider, 2, -5);
        }

        return $providers;
    }

    protected function configurePackageTransportOptions(PackageInterface $package)
    {
        foreach ($package->getDistUrls() as $url) {
            if (strpos($url, $this->baseUrl) === 0) {
                $package->setTransportOptions($this->options);

                return;
            }
        }
    }

    public function hasProviders()
    {
        $this->loadRootServerFile();

        return $this->hasProviders;
    }

    /**
     * {@inheritDoc}<commit_msg>Add proper docblocks in composer repo<commit_after><?php

/*
 * This file is part of Composer.
 *
 * (c) <NAME> <<EMAIL>>
 *     <NAME> <<EMAIL>>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Composer\Repository;

use Composer\Package\Loader\ArrayLoader;
use Composer\Package\Package;
use Composer\Package\PackageInterface;
use Composer\Package\AliasPackage;
use Composer\Package\Version\VersionParser;
use Composer\DependencyResolver\Pool;
use Composer\Json\JsonFile;
use Composer\Cache;
use Composer\Config;
use Composer\IO\IOInterface;
use Composer\Util\RemoteFilesystem;
use Composer\Plugin\PluginEvents;
use Composer\Plugin\PreFileDownloadEvent;
use Composer\EventDispatcher\EventDispatcher;

/**
 * @author <NAME> <<EMAIL>>
 */
class ComposerRepository extends ArrayRepository
{
    protected $config;
    protected $options;
    protected $url;
    protected $baseUrl;
    protected $io;
    protected $rfs;
    protected $cache;
    protected $notifyUrl;
    protected $searchUrl;
    protected $hasProviders = false;
    protected $providersUrl;
    protected $loadedMap = array();
    protected $lazyProvidersUrl;
    protected $providerListing;
    protected $loader;
    protected $rootAliases;
    protected $allowSslDowngrade = false;
    protected $eventDispatcher;
    protected $sourceMirrors;
    protected $distMirrors;
    private $degradedMode = false;
    private $rootData;

    public function __construct(array $repoConfig, IOInterface $io, Config $config, EventDispatcher $eventDispatcher = null)
    {
        if (!preg_match('{^[\w.]+\??://}', $repoConfig['url'])) {
            // assume http as the default protocol
            $repoConfig['url'] = 'http://'.$repoConfig['url'];
        }
        $repoConfig['url'] = rtrim($repoConfig['url'], '/');

        if ('https?' === substr($repoConfig['url'], 0, 6)) {
            $repoConfig['url'] = (extension_loaded('openssl') ? 'https' : 'http') . substr($repoConfig['url'], 6);
        }

        $urlBits = parse_url($repoConfig['url']);
        if ($urlBits === false || empty($urlBits['scheme'])) {
            throw new \UnexpectedValueException('Invalid url given for Composer repository: '.$repoConfig['url']);
        }

        if (!isset($repoConfig['options'])) {
            $repoConfig['options'] = array();
        }
        if (isset($repoConfig['allow_ssl_downgrade']) && true === $repoConfig['allow_ssl_downgrade']) {
            $this->allowSslDowngrade = true;
        }

        $this->config = $config;
        $this->options = $repoConfig['options'];
        $this->url = $repoConfig['url'];
        $this->baseUrl = rtrim(preg_replace('{^(.*)(?:/[^/\\]+.json)?(?:[?#].*)?$}', '$1', $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->loader = new ArrayLoader();
        $this->rfs = new RemoteFilesystem($this->io, $this->config, $this->options);
        $this->eventDispatcher = $eventDispatcher;
    }

    public function setRootAliases(array $rootAliases)
    {
        $this->rootAliases = $rootAliases;
    }

    public function getRootAliases()
    {
        return $this->rootAliases;
    }

    public function loadRecursively(array $packageNames, $acceptableCallback)
    {
        $workQueue = new \SplQueue;

        foreach ($packageNames as $packageName) {
            $workQueue->enqueue($packageName);
        }

        $loadedPackages = array();

        while (!$workQueue->isEmpty()) {
            $packageName = $workQueue->dequeue();
            if (isset($this->loadedMap[$packageName])) {
                continue;
            }

            $this->loadedMap[$packageName] = true;

            $packages = $this->loadName($packageName, $acceptableCallback);

            foreach ($packages as $package) {
                $loadedPackages[] = $package;
                $requires = $package->getRequires();
                foreach ($requires as $link) {
                    $workQueue->enqueue($link->getTarget());
                }
            }
        }

        return $loadedPackages;
    }

    /**
     * {@inheritDoc}
     */
    public function findPackage($name, $version)
    {
        if (!$this->hasProviders()) {
            return parent::findPackage($name, $version);
        }
        // normalize version & name
        $versionParser = new VersionParser();
        $version = $versionParser->normalize($version);
        $name = strtolower($name);

        foreach ($this->getProviderNames() as $providerName) {
            if ($name === $providerName) {
                $packages = $this->loadName($providerName, null, false);
                foreach ($packages as $package) {
                    if ($name == $package->getName() && $version === $package->getVersion()) {
                        return $package;
                    }
                }
            }
        }
    }

    /**
     * {@inheritDoc}
     */
    public function findPackages($name, $version = null)
    {
        if (!$this->hasProviders()) {
            return parent::findPackages($name, $version);
        }
        // normalize name
        $name = strtolower($name);

        // normalize version
        if (null !== $version) {
            $versionParser = new VersionParser();
            $version = $versionParser->normalize($version);
        }

        $packages = array();

        foreach ($this->getProviderNames() as $providerName) {
            if ($name === $providerName) {
                $packages = $this->loadName($providerName, null, false);
                foreach ($packages as $package) {
                    if ($name == $package->getName() && (null === $version || $version === $package->getVersion())) {
                        $packages[] = $package;
                    }
                }
            }
        }

        return $packages;
    }

    public function getPackages()
    {
        if ($this->hasProviders()) {
            throw new \LogicException('Composer repositories that have providers can not load the complete list of packages, use getProviderNames instead.');
        }

        return parent::getPackages();
    }

    /**
     * {@inheritDoc}
     */
    public function search($query, $mode = 0)
    {
        $this->loadRootServerFile();

        if ($this->searchUrl && $mode === self::SEARCH_FULLTEXT) {
            $url = str_replace('%query%', $query, $this->searchUrl);

            $hostname = parse_url($url, PHP_URL_HOST) ?: $url;
            $json = $this->rfs->getContents($hostname, $url, false);
            $results = JsonFile::parseJson($json, $url);

            return $results['results'];
        }

        if ($this->hasProviders()) {
            $results = array();
            $regex = '{(?:'.implode('|', preg_split('{\s+}', $query)).')}i';

            foreach ($this->getProviderNames() as $name) {
                if (preg_match($regex, $name)) {
                    $results[] = array('name' => $name);
                }
            }

            return $results;
        }

        return parent::search($query, $mode);
    }

    public function getProviderNames()
    {
        $this->loadRootServerFile();

        if (null === $this->providerListing) {
            $this->loadProviderListings($this->loadRootServerFile());
        }

        if ($this->lazyProvidersUrl) {
            // Can not determine list of provided packages for lazy repositories
            return array();
        }

        if ($this->providersUrl) {
            return array_keys($this->providerListing);
        }

        // BC handling for old providers-includes
        $providers = array();
        foreach (array_keys($this->providerListing) as $provider) {
            $providers[] = substr($provider, 2, -5);
        }

        return $providers;
    }

    /**
     * Loads package data for a given package name or provider name
     *
     * @param string $name
     * @param callable $acceptableCallback A callback to check if a package should be loaded
     * @param bool $exactMatch Whether packages only providing the name should be ignored
     *
     * @return array All packages that were loaded
     */
    protected function loadName($name, $acceptableCallback, $exactMatch = true)
    {
        // skip platform packages
        if (preg_match(PlatformRepository::PLATFORM_PACKAGE_REGEX, $name) || '__root__' === $name) {
            return array();
        }

        if (null === $this->providerListing) {
            $this->loadProviderListings($this->loadRootServerFile());
        }

        if ($this->lazyProvidersUrl && !isset($this->providerListing[$name])) {
            $hash = null;
            $url = str_replace('%package%', $name, $this->lazyProvidersUrl);
            $cacheKey = false;
        } elseif ($this->providersUrl) {
            // package does not exist in this repo
            if (!isset($this->providerListing[$name])) {
                return array();
            }

            $hash = $this->providerListing[$name]['sha256'];
            $url = str_replace(array('%package%', '%hash%'), array($name, $hash), $this->providersUrl);
            $cacheKey = 'provider-'.strtr($name, '/', '$').'.json';
        } else {
            // BC handling for old providers-includes
            $url = 'p/'.$name.'.json';

            // package does not exist in this repo
            if (!isset($this->providerListing[$url])) {
                return array();
            }
            $hash = $this->providerListing[$url]['sha256'];
            $cacheKey = null;
        }

        if ($cacheKey && $this->cache->sha256($cacheKey) === $hash) {
            $packages = json_decode($this->cache->read($cacheKey), true);
        } else {
            $packages = $this->fetchFile($url, $cacheKey, $hash);
        }

        $loadedPackages = array();
        foreach ($packages['packages'] as $versions) {
            foreach ($versions as $version) {
                if ($exactMatch && $version['name'] !== $name) {
                    continue;
                }

                if ($acceptableCallback && !call_user_func(
                    $acceptableCallback, strtolower($version['name']), VersionParser::parseStability($version['version'])
                )) {
                    continue;
                }

                // load acceptable packages in the providers
                $package = $this->createPackage($version, 'Composer\Package\Package');
                $this->addPackage($package);

                $loadedPackages[] = $package;

                if ($package instanceof AliasPackage) {
                    $loadedPackages[] = $package->getAliasOf();
                }
            }
        }

        return $loadedPackages;
    }


    protected function configurePackageTransportOptions(PackageInterface $package)
    {
        foreach ($package->getDistUrls() as $url) {
            if (strpos($url, $this->baseUrl) === 0) {
                $package->setTransportOptions($this->options);

                return;
            }
        }
    }

    public function hasProviders()
    {
        $this->loadRootServerFile();

        return $this->hasProviders;
    }

    /**
     * {@inheritDoc}
{'fraction_non_alphanumeric': 0.1498259394804963, 'fraction_numerical': 0.0018744979023475855, 'mean_word_length': 2.072819528250137, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 185, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3009567', 'n_tokens_mistral': 6224, 'n_tokens_neox': 5967, 'n_words': 1298}