Inheritance: extends Symfony\Component\Process\Process
 /**
  * @test
  */
 public function committerIsThreadSafe()
 {
     $gitRepository = new GitRepository(self::$repositoryDir, __DIR__);
     $gitRepository->init();
     $numberOfParallelCommits = 50;
     $numberOfFilesInEachCommit = 10;
     /** @var Process[] $runningProcesses */
     $runningProcesses = [];
     for ($i = 0; $i < $numberOfParallelCommits; $i++) {
         $from = $i * $numberOfFilesInEachCommit;
         $to = ($i + 1) * $numberOfFilesInEachCommit;
         $process = new Process("php generate-files-and-commit.php --from={$from} --to={$to}", __DIR__);
         $process->start();
         $runningProcesses[] = $process;
     }
     foreach ($runningProcesses as $process) {
         $process->wait();
     }
     $log = $gitRepository->log();
     $this->assertCount($numberOfParallelCommits, $log);
     foreach ($log as $commit) {
         $files = $commit->getChangedFiles();
         $this->assertCount($numberOfFilesInEachCommit, $files, "Files: \n" . join("\n", array_column($files, 'path')));
     }
 }
 public static function setUpBeforeClass()
 {
     parent::setUpBeforeClass();
     if (self::$testConfig->testSite->installationType !== 'standard') {
         throw new \PHPUnit_Framework_SkippedTestSuiteError();
     }
     $testDataPath = __DIR__ . '/../test-data';
     self::$pluginInfo = ['zipfile' => realpath($testDataPath . '/hello-dolly.1.6.zip'), 'url-fragment' => 'hello-dolly', 'name' => 'Hello Dolly', 'affected-path' => 'hello-dolly/*'];
     self::$secondPluginInfo = ['zipfile' => realpath($testDataPath . '/hello-dolly.1.6-2.zip'), 'url-fragment' => 'hello-dolly-2', 'name' => 'Hello Dolly 2', 'affected-path' => 'hello-dolly-2/*'];
     self::$worker->setPluginInfo(self::$pluginInfo);
     self::$worker->setSecondPluginInfo(self::$secondPluginInfo);
     // possibly delete single-file Hello dolly
     try {
         self::$wpAutomation->runWpCliCommand('plugin', 'uninstall', ['hello']);
     } catch (\Exception $e) {
     }
     // possibly delete our testing plugins
     try {
         self::$wpAutomation->runWpCliCommand('plugin', 'uninstall', ['hello-dolly']);
         self::$wpAutomation->runWpCliCommand('plugin', 'uninstall', ['hello-dolly-2']);
     } catch (\Exception $e) {
     }
     $process = new Process("git add -A && git commit -m " . ProcessUtils::escapeshellarg("Plugin setup"), self::$testConfig->testSite->path);
     $process->run();
 }
Example #3
0
 /**
  * Executes a command, optionally in a specified working directory.
  *
  * @param string $command
  * @param string|null $cwd
  * @return Process
  */
 public static function exec($command, $cwd = null)
 {
     // Changing env variables for debugging
     // If we run another wp-cli command from our command, it breaks and never continues (with xdebug).
     // So we need to turn xdebug off for all "nested" commands.
     if (isset($_SERVER["XDEBUG_CONFIG"])) {
         $env = $_SERVER;
         unset($env["XDEBUG_CONFIG"]);
     } else {
         $env = null;
     }
     $process = new Process($command, $cwd, $env);
     $process->run();
     return $process;
 }
 private function detectChanges()
 {
     $currentComposerLock = file_get_contents(VP_PROJECT_ROOT . '/composer.lock');
     $process = new Process(VP_GIT_BINARY . ' show HEAD:composer.lock', VP_PROJECT_ROOT);
     $process->run();
     $previousComposerLock = $process->getOutput();
     $currentPackages = $this->getPackagesFromLockFile($currentComposerLock);
     $previousPackages = $this->getPackagesFromLockFile($previousComposerLock);
     $installedPackages = array_diff_key($currentPackages, $previousPackages);
     $removedPackages = array_diff_key($previousPackages, $currentPackages);
     $packagesWithChangedVersion = array_filter(array_intersect_key($currentPackages, $previousPackages), function ($package) use($previousPackages) {
         return $package['version'] !== $previousPackages[$package['name']]['version'];
     });
     return ['installed' => $installedPackages, 'removed' => $removedPackages, 'updated' => $packagesWithChangedVersion];
 }
