00001 <?php
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 require_once 'VCS/Spool.php';
00023
00024 require_once 'System.php';
00025
00028 class Diogenes_VCS_RCS extends Diogenes_VCS_Spool {
00030 var $rcsdir;
00031
00033 var $login;
00041 function Diogenes_VCS_RCS(&$caller,$alias,$login,$init = false) {
00042 global $globals;
00043 $this->Diogenes_VCS_Spool($caller,$alias);
00044 $this->rcsdir = "{$globals->rcsroot}/$alias";
00045 $this->login = $login;
00046
00047
00048 if ($init) {
00049 if (!is_dir($this->rcsdir))
00050 mkdir($this->rcsdir, 0700);
00051 if (!is_dir($this->datadir))
00052 mkdir($this->datadir, 0700);
00053 }
00054
00055
00056 if (!is_dir($this->rcsdir) || !is_writable($this->rcsdir))
00057 $this->kill("'{$this->rcsdir}' is not a writable directory");
00058
00059
00060 if (!is_dir($this->datadir) || !is_writable($this->datadir))
00061 $this->kill("'{$this->datadir}' is not a writable directory");
00062 }
00063
00064
00070 function rcsPath($parent="",$entry="") {
00071 $this->checkPath($parent,$entry);
00072 return $this->rcsdir.($parent ? "/$parent": "") . ($entry ? "/$entry" : "");
00073 }
00074
00075
00081 function rcsFile($dir,$file) {
00082 return $this->rcsPath($dir,$file).",v";
00083 }
00084
00085
00091 function checkFile($dir, $file) {
00092 return is_file($this->rcsFile($dir, $file));
00093 }
00094
00095
00101 function checkDir($dir) {
00102 return is_dir($this->rcsPath($dir))
00103 && is_writable($this->rcsPath($dir))
00104 && is_dir($this->spoolPath($dir))
00105 && is_writable($this->spoolPath($dir));
00106 }
00107
00108
00116 function checkout($dir,$file,$rev,$output)
00117 {
00118 $this->info("RCS : checkout out $file ($rev)..");
00119 $rfile = $this->rcsFile($dir,$file);
00120 if ($this->cmdExec("co -q -r".escapeshellarg($rev)." ".escapeshellarg($rfile)." ".escapeshellarg("$output/$file")))
00121 {
00122 $this->info("RCS : Error, checkout failed!");
00123 $this->info($this->cmdStatus());
00124 return;
00125 }
00126 return "$output/$file";
00127 }
00128
00129
00137 function commit($dir,$file,$content,$message="")
00138 {
00139 $this->info("RCS : checking in '$file'..");
00140
00141
00142 if (!$this->checkDir($dir)) {
00143
00144 $this->info("RCS : Error, RCS sanity check for '$dir' failed!");
00145 return false;
00146 }
00147
00148
00149 $this->log("rcs_commit","{$this->alias}:$dir/$file:$message");
00150
00151 $sfile = $this->spoolPath($dir,$file);
00152 $rfile = $this->rcsFile($dir,$file);
00153
00154
00155 if (!file_exists($rfile)) {
00156 if ($this->cmdExec("echo '' | rcs -q -i ".escapeshellarg($rfile)))
00157 {
00158
00159 $this->info("RCS : Error, could not initialise RCS file '$rfile'!");
00160 $this->info($this->cmdStatus());
00161 return false;
00162 }
00163 }
00164
00165
00166 if ($this->cmdExec("co -q -l ".escapeshellarg($rfile)." ".escapeshellarg($sfile)))
00167 {
00168
00169 $this->info("RCS : Error, could not get RCS lock on file '$file'!");
00170 $this->info($this->cmdStatus());
00171 return false;
00172 }
00173 if ($fp = fopen($sfile,"w")) {
00174 fwrite($fp,$content);
00175 fclose($fp);
00176
00177 if ($this->cmdExec("ci -q -w".escapeshellarg($this->login). ($message ? " -m".escapeshellarg($message) : "").
00178 " ". escapeshellarg($sfile). " ". escapeshellarg($rfile)))
00179 {
00180
00181 $this->info("RCS : Error, checkin failed!");
00182 $this->info($this->cmdStatus());
00183 return false;
00184 }
00185
00186 if ($this->cmdExec("co -q ".escapeshellarg($rfile)." ".escapeshellarg($sfile)))
00187 {
00188
00189 $this->info("RCS : Error, checkout after checkin failed!");
00190 $this->info($this->cmdStatus());
00191 return false;
00192 }
00193 }
00194 return true;
00195 }
00196
00197
00198
00206 function copy($sdir,$sfile,$ddir,$dfile)
00207 {
00208 $this->info("RCS : copying '$sfile' to '$ddir/$dfile'..");
00209
00210 $spath = $this->spoolPath($sdir, $sfile);
00211 if (!is_file($spath)) {
00212 $this->info("Error: source file '$spath' does not exist!");
00213 return false;
00214 }
00215 if (!$this->checkDir($ddir))
00216 {
00217 $this->info("Error: directory '$ddir' does not exist!");
00218 return false;
00219 }
00220 if ($this->checkFile($ddir, $dfile))
00221 {
00222 $this->info("Error: file '$dfile' already exists in '$ddir'!");
00223 return false;
00224 }
00225 return $this->commit($ddir,$dfile,
00226 file_get_contents($spath),
00227 "copied from '$ddir/$sfile'");
00228 }
00229
00230
00236 function del($dir,$file) {
00237 $this->info("RCS : deleting '$file'..");
00238 $this->log("rcs_delete","{$this->alias}:$dir/$file");
00239 @unlink($this->spoolPath($dir,$file));
00240 @unlink($this->rcsFile($dir,$file));
00241 }
00242
00243
00251 function diff($dir,$file,$r1,$r2)
00252 {
00253 $rfile = $this->rcsFile($dir,$file);
00254 $this->info("RCS : diffing '$file' ($r1 to $r2)..");
00255 $this->cmdExec("rcsdiff -r".escapeshellarg($r1). " -r".escapeshellarg($r2)." ".escapeshellarg($rfile));
00256 return $this->cmd_output;
00257 }
00258
00259
00267 function importWordFile($dir,$htmlfile,$wordfile)
00268 {
00269 global $globals;
00270
00271 if (!$globals->word_import) {
00272 $this->info("Error : support for word import is disabled!");
00273 return false;
00274 }
00275
00276 $func = "importWordFile_{$globals->word_import}";
00277
00278 if (!method_exists($this, $func))
00279 {
00280 $this->info("Error : the utility '$globals->word_import' is not supported!");
00281 return false;
00282 }
00283
00284 return $this->$func($dir, $htmlfile, $wordfile);
00285 }
00286
00287
00295 function importWordFile_wvHtml($dir,$htmlfile,$wordfile)
00296 {
00297 $tmphtmlfile = "importWord.html";
00298 if (($tmpdir = System::mktemp('-d')) == false) {
00299 $this->info("Error : could not create temporary directory!");
00300 return false;
00301 }
00302
00303 if ($this->cmdExec("wvHtml --targetdir=".escapeshellarg($tmpdir).
00304 " --charset=iso-8859-15 ".
00305 escapeshellarg($wordfile)." ".escapeshellarg($tmphtmlfile)))
00306 {
00307 $this->info("Error : wvHtml returned an error!");
00308 $this->info($this->cmdStatus());
00309 return false;
00310 }
00311
00312 if (!$dh = opendir($tmpdir)) {
00313 $this->info("Error : could not find temporary directory '$tmpdir'!");
00314 return false;
00315 }
00316
00317
00318 $ok = true;
00319 while (($myentry = readdir($dh)) != false) {
00320 if (is_file($myfile = "$tmpdir/$myentry")) {
00321 if ($myentry == $tmphtmlfile) {
00322 $ok = $ok &&
00323 $this->commit($dir,$htmlfile,
00324 $this->importHtmlString(file_get_contents($myfile)),
00325 "Word file import");
00326 } else {
00327 $ok = $ok &&
00328 $this->commit($dir,$myentry,file_get_contents($myfile),
00329 "Word file import");
00330 }
00331 }
00332 }
00333 closedir($dh);
00334
00335 return $ok;
00336 }
00337
00338
00344 function logEntries($dir,$file) {
00345 $rfile = $this->rcsFile($dir,$file);
00346 $this->cmdExec("rlog ".escapeshellarg($rfile));
00347 return $this->cmd_output;
00348 }
00349
00350
00356 function logParse($dir,$file)
00357 {
00358
00359 $lines = $this->logEntries($dir,$file);
00360 array_pop($lines);
00361 array_pop($lines);
00362
00363
00364 $revs = split("----------------------------\n", implode("\n",$lines));
00365 array_shift($revs);
00366
00367
00368 $revinfo = array();
00369 foreach ($revs as $rev) {
00370 $myrev = array();
00371 $lines = explode("\n",$rev);
00372 preg_match("/^revision (.+)$/",array_shift($lines),$res);
00373 $myrev['rev'] = $res[1];
00374 preg_match("/^date: ([^;]+); author: ([^;]+); .*$/",array_shift($lines),$res);
00375 $myrev['date'] = $res[1];
00376 $myrev['author'] = $res[2];
00377 $myrev['log'] = implode("\n",$lines);
00378 array_push($revinfo,$myrev);
00379 }
00380 return $revinfo;
00381 }
00382
00383
00391 function move($sdir,$sfile,$ddir,$dfile)
00392 {
00393 $this->info("RCS : moving '$sfile' to '$ddir/$dfile'..");
00394
00395
00396
00397 $spath = $this->spoolPath($sdir, $sfile);
00398 $srpath = $this->rcsFile($sdir, $sfile);
00399
00400 if (!is_file($spath)) {
00401 $this->info("Error: source file '$spath' does not exist!");
00402 return false;
00403 }
00404
00405 if (!is_file($srpath)) {
00406 $this->info("Error: source RCS file '$srpath' does not exist!");
00407 return false;
00408 }
00409
00410
00411 $dpath = $this->spoolPath($ddir, $dfile);
00412 $drpath = $this->rcsFile($ddir, $dfile);
00413
00414 if (!$this->checkDir($ddir))
00415 {
00416 $this->info("Error: directory '$ddir' does not exist!");
00417 return false;
00418 }
00419
00420 if (file_exists($dpath)) {
00421 $this->info("Error: file '$dfile' already exists in '$ddir'!");
00422 return false;
00423 }
00424
00425 if (file_exists($drpath)) {
00426 $this->info("Error: file '".basename($drpath)."' already exists in '$ddir'!");
00427 return false;
00428 }
00429
00430 if (!rename($spath, $dpath))
00431 {
00432 $this->info("Error: failed to move '".basename($spath)."' to '".basename($dpath)."' in '$ddir'!");
00433 return false;
00434 }
00435
00436 if (!rename($srpath, $drpath))
00437 {
00438 $this->info("Error: failed to move '".basename($srpath)."' to '".basename($drpath)."' in '$ddir'!");
00439 return false;
00440 }
00441
00442
00443
00444
00445 return true;
00446 }
00447
00448
00454 function newdir($parent,$dir)
00455 {
00456 @mkdir($this->rcsPath($parent,$dir),0700);
00457 @mkdir($this->spoolPath($parent,$dir),0700);
00458 }
00459
00460
00468 function dispDiff($dir,$file,$r1,$r2)
00469 {
00470 $lns = "[0-9]+|[0-9]+,[0-9]+";
00471
00472
00473 $lines = $this->diff($dir,$file,$r1,$r2);
00474 $line = "";
00475 while (!preg_match("/^($lns)([acd])($lns)/",$line))
00476 $line = array_shift($lines);
00477 array_unshift($lines,$line);
00478 $raw = implode("\n",$lines);
00479
00480 $blocks = preg_split("/($lns)([acd])($lns)\n/",$raw,-1,PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
00481 $out = array();
00482
00483 $lold = array_shift($blocks);
00484 while ($lold!='')
00485 {
00486 $type = array_shift($blocks);
00487 $lnew = array_shift($blocks);
00488 $diff = array_shift($blocks);
00489
00490 switch ($type) {
00491 case 'c':
00492 list($a,$b) = split("---\n",$diff,2);
00493 break;
00494 case 'a':
00495 $a = "";
00496 $b = $diff;
00497 break;
00498 case 'd':
00499 $a = $diff;
00500 $b = "";
00501 break;
00502 }
00503 array_push($out,array($lold,$type,$lnew,$a,$b));
00504 $lold = array_shift($blocks);
00505 }
00506
00507 return $out;
00508 }
00509
00510
00517 function dispDir($dir,$loc,$canedit) {
00518 $entries = array();
00519
00520 if ($pdir = @opendir($this->rcsPath($dir))) {
00521 while ( ($file = readdir($pdir)) !== false) {
00522 if ( ($file != ".") && ($file != "..") )
00523 {
00524 $entry = $this->dispEntry($dir,$loc,$file,$canedit);
00525 if (!empty($entry))
00526 array_push($entries, $entry);
00527 }
00528 }
00529 closedir($pdir);
00530 }
00531 return $entries;
00532 }
00533
00534
00542 function dispEntry($dir,$loc,$file,$canedit) {
00543 global $globals;
00544
00545 $view = $edit = $del = $size = $rev = "";
00546
00547 $myitem = $this->rcsPath($dir,$file);
00548
00549
00550 if (!file_exists($myitem)) {
00551 $this->info("RCS entry '$myitem' does not exist!");
00552 return;
00553 }
00554
00555 if (is_dir($myitem))
00556 {
00557
00558 $this->info("Unexpected directory in RCS, skipping : '$myitem'");
00559 return;
00560 }
00561 else if (substr($file,-2) == ",v")
00562 {
00563
00564 $file = substr($file,0,-2);
00565
00566
00567 $spoolitem = $this->spoolPath($dir,$file);
00568 if (!is_file($spoolitem))
00569 {
00570 $this->info("Could not find working copy '$spoolitem'!");
00571 $size = "";
00572 $icon = "";
00573 } else {
00574 $size = $this->dispSize(filesize($spoolitem));
00575 $icon = $globals->icons->get_mime_icon($spoolitem);
00576 }
00577
00578
00579 $myrev = array_shift($tmparr = $this->logParse($dir,$file));
00580
00581 return array(
00582 "icon" => $icon,
00583 "file" => $file,
00584 "rev" => array($myrev['rev'],$rev),
00585 "date" => $myrev['date'],
00586 "author" => $myrev['author'],
00587 "size" => $size
00588 );
00589
00590 }
00591 else
00592 {
00593 $this->info("Unknown RCS entry type : '$myitem'");
00594 return;
00595 }
00596
00597 }
00598
00599
00604 function dispSize($size)
00605 {
00606 if ($size < 1000)
00607 return "$size B";
00608 else if ($size < 1000000)
00609 return floor($size/1000)." kB";
00610 else
00611 return floor($size/1000000)." MB";
00612 }
00613
00614 }
00615
00616 ?>