/** * Runs when silly routes the command to us. * ie: ```ppm install``` * * @param IOutput $output * @return void */ public function __invoke(IOutput $output) { // Save the output interface so we can use it later $this->output = $output; // Tell the world we have started installing stuff $this->output->writeLn("Starting Installer"); // Attach to Observables $this->downloader->attach($this); $this->cleaner->attach($this); // Read in the root composer.json file $composer = $this->reader->getComposerObject(); // Loop through all "require" packages, downloading them, recursively. if (isset($composer['require'])) { $this->downloadPackages($composer['require']); } // Loop through all "require-dev" packages, downloading them. // This is done recursively just like the normal require packages but // only these first level packages are downloaded, as to say we do not // download any "require-dev" packages of a "require-dev" package. if (isset($composer['require-dev'])) { $this->downloadPackages($composer['require-dev']); } // Remove anything that shouldn't exist $this->cleaner->clean($this->downloader->getDownloaded()); // Discover any namespace conflicts $conflicts = $this->conflicts->discover($this->downloader->getDownloaded()); // Re-Name conflicting types. $replacements = $this->renamer->renameConflicts($conflicts); // Generate auto loader. $this->autoload->generate($this->downloader->getDownloaded(), $replacements); $autoloader = (require $this->vendorDir . '/autoload.php'); // Create proxies for renamed types. //$this->proxy->generate($replacements, $autoloader); }
/** @inheritdoc */ public function discover($packages) { // This is the array that we will return $this->conflicts = []; // Get a list of packages that have multiple versions, // that "might" have name conflicts. $possibleConflicts = Linq::from($packages)->where(function ($v) { return count($v) > 1; }); foreach ($possibleConflicts as $packageName => $versions) { $psrLoaded = []; $mapLoaded = []; foreach ($versions as $version) { $psrLoaded[$version] = []; $mapLoaded[$version] = []; // Read the composer file $composer = $this->reader->setPackage($packageName)->setVersion($version)->getComposerObject(); // Make sure it defines an autoload section. // If it does not autoload anything then we ignore it. if (!isset($composer['autoload'])) { continue; } // Read in any excludes - getFilesFromMap will filter // out any files matched by these exclude globs. if (isset($composer['autoload']['exclude-from-classmap'])) { $this->excludes = []; $excludes = $composer['autoload']['exclude-from-classmap']; foreach ($excludes as $exclude) { $this->excludes[] = s(Glob::toRegex(s($exclude)->removeLeft('/')->ensureRight('**'), false))->replace('[^/]*[^/]*', '.*?'); } } // Find all autoloaded src files for this version if (isset($composer['autoload']['psr-4'])) { $psrLoaded[$version] = array_merge($psrLoaded[$version], $this->getFilesFromMap($packageName, $version, $composer['autoload']['psr-4'])); } if (isset($composer['autoload']['psr-0'])) { $psrLoaded[$version] = array_merge($psrLoaded[$version], $this->getFilesFromMap($packageName, $version, $composer['autoload']['psr-0'])); } if (isset($composer['autoload']['classmap'])) { $mapLoaded[$version] = array_merge($mapLoaded[$version], $this->getFilesFromMap($packageName, $version, $composer['autoload']['classmap'])); } if (isset($composer['autoload']['files'])) { $mapLoaded[$version] = array_merge($mapLoaded[$version], $this->getFilesFromMap($packageName, $version, $composer['autoload']['files'])); } } // We now know about all files that composer knows about. // Now we will search for any conflicting types, classes|functions // that have the exact same Fully Qualified Name. $this->findPsrConflicts($packageName, $psrLoaded); $this->findMappedConflicts($packageName, $mapLoaded); } return $this->conflicts; }
/** @inheritdoc */ public function renameConflicts(array $conflicts) { $replacements = []; $this->traverser->addVisitor($this->reNamer); foreach ($conflicts as $package => $types) { foreach ($types as $type => $versions) { foreach ($versions as $version => $files) { $composer = $this->reader->setPackage($package)->setVersion($version)->getComposerObject(); if ($this->hasNs($type)) { $split = $this->splitNsandClass($type); $fromNs = $split['ns']; $psrNs = $this->getPsrNs($composer, $fromNs); $toNs = $psrNs . $this->sanitizeVersionNo($version); $diff = str_replace($psrNs, '', $fromNs); if ($psrNs != $diff . '\\') { $toNs = $toNs . '\\' . $diff; } $newFullyQualifiedType = $toNs . '\\' . $split['class']; } else { $fromNs = $type; $toNs = $type . '_' . $this->sanitizeVersionNo($version); $newFullyQualifiedType = $toNs; } $this->reNamer->rename($fromNs, $toNs); $replacements[] = ['package' => $package, 'version' => $version, 'originalFullyQualifiedType' => $type, 'originalNamespace' => $fromNs, 'newFullyQualifiedType' => $newFullyQualifiedType, 'newNamespace' => $toNs, 'replacedIn' => $files]; foreach ($files as $file) { $fullPath = $this->vendorDir . '/' . $package . '/' . $version . '/' . $file; $src = $this->filesystem->read($fullPath); $ast = $this->parser->parse($src); $newAst = $this->traverser->traverse($ast); $code = $this->prettyPrinter->prettyPrintFile($newAst); $this->filesystem->update($fullPath, $code); } } } } $this->traverser->removeVisitor($this->reNamer); return $replacements; }
private function buildFileIncludes() { $map = []; foreach ($this->installedPackages as $package => $versions) { foreach ($versions as $version) { $composer = $this->reader->setPackage($package)->setVersion($version)->getComposerObject(); if (!isset($composer['autoload'])) { continue; } if (!isset($composer['autoload']['files'])) { continue; } foreach ($composer['autoload']['files'] as $path) { if ($package != null && $version != null) { $path = $package . '/' . $version . '/' . $path; } $map[] = $path; } } } return array_values(Linq::from($map)->distinct()->orderBy('$v')->toArray()); }