Example #5
0
 private static function getPermissionInfo()
 {
     $proc = proc_open('whoami', [['pipe', 'r'], ['pipe', 'w'], ['pipe', 'w']], $pipes);
     $procOpenUser = trim(stream_get_contents($pipes[1]));
     $processInfo = ['exec-user' => exec('whoami'), 'proc_open-user' => $procOpenUser];
     $writeTargets = ['ABSPATH' => ABSPATH, 'WP_CONTENT_DIR' => WP_CONTENT_DIR, 'sys_temp_dir' => sys_get_temp_dir()];
     foreach ($writeTargets as $target => $directory) {
         $filePath = $directory . '/' . '.vp-try-write-php';
         /** @noinspection PhpUsageOfSilenceOperatorInspection */
         @file_put_contents($filePath, "");
         $processInfo['php-can-write'][$target] = is_file($filePath);
         FileSystem::remove($filePath);
         $processInfo['php-can-delete'][$target] = !is_file($filePath);
         $filePath = $directory . '/' . '.vp-try-write-process';
         $process = new Process(sprintf("echo test > %s", ProcessUtils::escapeshellarg($filePath)));
         $process->run();
         $processInfo['process-can-write'][$target] = is_file($filePath);
         try {
             FileSystem::remove($filePath);
             $processInfo['php-can-delete-file-created-by-process'][$target] = !is_file($filePath);
         } catch (IOException $ex) {
             $processInfo['php-can-delete-file-created-by-process'][$target] = false;
         }
     }
     return $processInfo;
 }
 /**
  * Low-level helper, generally use runShellCommand()
  *
  * @param $cmd
  * @return array
  */
 private function runProcess($cmd)
 {
     /*
      * MAMP / XAMPP issue on Mac OS X, see #106.
      *
      * http://stackoverflow.com/a/16903162/1243495
      */
     $dyldLibraryPath = getenv("DYLD_LIBRARY_PATH");
     if ($dyldLibraryPath != "") {
         putenv("DYLD_LIBRARY_PATH=");
     }
     $process = new Process($cmd, $this->workingDirectoryRoot);
     if ($this->gitProcessTimeout !== null) {
         $process->setTimeout($this->gitProcessTimeout);
     }
     $process->run();
     $result = ['stdout' => $process->getOutput(), 'stderr' => $process->getErrorOutput()];
     putenv("DYLD_LIBRARY_PATH={$dyldLibraryPath}");
     if ($result['stdout'] !== null) {
         $result['stdout'] = trim($result['stdout']);
     }
     if ($result['stderr'] !== null) {
         $result['stderr'] = trim($result['stderr']);
     }
     return $result;
 }
 private function tryWrite()
 {
     $filename = ".vp-try-write";
     $testPaths = [ABSPATH, WP_CONTENT_DIR, sys_get_temp_dir()];
     $writable = true;
     foreach ($testPaths as $directory) {
         $filePath = $directory . '/' . $filename;
         /** @noinspection PhpUsageOfSilenceOperatorInspection */
         @file_put_contents($filePath, "");
         $writable &= is_file($filePath);
         FileSystem::remove($filePath);
         // Trying to create file from process (issue #522)
         $process = new Process(sprintf("echo test > %s", ProcessUtils::escapeshellarg($filePath)));
         $process->run();
         $writable &= is_file($filePath);
         try {
             FileSystem::remove($filePath);
         } catch (IOException $ex) {
             $writable = false;
             // the file could not be deleted - the permissions are wrong
         }
     }
     return $writable;
 }
