/**
  * 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];
     }
 }
 /**
  * {@inheritdoc}
  */
 protected function execute(InputInterface $input, OutputInterface $output)
 {
     $languages = $input->getArgument(self::PACKAGE_ARGUMENT);
     $packagesToRemove = [];
     $dependencies = $this->dependencyChecker->checkDependencies($languages, true);
     foreach ($languages as $package) {
         if (!$this->validate($package)) {
             $output->writeln("<info>Package {$package} is not a Magento language and will be skipped.</info>");
         } else {
             if (sizeof($dependencies[$package]) > 0) {
                 $output->writeln("<info>Package {$package} has dependencies and will be skipped.</info>");
             } else {
                 $packagesToRemove[] = $package;
             }
         }
     }
     if ($packagesToRemove !== []) {
         if ($input->getOption(self::BACKUP_CODE_OPTION)) {
             $backupRestore = $this->backupRollbackFactory->create($output);
             $backupRestore->codeBackup(time());
         } else {
             $output->writeln('<info>You are removing language package without a code backup.</info>');
         }
         $this->remove->remove($packagesToRemove);
         $this->cache->clean();
     } else {
         $output->writeln('<info>Nothing is removed.</info>');
     }
 }
 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 testExecuteFailedDependencyCheck()
 {
     $this->setUpPassValidation();
     $this->setupPassThemeInUseCheck();
     $this->setupPassChildThemeCheck();
     $this->dependencyChecker->expects($this->once())->method('checkDependencies')->willReturn(['magento/theme-a' => ['magento/theme-b', 'magento/theme-c']]);
     $this->tester->execute(['theme' => ['frontend/Magento/a']]);
     $this->assertContains('Unable to uninstall. Please resolve the following issues:' . PHP_EOL . 'frontend/Magento/a has the following dependent package(s):' . PHP_EOL . "\tmagento/theme-b" . PHP_EOL . "\tmagento/theme-c", $this->tester->getDisplay());
 }
 public function setUpExecute()
 {
     $this->setUpPassValidation();
     $this->setupPassChildThemeCheck();
     $this->dependencyChecker->expects($this->once())->method('checkDependencies')->willReturn([]);
     $this->remove->expects($this->once())->method('remove');
     $this->cache->expects($this->once())->method('clean');
     $theme = $this->getMock('Magento\\Theme\\Model\\Theme', [], [], '', false);
     $this->themeProvider->expects($this->any())->method('getThemeByFullPath')->willReturn($theme);
 }
 public function testExecutePackageNoLanguage()
 {
     $dependencies['vendor/language-ua_ua'] = [];
     $this->dependencyChecker->expects($this->once())->method('checkDependencies')->with(['vendor/language-ua_ua'])->willReturn($dependencies);
     $this->composerInfo->expects($this->once())->method('getRootRequiredPackagesAndTypes')->willReturn(['vendor/language-ua_ua' => 'library']);
     $this->remove->expects($this->never())->method('remove');
     $this->cache->expects($this->never())->method('clean');
     $this->tester->execute(['package' => ['vendor/language-ua_ua']]);
     $this->assertContains('Package vendor/language-ua_ua is not a Magento language and will be skipped', $this->tester->getDisplay());
     $this->assertContains('Nothing is removed.', $this->tester->getDisplay());
 }
 public function testCheckDependenciesExcludeSelf()
 {
     $composerApp = $this->getMock('Composer\\Console\\Application', ['setAutoExit', 'resetComposer', 'run'], [], '', false);
     $directoryList = $this->getMock('Magento\\Framework\\App\\Filesystem\\DirectoryList', [], [], '', false);
     $directoryList->expects($this->exactly(3))->method('getRoot');
     $composerApp->expects($this->once())->method('setAutoExit')->with(false);
     $composerApp->expects($this->at(2))->method('run')->willReturnCallback(function ($input, $buffer) {
         $output = 'magento/package-b requires magento/package-a (1.0)' . PHP_EOL . 'magento/package-c requires magento/package-a (1.0)' . PHP_EOL;
         $buffer->writeln($output);
     });
     $composerApp->expects($this->at(4))->method('run')->willReturnCallback(function ($input, $buffer) {
         $output = 'magento/package-c requires magento/package-b (1.0)' . PHP_EOL . 'magento/package-d requires magento/package-b (1.0)' . PHP_EOL;
         $buffer->writeln($output);
     });
     $composerApp->Expects($this->at(6))->method('run')->willReturnCallback(function ($input, $buffer) {
         $output = 'magento/package-d requires magento/package-c (1.0)' . PHP_EOL;
         $buffer->writeln($output);
     });
     $dependencyChecker = new DependencyChecker($composerApp, $directoryList);
     $expected = ['magento/package-a' => [], 'magento/package-b' => ['magento/package-d'], 'magento/package-c' => ['magento/package-d']];
     $this->assertEquals($expected, $dependencyChecker->checkDependencies(['magento/package-a', 'magento/package-b', 'magento/package-c'], true));
 }
 /**
  * Check dependencies to given full theme paths
  *
  * @param string[] $themePaths
  * @return string[]
  */
 private function checkDependencies($themePaths)
 {
     $messages = [];
     $packageToPath = [];
     foreach ($themePaths as $themePath) {
         $packageToPath[$this->themePackageInfo->getPackageName($themePath)] = $themePath;
     }
     $dependencies = $this->dependencyChecker->checkDependencies(array_keys($packageToPath), true);
     foreach ($dependencies as $package => $dependingPackages) {
         if (!empty($dependingPackages)) {
             $messages[] = '<error>' . $packageToPath[$package] . " has the following dependent package(s):</error>" . PHP_EOL . "\t<error>" . implode('</error>' . PHP_EOL . "\t<error>", $dependingPackages) . "</error>";
         }
     }
     return $messages;
 }