コード例 #1
0
ファイル: ZipRepository.php プロジェクト: balbuf/composer-wp
 /**
  * Scan the directory set in $repoConfig['url']
  * and create any found packages.
  */
 protected function scanDir()
 {
     $dir = $this->repoConfig['url'];
     // make sure tilde is not escaped so it can be expanded
     // this allows '~/' followed by a path or just '~'
     if (($tilde = substr($dir, 0, 2)) === '~/' || $tilde === '~') {
         $dir = $tilde . ProcessExecutor::escape(substr($dir, strlen($tilde)));
     } else {
         $dir = ProcessExecutor::escape($dir);
     }
     // patterns specific to both plugins and themes
     // 'inflating' is a line printed by unzip which indicates which internal file we are looking at
     $patterns = ['inflating|Version|Description|Author|Author URI|License'];
     // files within the archives to look at
     $files = [];
     // look for plugins?
     if (isset($this->repoConfig['package-types']['wordpress-plugin']) || isset($this->repoConfig['package-types']['wordpress-muplugin'])) {
         $patterns[] = 'Plugin Name|Plugin URI';
         $files[] = "'*.php'";
     }
     // look for themes?
     if (isset($this->repoConfig['package-types']['wordpress-theme'])) {
         $patterns[] = 'Theme Name|Theme URI';
         $files[] = "'style.css'";
     }
     // determine if we have a depth limit
     $maxdepth = ($depth = (int) $this->repoConfig['max-depth']) > 0 ? "-maxdepth {$depth}" : '';
     // assemble the command
     // 1. `find` to get all zip files in the given directory
     // 2. echo the filename so we can capture where the zip is
     // 3. use `unzip` piped into `grep` to scan the zip for WP
     //    theme or plugin headers in style.css or *.php files,
     //    respectively, but only in the top two directories within the zip
     $cmd = "find -L {$dir} {$maxdepth} -iname '*.zip' -exec echo '{}' ';' -exec sh -c " . "\"unzip -c {} '*.php' -x '*/*/*' | grep -iE '^[ ^I*]*(" . implode('|', $patterns) . ")'\" ';'";
     // if this is using ssh, wrap the command in an ssh call instead
     if ($this->ssh) {
         $cmd = 'ssh ' . ProcessExecutor::escape($this->repoConfig['ssh']) . ' ' . ProcessExecutor::escape($cmd);
     }
     $process = new ProcessExecutor($this->io);
     // execute the command and see if the response code indicates success
     // @todo: do we need to catch any exceptions here?
     if (($code = $process->execute($cmd, $output)) === 0) {
         // store details about each of the files, which may be used to create a package
         $files = [];
         $zipFile = null;
         $fileName = null;
         // parse the response line-by-line to pluck out the header information
         foreach ($process->splitLines($output) as $line) {
             // is this a new zip file?
             if (strtolower(substr($line, -4)) === '.zip') {
                 $zipFile = $line;
                 // is this a new internal file?
             } else {
                 if (preg_match('/^\\s*inflating:\\s*(.+?)\\s*$/i', $line, $matches)) {
                     $fileName = $matches[1];
                 } else {
                     // parse the line for information
                     if (preg_match('/^[\\s*]*([^:]+):\\s*(.+?)\\s*$/i', $line, $matches)) {
                         // for clarity
                         list(, $property, $value) = $matches;
                         $files[$zipFile][$fileName][$property] = $value;
                     }
                 }
             }
         }
         // take the header information and create packages!
         foreach ($files as $url => $packages) {
             // we will only consider zips that have one package inside
             if (count($packages) === 1) {
                 // make sure all the keys are consistent
                 $headers = array_change_key_case(reset($packages), CASE_LOWER);
                 // file within the zip where the headers were found
                 $fileName = key($packages);
                 // the info used to create the package
                 $package = [];
                 // we have a theme!
                 if (!empty($headers['theme name'])) {
                     $package['type'] = 'wordpress-theme';
                     $name = Util::slugify($headers['theme name']);
                     $name = Util::callFilter($this->repoConfig['name-filter'], $name, $url, $fileName, $headers);
                     if (!empty($headers['theme uri'])) {
                         $package['homepage'] = $headers['theme uri'];
                     }
                     // we have a plugin!
                 } else {
                     if (!empty($headers['plugin name'])) {
                         $package['type'] = 'wordpress-plugin';
                         // use the basename of the file where the plugin headers were as the name
                         // this is a wordpress convention, but may not always be accurate
                         // @todo: what do we do about that?
                         $name = Util::slugify($headers['plugin name']);
                         $name = Util::callFilter($this->repoConfig['name-filter'], $name, $url, $fileName, $headers);
                         if (!empty($headers['plugin uri'])) {
                             $package['homepage'] = $headers['plugin uri'];
                         }
                         // does not appear to be a theme or plugin
                         // sometimes other files get picked up
                     } else {
                         if ($this->io->isVerbose()) {
                             $this->io->writeError("{$url} does not appear to contain a valid package");
                         }
                         continue;
                     }
                 }
                 // if the name is empty we don't use it
                 if (!strlen($name)) {
                     continue;
                 }
                 // add version
                 if (!empty($headers['version'])) {
                     $package['version'] = Util::fixVersion($headers['version'], 'dev-default');
                 } else {
                     $package['version'] = 'dev-default';
                 }
                 $package['version'] = Util::callFilter($this->repoConfig['version-filter'], $package['version'], $name, $url, $fileName, $headers);
                 // empty version means we don't use it
                 if (!strlen($package['version'])) {
                     continue;
                 }
                 // add author information
                 if (!empty($headers['author'])) {
                     $package['authors'][0]['name'] = $headers['author'];
                     if (!empty($headers['author uri'])) {
                         $package['authors'][0]['homepage'] = $headers['author uri'];
                     }
                 }
                 // add description
                 if (!empty($headers['description'])) {
                     $package['description'] = strip_tags($headers['description']);
                 }
                 // add license
                 if (!empty($headers['license'])) {
                     $package['license'] = $headers['license'];
                 }
                 // add dist information
                 $package['dist'] = ['url' => $this->ssh ? "ssh://{$this->repoConfig['ssh']}:{$url}" : $url, 'type' => 'zip'];
                 // add a new package for each vendor alias of the given type
                 // @todo: maybe use links instead? or in addition to?
                 foreach ($this->repoConfig['vendors'] as $vendor => $type) {
                     // match wordpress-plugin for wordpress-muplugin vendors
                     if ($type === $package['type'] || $type === 'wordpress-muplugin' && $package['type'] === 'wordpress-plugin') {
                         // this makes sure muplugins are the correct type
                         $package['type'] = $type;
                         $package['name'] = "{$vendor}/{$name}";
                         $packageObj = $this->loader->load($package);
                         Util::callFilter($this->repoConfig['package-filter'], $packageObj, $url, $fileName, $headers);
                         $this->addPackage($packageObj);
                     }
                 }
             } else {
                 // if the zip contains multiple packages, we can't use it @todo - maybe make it possible?
                 if ($this->io->isVerbose()) {
                     $this->io->writeError("Cannot use file {$url} as is appears to contain multiple packages.");
                 }
             }
         }
     } else {
         // some sort of error - boo!
         throw new \RuntimeException('Could not complete directory scan of ' . $this->repoConfig['url'] . '. ' . $process->getErrorOutput());
     }
 }