Example #8
0
 /**
  * Pulls changes from another clone
  *
  * ## OPTIONS
  *
  * [--from=<name|path|url>]
  * : Where to pull from. Can be a clone name (specified previously during the
  * 'clone' command), a path or a URL. Defaults to 'origin' which is
  * automatically set in every clone by the 'clone' command.
  *
  * [--continue]
  * : Finishes the pull after solving merge conflicts.
  *
  * ## EXAMPLES
  *
  * Let's have a site 'wpsite' and a clone 'myclone' created from it. To pull the changes
  * from the clone back into the main site, use:
  *
  *     wp vp pull --from=myclone
  *
  * When in the clone, the pull can be run without any parameter:
  *
  *     wp vp pull
  *
  * This will pull the changes from 'origin' which was set to the parent site during the
  * 'clone' command.
  *
  */
 public function pull($args = [], $assoc_args = [])
 {
     if (!VersionPress::isActive()) {
         WP_CLI::error('This site is not tracked by VersionPress. Please run "wp vp activate" before cloning / merging.');
     }
     if (isset($assoc_args['continue'])) {
         $process = new Process('git diff --name-only --diff-filter=U', VP_PROJECT_ROOT);
         $process->run();
         if ($process->getConsoleOutput() !== '') {
             WP_CLI::error('There are still some conflicts. Please resolve them and run `wp vp pull --continue` again.');
         }
         $this->finishPull();
         return;
     }
     $remote = isset($assoc_args['from']) ? $assoc_args['from'] : 'origin';
     $process = VPCommandUtils::exec("git config --get remote." . ProcessUtils::escapeshellarg($remote) . ".url");
     $remoteUrl = $process->getConsoleOutput();
     if (is_dir($remoteUrl)) {
         $this->runVPInternalCommand('commit-frequently-written-entities', [], $remoteUrl);
     } else {
         // We currently do not support commiting frequently written entities for repositories on a different server
     }
     $this->switchMaintenance('on');
     $branchToPullFrom = 'master';
     // hardcoded until we support custom branches
     $pullCommand = 'git pull ' . ProcessUtils::escapeshellarg($remote) . ' ' . $branchToPullFrom;
     $process = VPCommandUtils::exec($pullCommand);
     if ($process->isSuccessful()) {
         WP_CLI::success("Pulled changes from '{$remote}'");
     } else {
         if (stripos($process->getConsoleOutput(), 'automatic merge failed') !== false) {
             WP_CLI::warning("");
             WP_CLI::warning("CONFLICTS DETECTED. Your options:");
             WP_CLI::warning("");
             WP_CLI::warning(" 1) Keep the conflicts. You will be able to resolve them manually.");
             WP_CLI::warning(" 2) Abort the process. The site will look like you never ran the pull.");
             WP_CLI::warning("");
             fwrite(STDOUT, "Choose 1 or 2: ");
             $answer = trim(fgets(STDIN));
             if ($answer == "1") {
                 WP_CLI::success("You've chosen to keep the conflicts on the disk. MAINTENANCE MODE IS STILL ON.");
                 WP_CLI::success("");
                 WP_CLI::success("Do this now:");
                 WP_CLI::success("");
                 WP_CLI::success(" 1. Resolve the conflicts manually as in a standard Git workflow");
                 WP_CLI::success(" 2. Stage and `git commit` the changes");
                 WP_CLI::success(" 3. Return here and run `wp vp pull --continue`");
                 WP_CLI::success("");
                 WP_CLI::success("That last step will turn the maintenance mode off.");
                 WP_CLI::success("You can also abort the merge manually by running `git merge --abort`");
                 exit;
             } else {
                 $process = VPCommandUtils::exec('git merge --abort');
                 if ($process->isSuccessful()) {
                     $this->switchMaintenance('off');
                     WP_CLI::success("Pull aborted, your site is now clean and running");
                     exit;
                 } else {
                     WP_CLI::error("Aborting pull failed, do it manually by executing 'git merge --abort'", false);
                     WP_CLI::error("and also don't fortget to turn off the maintenance mode.");
                 }
             }
         } else {
             // not a merge conflict, some other error
             $this->switchMaintenance('off');
             WP_CLI::error("Changes from {$remote} couldn't be pulled. Details:\n\n" . $process->getConsoleOutput());
         }
     }
     $this->finishPull();
 }
 /**
  * Runs Git command in the test repo and returns the exit code.
  *
  * @param string $cmd
  * @return int Exit code
  */
 public static function runGitCommand($cmd)
 {
     $process = new Process($cmd, self::$repositoryDir);
     $process->run();
     return $process->getExitCode();
 }
 public static function tearDownAfterClass()
 {
     $process = new Process("git add -A && git commit -m " . ProcessUtils::escapeshellarg("Commited changes made by " . get_called_class()), self::$testConfig->testSite->path);
     $process->run();
 }
 /**
  * Creates project structure similar to Bedrock.
  * Pedestal (https://github.com/versionpress/pedestal) is inpired by Bedrock. It only have
  * a standard wp-config-based configuration system and predefined Composer scripts for VersionPress.
  */
 private function createPedestalBasedSite()
 {
     $process = new Process('composer create-project -s dev versionpress/pedestal .', $this->siteConfig->path);
     $process->run();
     $this->updateConfigConstant('DB_NAME', $this->siteConfig->dbName);
     $this->updateConfigConstant('DB_USER', $this->siteConfig->dbUser);
     $this->updateConfigConstant('DB_PASSWORD', $this->siteConfig->dbPassword);
     $this->updateConfigConstant('DB_HOST', $this->siteConfig->dbHost);
     $this->updateConfigConstant('WP_HOME', $this->siteConfig->url);
 }