You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

471 lines
14 KiB
PHTML

<?php
/**
* Created by JetBrains PhpStorm.
* User: matt.whittom
* Date: 7/23/13
* Time: 3:22 PM
* To change this template use File | Settings | File Templates.
*/
namespace Composer\Util;
use Composer\IO\IOInterface;
class Perforce {
protected $path;
protected $p4client;
protected $p4user;
protected $p4password;
protected $p4port;
protected $p4stream;
protected $p4clientSpec;
protected $p4depotType;
protected $p4branch;
11 years ago
protected $process;
11 years ago
public function __construct($repoConfig, $port, $path, ProcessExecutor $process = NULL) {
$this->p4port = $port;
$this->path = $path;
11 years ago
$this->process = $process ? : new ProcessExecutor;
$fs = new Filesystem();
$fs->ensureDirectoryExists($path);
11 years ago
if (isset($repoConfig['depot'])) {
$this->p4depot = $repoConfig['depot'];
}
if (isset($repoConfig['branch'])) {
$this->p4branch = $repoConfig['branch'];
}
if (isset($repoConfig['p4user'])) {
$this->p4user = $repoConfig['p4user'];
}
else {
$this->p4user = $this->getP4variable("P4USER");
}
11 years ago
if (isset($repoConfig['p4password'])) {
$this->p4password = $repoConfig['p4password'];
}
}
11 years ago
protected function getRandomValue() {
return mt_rand(1000, 9999);
}
11 years ago
protected function isWindows(){
return defined('PHP_WINDOWS_VERSION_BUILD');
}
11 years ago
protected function executeCommand($command) {
$result = "";
$this->process->execute($command, $result);
return $result;
}
protected function getClient() {
if (!isset($this->p4client)) {
$random_value = $this->getRandomValue();
$clean_stream_name = str_replace("@", "", str_replace("/", "_", str_replace("//", "", $this->getStream())));
$this->p4client = "composer_perforce_" . $random_value . "_" . $clean_stream_name;
}
11 years ago
return $this->p4client;
}
11 years ago
protected function getPath() {
return $this->path;
}
11 years ago
protected function getPort() {
return $this->p4port;
}
11 years ago
protected function isStream() {
return (strcmp($this->p4depotType, "stream") === 0);
}
11 years ago
protected function getStream() {
if (!isset($this->p4stream)) {
if ($this->isStream()) {
$this->p4stream = "//$this->p4depot/$this->p4branch";
11 years ago
}
else {
$this->p4stream = "//$this->p4depot";
}
}
11 years ago
return $this->p4stream;
}
11 years ago
protected function getStreamWithoutLabel() {
$stream = $this->getStream();
$index = strpos($stream, "@");
11 years ago
if ($index === FALSE) {
return $stream;
}
11 years ago
return substr($stream, 0, $index);
}
11 years ago
protected function getP4ClientSpec() {
$p4clientSpec = $this->path . "/" . $this->getClient() . ".p4.spec";
11 years ago
return $p4clientSpec;
}
public function getUser() {
return $this->p4user;
}
11 years ago
public function queryP4User(IOInterface $io) {
$this->getUser();
11 years ago
if (strlen($this->p4user) > 0) {
return;
}
$this->p4user = $this->getP4variable("P4USER");
if (strlen($this->p4user) > 0) {
return;
}
$this->p4user = $io->ask("Enter P4 User:");
if ($this->isWindows()) {
$command = "p4 set P4USER=$this->p4user";
}
else {
$command = "export P4USER=$this->p4user";
}
11 years ago
$result = $this->executeCommand($command);
}
11 years ago
protected function getP4variable($name) {
if ($this->isWindows()) {
$command = "p4 set";
$result = $this->executeCommand($command);
$resArray = explode("\n", $result);
foreach ($resArray as $line) {
$fields = explode("=", $line);
11 years ago
if (strcmp($name, $fields[0]) == 0) {
$index = strpos($fields[1], " ");
11 years ago
if ($index === FALSE) {
$value = $fields[1];
11 years ago
}
else {
$value = substr($fields[1], 0, $index);
}
$value = trim($value);
11 years ago
return $value;
}
}
11 years ago
}
else {
$command = 'echo $' . $name;
$result = trim($this->executeCommand($command));
11 years ago
return $result;
}
}
11 years ago
protected function queryP4Password(IOInterface $io) {
11 years ago
if (isset($this->p4password)) {
return $this->p4password;
}
11 years ago
$password = $this->getP4variable("P4PASSWD");
if (strlen($password) <= 0) {
$password = $io->askAndHideAnswer("Enter password for Perforce user " . $this->getUser() . ": ");
}
$this->p4password = $password;
11 years ago
return $password;
}
11 years ago
protected function generateP4Command($command, $useClient = TRUE) {
$p4Command = "p4 ";
$p4Command = $p4Command . "-u " . $this->getUser() . " ";
11 years ago
if ($useClient) {
$p4Command = $p4Command . "-c " . $this->getClient() . " ";
}
$p4Command = $p4Command . "-p " . $this->getPort() . " ";
$p4Command = $p4Command . $command;
11 years ago
return $p4Command;
}
11 years ago
protected function isLoggedIn() {
$command = $this->generateP4Command("login -s", FALSE);
$result = trim($this->executeCommand($command));
$index = strpos($result, $this->getUser());
11 years ago
if ($index === FALSE) {
return FALSE;
}
11 years ago
11 years ago
return TRUE;
}
11 years ago
public function setStream($stream) {
$this->p4stream = $stream;
$this->p4depotType = "stream";
}
11 years ago
public function connectClient() {
$p4CreateClientCommand = $this->generateP4Command("client -i < " . $this->getP4ClientSpec());
$this->executeCommand($p4CreateClientCommand);
}
11 years ago
public function syncCodeBase($label) {
$prevDir = getcwd();
chdir($this->path);
11 years ago
$this->executeCommand("pwd");
11 years ago
$p4SyncCommand = $this->generateP4Command("sync -f ");
if (isset($label)) {
if (strcmp($label, "dev-master") != 0) {
$p4SyncCommand = $p4SyncCommand . "@" . $label;
}
}
11 years ago
$this->executeCommand($p4SyncCommand);
chdir($prevDir);
}
11 years ago
protected function writeClientSpecToFile($spec) {
fwrite($spec, "Client: " . $this->getClient() . "\n\n");
fwrite($spec, "Update: " . date("Y/m/d H:i:s") . "\n\n");
fwrite($spec, "Access: " . date("Y/m/d H:i:s") . "\n");
fwrite($spec, "Owner: " . $this->getUser() . "\n\n");
fwrite($spec, "Description:\n");
fwrite($spec, " Created by " . $this->getUser() . " from composer.\n\n");
fwrite($spec, "Root: " . $this->getPath() . "\n\n");
fwrite($spec, "Options: noallwrite noclobber nocompress unlocked modtime rmdir\n\n");
fwrite($spec, "SubmitOptions: revertunchanged\n\n");
fwrite($spec, "LineEnd: local\n\n");
if ($this->isStream()) {
fwrite($spec, "Stream:\n");
fwrite($spec, " " . $this->getStreamWithoutLabel() . "\n");
}
else {
fwrite(
$spec, "View: " . $this->getStream() . "/... //" . $this->getClient() . "/" . str_replace(
"//", "", $this->getStream()
) . "/... \n"
);
}
}
public function writeP4ClientSpec() {
$spec = fopen($this->getP4ClientSpec(), 'w');
try {
11 years ago
$this->writeClientSpecToFile($spec);
} catch (Exception $e) {
fclose($spec);
throw $e;
}
fclose($spec);
}
11 years ago
11 years ago
protected function read($pipe, $name) {
11 years ago
if (feof($pipe)) {
return;
}
$line = fgets($pipe);
11 years ago
while ($line != FALSE) {
11 years ago
$line = fgets($pipe);
}
11 years ago
11 years ago
return;
}
11 years ago
public function windowsLogin($password) {
11 years ago
$descriptorspec = array(
0 => array("pipe", "r"),
1 => array("pipe", "w"),
2 => array("pipe", "a")
);
$command = $this->generateP4Command(" login -a");
$process = proc_open($command, $descriptorspec, $pipes);
11 years ago
if (!is_resource($process)) {
return FALSE;
}
11 years ago
fwrite($pipes[0], $password);
fclose($pipes[0]);
$this->read($pipes[1], "Output");
$this->read($pipes[2], "Error");
fclose($pipes[1]);
fclose($pipes[2]);
$return_code = proc_close($process);
return $return_code;
}
11 years ago
public function p4Login(IOInterface $io) {
$this->queryP4User($io);
11 years ago
if (!$this->isLoggedIn()) {
$password = $this->queryP4Password($io);
11 years ago
if ($this->isWindows()) {
11 years ago
$this->windowsLogin($password);
11 years ago
}
else {
$command = "echo $password | " . $this->generateP4Command(" login -a", FALSE);
11 years ago
$this->executeCommand($command);
}
}
}
11 years ago
public static function checkServerExists($url, ProcessExecutor $process_executor) {
$process = $process_executor ? : new ProcessExecutor;
$result = "";
$process->execute("p4 -p $url info -s", $result);
$index = strpos($result, "error");
11 years ago
if ($index === FALSE) {
return TRUE;
}
11 years ago
return FALSE;
}
11 years ago
public function getComposerInformation($identifier) {
$index = strpos($identifier, "@");
11 years ago
if ($index === FALSE) {
$composer_json = "$identifier/composer.json";
return $this->getComposerInformationFromPath($composer_json);
11 years ago
}
else {
return $this->getComposerInformationFromLabel($identifier, $index);
}
}
11 years ago
public function getComposerInformationFromPath($composer_json) {
$command = $this->generateP4Command(" print $composer_json");
$result = $this->executeCommand($command);
$index = strpos($result, "{");
11 years ago
if ($index === FALSE) {
return "";
}
11 years ago
if ($index >= 0) {
$rawData = substr($result, $index);
11 years ago
$composer_info = json_decode($rawData, TRUE);
return $composer_info;
}
11 years ago
return "";
}
11 years ago
public function getComposerInformationFromLabel($identifier, $index) {
$composer_json_path = substr($identifier, 0, $index) . "/composer.json" . substr($identifier, $index);
11 years ago
$command = $this->generateP4Command(" files $composer_json_path", FALSE);
$result = $this->executeCommand($command);
$index2 = strpos($result, "no such file(s).");
11 years ago
if ($index2 === FALSE) {
$index3 = strpos($result, "change");
11 years ago
if (!($index3 === FALSE)) {
$phrase = trim(substr($result, $index3));
$fields = explode(" ", $phrase);
$id = $fields[1];
$composer_json = substr($identifier, 0, $index) . "/composer.json@" . $id;
11 years ago
return $this->getComposerInformationFromPath($composer_json);
}
}
11 years ago
return "";
}
11 years ago
public function getBranches() {
$possible_branches = array();
11 years ago
if (!$this->isStream()) {
$possible_branches[$this->p4branch] = $this->getStream();
}
else {
$command = $this->generateP4Command("streams //$this->p4depot/...");
11 years ago
$result = "";
$this->process->execute($command, $result);
$resArray = explode("\n", $result);
11 years ago
foreach ($resArray as $line) {
$resBits = explode(" ", $line);
11 years ago
if (count($resBits) > 4) {
$branch = preg_replace("/[^A-Za-z0-9 ]/", '', $resBits[4]);
$possible_branches[$branch] = $resBits[1];
}
}
}
$branches = array();
$branches['master'] = $possible_branches[$this->p4branch];
11 years ago
return $branches;
}
11 years ago
public function getTags() {
$command = $this->generateP4Command("labels");
11 years ago
$result = $this->executeCommand($command);
$resArray = explode("\n", $result);
$tags = array();
11 years ago
foreach ($resArray as $line) {
$index = strpos($line, "Label");
11 years ago
if (!($index === FALSE)) {
$fields = explode(" ", $line);
11 years ago
$tags[$fields[1]] = $this->getStream() . "@" . $fields[1];
}
}
11 years ago
return $tags;
}
11 years ago
public function checkStream() {
$command = $this->generateP4Command("depots", FALSE);
$result = $this->executeCommand($command);
$resArray = explode("\n", $result);
11 years ago
foreach ($resArray as $line) {
$index = strpos($line, "Depot");
11 years ago
if (!($index === FALSE)) {
$fields = explode(" ", $line);
11 years ago
if (strcmp($this->p4depot, $fields[1]) === 0) {
$this->p4depotType = $fields[3];
11 years ago
return $this->isStream();
}
}
}
11 years ago
return FALSE;
}
protected function getChangeList($reference){
$index = strpos($reference, "@");
if ($index === false){
return;
}
$label = substr($reference, $index);
$command = $this->generateP4Command(" changes -m1 $label");
$changes = $this->executeCommand($command);
if (strpos($changes, "Change") !== 0){
return;
}
$fields = explode(" ", $changes);
$changeList = $fields[1];
return $changeList;
}
public function getCommitLogs($fromReference, $toReference){
$fromChangeList = $this->getChangeList($fromReference);
if ($fromChangeList == null){
return;
}
$toChangeList = $this->getChangeList($toReference);
if ($toChangeList == null){
return;
}
$index = strpos($fromReference, "@");
$main = substr($fromReference, 0, $index) . "/...";
$command = $this->generateP4Command("filelog $main@$fromChangeList,$toChangeList");
$result = $this->executeCommand($command);
return $result;
}
}