コード例 #2
0
ファイル: SVNRepository.php プロジェクト: balbuf/composer-wp
 public function whatProvides(Pool $pool, $name, $bypassFilters = false)
 {
     // split on vendor and name
     if (count($parts = explode('/', $name)) !== 2) {
         return [];
     }
     list($vendor, $shortName) = $parts;
     // does the vendor match one of our virtual vendors?
     if (!isset($this->vendors[$vendor])) {
         return [];
     }
     // do we already have its packages?
     if (isset($this->providers[$name])) {
         return $this->providers[$name];
     }
     // make sure the providers have been loaded
     $this->loadProviders();
     // does the shortname even exist in this repo?
     if (!isset($this->providerHash[$shortName])) {
         return [];
     }
     // base url for the requested set of packages (i.e. the provider)
     // there should be no trailing slash
     $providerUrl = $this->providerHash[$shortName];
     $packages = [];
     // get a listing of available packages
     // these are paths under the provider url where we should find actual packages
     foreach ((array) $this->repoConfig->get('package-paths') as $path) {
         // the relative path without surrounding slashes
         $relPath = trim($path, '/');
         // if the path ends with a slash, we grab its subdirectories
         if (substr($path, -1) === '/') {
             // try to fetch the packages!
             try {
                 if ($this->io->isVerbose()) {
                     $this->io->writeError("Fetching available versions for {$name}");
                 }
                 $pkgRaw = $this->svnUtil->execute('ls', "{$providerUrl}/{$relPath}");
             } catch (\RuntimeException $e) {
                 // @todo maybe don't throw an exception and just pass this one up?
                 throw new \RuntimeException("SVN Error: Could not retrieve package listing for {$name}. " . $e->getMessage());
             }
             // check the versions and add any good ones to the set
             foreach (SvnUtil::parseSvnList($pkgRaw) as $version) {
                 // format the version identifier to be composer-compatible
                 $version = Util::fixVersion($version, 'dev-default');
                 $version = Util::callFilter($this->repoConfig->get('version-filter'), $version, $name, $path, $providerUrl);
                 // if the version string is empty, we don't take it
                 if (!empty($version)) {
                     $packages[$version] = trim("{$relPath}/{$version}", '/');
                 }
             }
         } else {
             // otherwise we add as-is (no checking is performed to see if this reference really exists)
             // @todo: perhaps add an optional check?
             $version = Util::fixVersion(basename($path), 'dev-default');
             $version = Util::callFilter($this->repoConfig->get('version-filter'), $version, $name, $path, $providerUrl);
             // if the version string is empty, we don't take it
             if (!empty($version)) {
                 $packages[$version] = $relPath;
             }
         }
     }
     // store the providers based on its full name (i.e. with vendor)
     // this allows the same package to be loaded as different types,
     // which allows the package type to be changed in composer.json,
     // i.e. the type that is being removed AND the type that is being installed
     // both have to exist during the solving
     $this->providers[$name] = [];
     // create a package for each tag
     foreach ($packages as $version => $reference) {
         if (!$pool->isPackageAcceptable($shortName, VersionParser::parseStability($version))) {
             continue;
         }
         // first, setup the repo-determined package properties
         $data = ['name' => $name, 'version' => $version, 'type' => $this->vendors[$vendor], 'source' => ['type' => 'svn', 'url' => "{$providerUrl}/", 'reference' => $reference ?: '/']];
         // next, fill in any defaults that were missing
         if (($defaults = $this->repoConfig->get('package-defaults')) && is_array($defaults)) {
             $data = array_merge($defaults, $data);
         }
         // finally, apply any overrides
         if (($overrides = $this->repoConfig->get('package-overrides')) && is_array($overrides)) {
             $data = array_replace($data, $overrides);
         }
         // create the package object
         $package = $this->createPackage($data, 'Composer\\Package\\CompletePackage');
         $package->setRepository($this);
         // add "replaces" array for any other vendors that this repository supports
         if (count($this->vendors) > 1) {
             $replaces = [];
             $constraint = new Constraint('=', $package->getVersion());
             foreach ($this->vendors as $vendorName => $type) {
                 // it doesn't replace itself
                 if ($vendorName === $vendor) {
                     continue;
                 }
                 $replaces[] = new Link($package->getName(), "{$vendorName}/{$shortName}", $constraint, "'{$type}' alias for", $package->getPrettyVersion());
             }
             $package->setReplaces($replaces);
         }
         // apply a filter to the package object
         Util::callFilter($this->repoConfig->get('package-filter'), $package);
         // add the package object to the set
         $this->providers[$name][$version] = $package;
         // handle root aliases
         // @todo: not sure if this is correct (this was copped from the parent class)
         if (isset($this->rootAliases[$package->getName()][$package->getVersion()])) {
             $rootAliasData = $this->rootAliases[$package->getName()][$package->getVersion()];
             $alias = $this->createAliasPackage($package, $rootAliasData['alias_normalized'], $rootAliasData['alias']);
             $alias->setRepository($this);
             $this->providers[$name][$version . '-root'] = $alias;
         }
     }
     return $this->providers[$name];
 }