/** * hasBinary returns true if the binary is available in any of the PATHs. * * @param string $binaryName * * @return bool */ public static function hasBinary($binaryName) { $exec = Exec::create(); if (self::isWindows()) { // 'where.exe' uses 0 for success, 1 for failure to find $exec->run('where.exe', '/q', $binaryName); return $exec->getStatus() === 0; } // 'which' uses 0 for success, 1 for failure to find $exec->run('which', $binaryName); if ($exec->getStatus() === 0) { return true; } // 'whereis' does not use status codes. Check for a matching line instead. $exec->run('whereis', '-b', $binaryName); foreach ($exec->getOutput() as $line) { if (preg_match('/^' . preg_quote($binaryName) . ': .*$/', $line) === 1) { return true; } } return false; }
/** * deleteContents of a folder recursively, but not the folder itself. * * On Windows systems this will try to remove the read-only attribute if needed. * * @param string $path Path of folder whose contents will be deleted * * @throws \RuntimeException Thrown when something could not be deleted. */ public static function deleteContents($path) { if (!is_dir($path)) { return; } /** @var \SplFileInfo[] $files */ $files = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path, \RecursiveDirectoryIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST); foreach ($files as $fileInfo) { if ($fileInfo->isDir()) { if (@rmdir($fileInfo->getRealPath()) === false) { throw new \RuntimeException(sprintf("Unable to delete child folder '%s' in '%s': %s", $fileInfo->getFilename(), $fileInfo->getPathname(), error_get_last()['message'])); } } elseif (@unlink($fileInfo->getRealPath()) === false) { if (OS::isWindows()) { Exec::create('attrib', '-R', $fileInfo->getRealPath())->run(); if (@unlink($fileInfo->getPathname())) { continue; } } throw new \RuntimeException(sprintf("Unable to delete file '%s' in folder '%s': %s", $fileInfo->getFilename(), $fileInfo->getPathname(), error_get_last()['message'])); } } }
/** * @return null|string */ private function readMercurial() { $hgDir = Path::combine($this->repositoryRoot, '.hg'); if (!is_dir($hgDir) || !OS::hasBinary('hg')) { return null; } $hg = Exec::create('hg', '--repository', $this->repositoryRoot); // Removes everything but the tag if distance is zero. $hg->run('log', '-r', '.', '--template', '{latesttag}{sub(\'^-0-m.*\', \'\', \'-{latesttagdistance}-m{node|short}\')}'); $tag = Dot::get($hg->getOutput(), 0); // Actual null if no lines were returned or `hg log` returned actual "null". // Either way, need to fall back to the revision id. if ($tag === null || $tag === 'null' || Strings::startsWith($tag, 'null-')) { $hg->run('id', '-i'); $tag = Dot::get($hg->getOutput(), 0); // Remove 'dirty' plus from revision id $tag = rtrim($tag, '+'); } $summary = $hg->run('summary')->getOutput(); $isDirty = 0 === count(array_filter($summary, function ($line) { return preg_match('/^commit: .*\\(clean\\)$/', $line) === 1; })); if ($isDirty) { $tag .= '-dirty'; } return $tag; }