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(); }
/** * 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]; }
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; }
/** * 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); }