/** * Loads a package from a given directory. * * This function returns the string of the primary package class. * * @throws InvalidPathException Thrown when the package directory * does not exist. * @throws NewUpException * @param $directory * @return string */ public function loadPackage($directory) { if (!$this->files->exists($directory)) { throw new InvalidPathException("The directory {$directory} does not exist."); } if (!$this->files->exists($directory . '/composer.json')) { throw new InvalidPathException("There is no composer.json file in {$directory}"); } if (!$this->files->exists($directory . '/_newup')) { throw new InvalidPathException("There is no _newup directory in {$directory}"); } if (!$this->files->exists($directory . '/_newup/Package.php')) { throw new InvalidPathException("A Package.php file must be present in in \"_newup\" directory."); } $package = Package::fromFile($directory . '/composer.json', user_config('configuration.strictComposerValues', true)); $namespace = package_vendor_namespace($package->getVendor(), $package->getPackage(), true); add_psr4($namespace, $directory . '/_newup'); if (!class_exists($namespace . 'Package', true)) { throw new NewUpException("A valid reachable class named 'Package' must be defined."); } if (!is_subclass_of($namespace . 'Package', BasePackageTemplate::class)) { throw new NewUpException("The 'Package' class must extend " . BasePackageTemplate::class); } return $namespace . 'Package'; }
/** * Execute the console command. * * @return mixed */ public function handle() { $this->line('Starting package template initialization...'); try { $directory = $this->argument('directory'); if (!$this->files->exists($directory)) { $createDirectory = $this->confirm("{$directory} does not exist. Would you like to create it? [YES/no]", true); if ($createDirectory) { $this->line("{$directory} was created."); $this->files->makeDirectory($directory); } } if ($this->files->exists($directory) && $this->files->isDirectory($directory)) { $fileCount = count($this->files->allFiles($directory)); if ($fileCount > 0) { $removeFiles = $this->confirm("{$directory} is not empty. Would you like to remove the contents? [yes|NO]", false); if ($removeFiles) { $this->line("The contents in '{$directory}' were cleared."); $this->files->deleteDirectory($directory, true); } } } $this->templateInitializer->setShouldCreateTemplateDirectory(!$this->option('no-template-dir')); $packageVendor = Package::parseVendorAndPackage($this->argument('name')); $this->templateInitializer->initialize($packageVendor[0], $packageVendor[1], $directory); $this->info('Package was successfully initialized!'); } catch (InvalidPathException $invalidPath) { $this->error('There was a problem initializing the package template (most likely due to an invalid path). The error was:'); $this->error($invalidPath->getMessage()); } catch (InvalidArgumentException $invalidVendorPackage) { $this->error('There was a problem initializing the package template'); $this->error($invalidVendorPackage->getMessage()); } }
/** * Initializes a package template in the provided directory. * * @throws InvalidPathException * * @param $vendor * @param $package * @param $directory */ public function initialize($vendor, $package, $directory) { if (!$this->files->exists($directory) || !$this->files->isDirectory($directory)) { throw new InvalidPathException("{$directory} does not exist or is not a valid directory."); } $packageComposer = new Package(); $packageComposer->setVendor($vendor); $packageComposer->setPackage($package); $packageComposer->setDescription('Give your package template a good description'); $packageComposer->setLicense(user_config('configuration.license', '')); $packageComposer->setAuthors(user_config('configuration.authors', [])); $writer = new ConfigurationWriter($packageComposer->toArray()); $writer['config'] = (object) ['vendor-dir' => '_newup_vendor']; $writer->save($directory . '/composer.json'); $this->renderer->setData('package', $package); $this->renderer->setData('vendor', $vendor); $packageClass = $this->renderer->render('template'); if (!$this->files->exists($directory . '/_newup/')) { $this->files->makeDirectory($directory . '/_newup/'); } if ($this->shouldCreateTemplateDirectory && $this->files->exists($directory . '/_template') == false) { $this->files->makeDirectory($directory . '/_template'); } $this->files->put($directory . '/_newup/Package.php', $packageClass); }
/** * Override the builderLoaded method so we can know when NewUp * has loaded the workbench playground. We can access user * arguments and options at this point in template * generation, which will prove very useful. */ public function builderLoaded() { // Get the parsed vendor and package name from the user input. NewUp's Package class // provides a helper method just for this. $vendorPackageParts = PackageClass::parseVendorAndPackage($this->argument('package')); $vendor = $vendorPackageParts[0]; $package = $vendorPackageParts[1]; // Share the vendor and package with the template system. $this->with(['vendor' => $vendor, 'package' => $package]); if (!$this->option('resources')) { // If the user has not specified the resources option, we can just tell // NewUp to ignore the Laravel specific directories. It is important // to note that ignored paths are actually patterns. $this->ignorePath(['src/controllers*', 'src/migrations*', 'src/config*', 'src/views*', 'src/lang*', 'public/*']); } // Laravel 4's workbench tool created a "composer.json" file in the directory // of the new package. This is also very easy to accomplish using NewUp. // First, we will get a PackageClass instance that we can work with // and manipulate. Conveniently, the PackageClass's structure is // very close to that of a "composer.json" file. Since NewUp // allows users to configure the default authors and license // we can get a PackageClass instance with all of those // values already set. $composerJson = PackageClass::getConfiguredPackage(); // Now we can set the vendor and package name, which we parsed earlier. We // will also need to add a few more things that the PackageClass cannot // handle on its own. We will take care of that later with the // ConfigurationWriter class. $composerJson->setVendor($vendor)->setPackage($package); // The PackageClass cannot save anything by itself, but a ConfigurationWriter // class is available that can. We can create a new instance of the writer // and pass all the values from the PackageClass as an array! $writer = new ConfigurationWriter($composerJson->toArray()); // Before we save anything, we need to add a few more things to the final // "composer.json" file. We need to add the require, autoload and minimum // stability sections. Also take note that we are casting some arrays // into objects to get the desired output when everything is finally // saved in the JSON format. $writer['require'] = (object) ['php' => '>=5.4.0', 'illuminate/support' => '4.2.*']; $autoloadSection = ['psr-0' => (object) [Str::studly($vendor) . '\\\\' . Str::studly($package) . '\\\\' => 'src/']]; // Add the migrations to the autoload section if the user specified the "resources" option. if ($this->option('resources')) { $autoloadSection['classmap'][] = 'src/migrations'; } // Now we can add the autoload section. $writer['autoload'] = (object) $autoloadSection; $writer['minimum-stability'] = 'stable'; // Now it is time to save the "composer.json" file. $writer->save($this->outputDirectory() . '/composer.json'); }
/** * Called when the builder has loaded the package class. * * @return mixed */ public function builderLoaded() { // Get the parsed vendor and package name from the user input. NewUp's Package class // provides a helper method just for this. $vendorPackageParts = PackageClass::parseVendorAndPackage($this->argument('package')); $vendor = $vendorPackageParts[0]; $package = $vendorPackageParts[1]; // Share the vendor and package with the template system. $this->with(['vendor' => $vendor, 'package' => $package]); // Just some setup code to create a composer.json file. $composerJson = PackageClass::getConfiguredPackage(); $composerJson->setVendor($vendor)->setPackage($package); $writer = new ConfigurationWriter($composerJson->toArray()); // Package requirements. $requirements = ['php' => $this->argument('phpv')]; // Package dev requirements. $requireDev = []; // If the user specified PHPUnit support, we need to add that to the requirements. if ($this->option('phpunit')) { $requireDev['mockery/mockery'] = '~0.9.2'; $requireDev['phpunit/phpunit'] = '~4.0'; $this->line("Added 'mockery/mockery' and 'phpunit/phpunit' to composer dev dependencies."); } else { $this->ignorePath(['phpunit.xml', 'tests/*']); } // Gather TravisCI information. if ($this->option('travis')) { $this->gatherTravisCIRequirements(); $this->with(['travisVersions' => $this->travisVersions]); } else { $this->ignorePath(['.travis.yml']); } $writer['require'] = (object) $requirements; $writer['require-dev'] = (object) $requireDev; // This next section will create the "autoload" section within the composer.json file. $autoLoader = $this->option('psr'); $autoLoader == 'psr0' ? $autoLoader = 'psr-0' : ($autoLoader = 'psr-4'); $autoloadSection = [$autoLoader => (object) [Str::studly($vendor) . '\\' . Str::studly($package) . '\\' => 'src/']]; $this->line("Using {$autoLoader} autoloader."); // Now we can add the autoload section. $writer['autoload'] = (object) $autoloadSection; $writer['minimum-stability'] = 'stable'; // Now it is time to save the "composer.json" file. $writer->save($this->outputDirectory() . '/composer.json'); $this->info("Your package was generated! Make sure to set the description field in your composer.json file!"); }
/** * Returns a new package instance from the provided array. * * @param array $array * @param bool $strict * * @return PackageContract * @throws \InvalidArgumentException */ public static function fromArray(array $array, $strict = true) { $details = (object) $array; $packageNameDetails = self::parseVendorAndPackage(object_get($details, 'name', null)); $description = object_get($details, 'description', null); $license = object_get($details, 'license', null); $authors = object_get($details, 'authors', null); // Throw exceptions if the developer wants us to be super strict. if ($strict) { self::throwInvalidArgumentException($description, 'Invalid package description.'); self::throwInvalidArgumentException($license, 'Invalid package license.'); self::throwInvalidArgumentException($authors, 'Invalid package authors.'); } $package = new Package(); $package->setAuthors($authors); $package->setDescription($description); $package->setLicense($license); $package->setVendor($packageNameDetails[0]); $package->setPackage($packageNameDetails[1]); return $package; }
/** * Gets the details for a given package, based on a given path. * * @param $path * @return array */ private function getPackageDetails($path) { $packagePath = $this->normalizePath($path); $packageName = explode(DIRECTORY_SEPARATOR, $packagePath); $packageName = end($packageName); $packageVersion = null; if (Str::endsWith($packageName, '}')) { // Version, handle it specially. $packageName = str_replace('_{updating_in_progress}', '', $packageName); $parts = null; $parts = explode('{', $packageName, 2); $packageName = rtrim($parts[0], '_'); if (isset($parts[1])) { $packageVersion = rtrim($parts[1], '}'); } } $packageDetails = ['package' => $packageName, 'version' => $packageVersion, 'instance' => Package::fromFile($path . DIRECTORY_SEPARATOR . 'composer.json', false), 'path' => $packagePath]; return $packageDetails; }
public function testPackageExportsCorrectJSONStructure() { $package = $this->getPackageFromArray(); $this->assertEquals($package, Package::fromArray(json_decode($package->toJson(), true))); }