/**
  * Run Composer dependency check for uninstall
  *
  * @param array $packages
  * @return array
  * @throws \RuntimeException
  */
 public function runUninstallReadinessCheck(array $packages)
 {
     try {
         $packagesAndTypes = $this->composerInfo->getRootRequiredPackageTypesByName();
         $dependencies = $this->packageDependencyChecker->checkDependencies($packages, true);
         $messages = [];
         $themes = [];
         foreach ($packages as $package) {
             if (!isset($packagesAndTypes[$package])) {
                 throw new \RuntimeException('Package ' . $package . ' not found in the system.');
             }
             switch ($packagesAndTypes[$package]) {
                 case ComposerInformation::METAPACKAGE_PACKAGE_TYPE:
                     unset($dependencies[$package]);
                     break;
                 case ComposerInformation::THEME_PACKAGE_TYPE:
                     $themes[] = $package;
                     break;
             }
             if (!empty($dependencies[$package])) {
                 $messages[] = $package . " has the following dependent package(s): " . implode(', ', $dependencies[$package]);
             }
         }
         if (!empty($themes)) {
             $messages = array_merge($messages, $this->themeDependencyChecker->checkChildThemeByPackagesName($themes));
         }
         if (!empty($messages)) {
             throw new \RuntimeException(implode(PHP_EOL, $messages));
         }
         return ['success' => true];
     } catch (\RuntimeException $e) {
         $message = str_replace(PHP_EOL, '<br/>', htmlspecialchars($e->getMessage()));
         return ['success' => false, 'error' => $message];
     }
 }
 public function testRunUninstallReadinessCheckWithError()
 {
     $packages = ['verndor/module' => 'magento2-module', 'verndor/theme' => 'magento2-theme', 'verndor/metapackage' => 'metapackage', 'verndor/language' => 'magento2-language'];
     $this->composerInfo->expects($this->once())->method('getRootRequiredPackageTypesByName')->willReturn($packages);
     $this->packageDependencyChecker->expects($this->once())->method('checkDependencies')->with(array_keys($packages))->willReturn([]);
     $this->themeDependencyChecker->expects($this->once())->method('checkChildThemeByPackagesName')->with(['verndor/theme'])->willReturn(['Error message']);
     $result = $this->uninstallDependencyCheck->runUninstallReadinessCheck(array_keys($packages));
     $this->assertEquals(['success' => false, 'error' => 'Error message'], $result);
 }
 public function setUpPassValidation()
 {
     $this->themePackageInfo->expects($this->any())->method('getPackageName')->willReturn('magento/theme-a');
     $this->collection->expects($this->any())->method('getThemeByFullPath')->willReturn($this->getMockForAbstractClass('Magento\\Framework\\View\\Design\\ThemeInterface', [], '', false));
     $this->themeDependencyChecker->expects($this->any())->method('checkChildTheme')->willReturn([]);
     $this->collection->expects($this->any())->method('hasTheme')->willReturn(true);
 }
 /**
  * @dataProvider executeFailedChildThemeCheckDataProvider
  * @param bool $hasVirtual
  * @param bool $hasPhysical
  * @param array $input
  * @param string $expected
  * @return void
  */
 public function testExecuteFailedChildThemeCheck($hasVirtual, $hasPhysical, array $input, $expected)
 {
     $theme = $this->getMock('Magento\\Theme\\Model\\Theme', [], [], '', false);
     $theme->expects($this->any())->method('hasChildThemes')->willReturn($hasVirtual);
     $parentThemeA = $this->getMock('Magento\\Theme\\Model\\Theme', [], [], '', false);
     $parentThemeA->expects($this->any())->method('getFullPath')->willReturn('frontend/Magento/a');
     $parentThemeB = $this->getMock('Magento\\Theme\\Model\\Theme', [], [], '', false);
     $parentThemeB->expects($this->any())->method('getFullPath')->willReturn('frontend/Magento/b');
     $childThemeC = $this->getMock('Magento\\Theme\\Model\\Theme', [], [], '', false);
     $childThemeC->expects($this->any())->method('getFullPath')->willReturn('frontend/Magento/c');
     $childThemeD = $this->getMock('Magento\\Theme\\Model\\Theme', [], [], '', false);
     $childThemeD->expects($this->any())->method('getFullPath')->willReturn('frontend/Magento/d');
     if ($hasPhysical) {
         $childThemeC->expects($this->any())->method('getParentTheme')->willReturn($parentThemeA);
         $childThemeD->expects($this->any())->method('getParentTheme')->willReturn($parentThemeB);
     }
     $this->themeProvider->expects($this->any())->method('getThemeByFullPath')->willReturn($theme);
     $this->themeCollection->expects($this->any())->method('getIterator')->willReturn(new \ArrayIterator([$childThemeC, $childThemeD]));
     $this->assertEquals($expected, $this->themeDependencyChecker->checkChildTheme($input));
 }
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $messages = [];
     $themePaths = $input->getArgument(self::INPUT_KEY_THEMES);
     $messages = array_merge($messages, $this->validate($themePaths));
     if (!empty($messages)) {
         $output->writeln($messages);
         return;
     }
     $messages = array_merge($messages, $this->themeValidator->validateIsThemeInUse($themePaths), $this->themeDependencyChecker->checkChildTheme($themePaths), $this->checkDependencies($themePaths));
     if (!empty($messages)) {
         $output->writeln('<error>Unable to uninstall. Please resolve the following issues:</error>' . PHP_EOL . implode(PHP_EOL, $messages));
         return;
     }
     try {
         $output->writeln('<info>Enabling maintenance mode</info>');
         $this->maintenanceMode->set(true);
         if ($input->getOption(self::INPUT_KEY_BACKUP_CODE)) {
             $time = time();
             $codeBackup = $this->backupRollbackFactory->create($output);
             $codeBackup->codeBackup($time);
         }
         $this->themeUninstaller->uninstallRegistry($output, $themePaths);
         $this->themeUninstaller->uninstallCode($output, $themePaths);
         $this->cleanup($input, $output);
         $output->writeln('<info>Disabling maintenance mode</info>');
         $this->maintenanceMode->set(false);
     } catch (\Exception $e) {
         $output->writeln('<error>' . $e->getMessage() . '</error>');
         $output->writeln('<error>Please disable maintenance mode after you resolved above issues</error>');
     }
 }