/** * {@inheritdoc} */ public function generate(array $packages = array(), FeaturesBundleInterface $bundle = NULL) { // If no packages were specified, get all packages. if (empty($packages)) { $packages = $this->featuresManager->getPackages(); } // Determine the best name for the tar archive. // Single package export, so name by package name. if (count($packages) == 1) { $filename = current($packages)->getMachineName(); } elseif (isset($bundle) && $bundle->isProfile()) { $filename = $bundle->getProfileName(); } elseif (isset($bundle) && !$bundle->isDefault()) { $filename = $bundle->getMachineName(); } else { $filename = 'generated_features'; } $return = []; $this->archiveName = $filename . '.tar.gz'; $archive_name = file_directory_temp() . '/' . $this->archiveName; if (file_exists($archive_name)) { file_unmanaged_delete($archive_name); } $archiver = new ArchiveTar($archive_name); // Add package files. foreach ($packages as $package) { if (count($packages) == 1) { // Single module export, so don't generate entire modules dir structure. $package->setDirectory($package->getMachineName()); } $this->generatePackage($return, $package, $archiver); } return $return; }
/** * Adds the optional bundle prefix to package machine names. * * @param string[] &$package_names * Array of package names, passed by reference. * @param \Drupal\features\FeaturesBundleInterface $bundle * The optional bundle used for the generation. Used to generate profiles. */ protected function setPackageBundleNames(array &$package_names, FeaturesBundleInterface $bundle = NULL) { if ($bundle && !$bundle->isDefault()) { $new_package_names = []; // Assign the selected bundle to the exports. $packages = $this->featuresManager->getPackages(); foreach ($package_names as $package_name) { // Rename package to use bundle prefix. $package = $packages[$package_name]; // The install profile doesn't need renaming. if ($package['type'] != 'profile') { unset($packages[$package_name]); $package['machine_name'] = $bundle->getFullName($package['machine_name']); $packages[$package['machine_name']] = $package; } // Set the bundle machine name. $packages[$package['machine_name']]['bundle'] = $bundle->getMachineName(); $new_package_names[] = $package['machine_name']; } $this->featuresManager->setPackages($packages); $package_names = $new_package_names; } }
/** * {@inheritdoc} */ public function setPackageBundleNames(FeaturesBundleInterface $bundle, array &$package_names = []) { $this->packagesPrefixed = TRUE; if (!$bundle->isDefault()) { $new_package_names = []; // Assign the selected bundle to the exports. $packages = $this->getPackages(); if (empty($package_names)) { $package_names = array_keys($packages); } foreach ($package_names as $package_name) { // Rename package to use bundle prefix. $package = $packages[$package_name]; // The install profile doesn't need renaming. if ($package->getType() != 'profile') { unset($packages[$package_name]); $package->setMachineName($bundle->getFullName($package->getMachineName())); $packages[$package->getMachineName()] = $package; } // Set the bundle machine name. $packages[$package->getMachineName()]->setBundle($bundle->getMachineName()); $new_package_names[] = $package->getMachineName(); } $this->setPackages($packages); $package_names = $new_package_names; } }
/** * {@inheritdoc} */ public function getAllModules(FeaturesBundleInterface $bundle = NULL) { // ModuleHandler::getModuleDirectories() returns data only for installed // modules. system_rebuild_module_data() includes only the site's install // profile directory, while we may need to include a custom profile. // @see _system_rebuild_module_data(). $listing = new ExtensionDiscovery(\Drupal::root()); $profile_directories = []; // Register the install profile. $installed_profile = drupal_get_profile(); if ($installed_profile) { $profile_directories[] = drupal_get_path('profile', $installed_profile); } if (isset($bundle) && $bundle->isProfile()) { $profile_directory = 'profiles/' . $bundle->getProfileName(); if ($bundle->getProfileName() != $installed_profile && is_dir($profile_directory)) { $profile_directories[] = $profile_directory; } } $listing->setProfileDirectories($profile_directories); // Find modules. $modules = $listing->scan('module'); // Find installation profiles. $profiles = $listing->scan('profile'); foreach ($profiles as $key => $profile) { $modules[$key] = $profile; } $return = array(); // Detect modules by namespace. // If namespace is provided but is empty, then match all modules. foreach ($modules as $module_name => $extension) { if ($this->isFeatureModule($extension) && (!isset($bundle) || $bundle->isDefault() || $bundle->inBundle($module_name))) { $return[$module_name] = $extension; } } return $return; }
/** * @covers Drupal\features\Plugin\FeaturesAssignment\FeaturesAssignmentExclude */ public function testAssignExclude() { $method_id = 'exclude'; // Enable the method. $this->enableAssignmentMethod($method_id); // Also enable Packages and Core plugins. $this->enableAssignmentMethod('packages', FALSE); $this->enableAssignmentMethod('core', FALSE); // Apply the bundle $this->bundle = $this->assigner->loadBundle('test_mybundle'); $this->assigner->applyAssignmentMethod('packages'); $packages = $this->featuresManager->getPackages(); $this->assertNotEmpty($packages[self::TEST_INSTALLED_PACKAGE], 'Expected package not created.'); // 1. When Required is set to True, config should stay with the module // First, test with "Required" set to True. $packages[self::TEST_INSTALLED_PACKAGE]->setRequired(true); $this->featuresManager->setPackages($packages); $this->assigner->applyAssignmentMethod('exclude'); $this->assigner->applyAssignmentMethod('core'); $this->assigner->applyAssignmentMethod('existing'); $packages = $this->featuresManager->getPackages(); $expected_config_items = ['core.date_format.long']; $this->assertEquals($expected_config_items, $packages[self::TEST_INSTALLED_PACKAGE]->getConfig(), 'Expected configuration items not present in existing test_core package.'); // 2. When Required is set to False, config still stays with module // Because the module is installed. $this->reset(); $this->bundle = $this->assigner->loadBundle('test_mybundle'); $this->assigner->applyAssignmentMethod('packages'); $packages = $this->featuresManager->getPackages(); $this->assertNotEmpty($packages[self::TEST_INSTALLED_PACKAGE], 'Expected test_mybundle_core package not created.'); // Set "Required" set to False $packages[self::TEST_INSTALLED_PACKAGE]->setRequired(false); $this->featuresManager->setPackages($packages); $this->assigner->applyAssignmentMethod('exclude'); $this->assigner->applyAssignmentMethod('core'); $this->assigner->applyAssignmentMethod('existing'); $packages = $this->featuresManager->getPackages(); $this->assertFalse(array_key_exists('core', $packages), 'Core package should not be created.'); $expected_config_items = ['core.date_format.long']; $this->assertEquals($expected_config_items, $packages[self::TEST_INSTALLED_PACKAGE]->getConfig(), 'Expected configuration items not present in existing test_core package.'); // 3. When Required is set to False and module is NOT installed, // Config stays with module if it doesn't match the current namespace $this->reset(); // Load a bundle different from TEST_UNINSTALLED_PACKAGE $this->bundle = $this->assigner->loadBundle('test_mybundle'); $this->assigner->applyAssignmentMethod('packages'); $packages = $this->featuresManager->getPackages(); $this->assertNotEmpty($packages[self::TEST_UNINSTALLED_PACKAGE], 'Expected test_feature package not created.'); $this->assertNotEmpty($packages[self::TEST_INSTALLED_PACKAGE], 'Expected test_mybundle_core package not created.'); // Mark package as uninstalled, set "Required" set to False $packages[self::TEST_UNINSTALLED_PACKAGE]->setRequired(false); $this->featuresManager->setPackages($packages); $this->assigner->applyAssignmentMethod('exclude'); $this->assigner->applyAssignmentMethod('core'); $this->assigner->applyAssignmentMethod('existing'); $packages = $this->featuresManager->getPackages(); $this->assertFalse(array_key_exists('core', $packages), 'Core package should not be created.'); $expected_config_items = ['core.date_format.short', 'system.cron']; $this->assertEquals($expected_config_items, $packages[self::TEST_UNINSTALLED_PACKAGE]->getConfig(), 'Expected configuration items not present in existing test_feature package.'); // 4. When Required is set to False and module is NOT installed, // Config is reassigned within modules that match the namespace. $this->reset(); // Load the bundle used in TEST_UNINSTALLED_PACKAGE $this->bundle = $this->assigner->loadBundle('test'); if (empty($this->bundle) || $this->bundle->isDefault()) { // Since we uninstalled the test_feature, we probably need to create // an empty "test" bundle $this->bundle = $this->assigner->createBundleFromDefault('test'); } $this->assigner->applyAssignmentMethod('packages'); $packages = $this->featuresManager->getPackages(); $this->assertNotEmpty($packages[self::TEST_UNINSTALLED_PACKAGE], 'Expected test_feature package not created.'); // Set "Required" set to False $packages[self::TEST_UNINSTALLED_PACKAGE]->setRequired(false); $this->featuresManager->setPackages($packages); $this->assigner->applyAssignmentMethod('exclude'); $this->assigner->applyAssignmentMethod('core'); $this->assigner->applyAssignmentMethod('existing'); $packages = $this->featuresManager->getPackages(); $this->assertNotEmpty($packages['core'], 'Expected Core package not created.'); // Ensure "core" package is not confused with "test_core" module // Since we are in a bundle $this->assertEmpty($packages['core']->getExtension(), 'Autogenerated core package should not have an extension'); // Core config should be reassigned from TEST_UNINSTALLED_PACKAGE into Core $expected_config_items = ['system.cron']; $this->assertEquals($expected_config_items, $packages[self::TEST_UNINSTALLED_PACKAGE]->getConfig(), 'Expected configuration items not present in existing test_feature package.'); $expected_config_items = ['core.date_format.short']; $this->assertEquals($expected_config_items, $packages['core']->getConfig(), 'Expected configuration items not present in core package.'); }