'Perforce',
'url' => 'http://public.perforce.com/wiki/index.php/Perforce_%28MediaWiki_parser_hook%29',
'author' => 'Matt Attaway and Sam Stafford',
'description' => 'Display Perforce data in wiki pages',
);
function perforceExtension()
{
global $wgParser;
$wgParser->setHook( 'changelist', 'renderChangelist' );
$wgParser->setHook( 'recentchanges', 'tagP4Changes' );
$wgParser->setHook( 'p4variants', 'tagP4Variants' );
$wgParser->setFunctionHook( 'p4changes', 'runP4Changes' );
}
function wfPerforceLanguageGetMagic( &$magicWords, $langCode = "en" )
{
switch( $langCode )
{
default:
$magicWords['p4changes'] = array ( 0, 'p4changes' );
}
return true;
}
function wfPerforceParserOutput( &$outputPage, &$parserOutput )
{
if ( !empty( $parserOutput->mPerforceJavascriptTag ) )
{
global $wgJsMimeType, $wgScriptPath;
$outputPage->addScript(
"\n"
);
}
return true;
}
# {{#p4changes:num|path|brief/long/full|user}}
function runP4Changes( &$parser, $num = '', $path = '', $desc = '', $user = '' )
{
$argv['num'] = $num;
$argv['path'] = $path;
$argv['desc'] = $desc;
$argv['user'] = $user;
return renderRecentChanges( '', $argv, $parser, 'wiki' );
}
function tagP4Changes( $input, $argv, &$parser )
{
return renderRecentChanges( $input, $argv, $parser, 'html' );
}
function tagP4Variants( $input, $argv, &$parser )
{
global $wgUseAjax, $wgScriptPath;
if ( !$wgUseAjax )
return "This MediaWiki instance does not support Ajax.";
$parser->mOutput->mPerforceJavascriptTag = true; # flag for use by wfPerforceParserOutput
$path = $argv["path"];
if( $path == '' )
return "Please provide a depot path (path attribute).";
$nocache = time();
$html = '';
$html .= '
';
$html .= '
';
$html .= renderPerforcePathLink( $path, TRUE );
$html .= '
[';
$html .= 'addText( getP4Variants( $path ) );
return getP4Variants( $path );
return $response;
}
function renderChangelist( $input, $argv, &$parser )
{
global $wgP4EXEC;
global $wgP4PORT;
global $wgP4USER;
global $wgP4PASSWD;
global $wgP4WEBURL;
if( $argv["style"] )
{
$range = '@' . $input . ',' . $input;
$cmdline = wfEscapeShellArg( $wgP4EXEC ) .
" -u " . wfEscapeShellArg( $wgP4USER ) .
" -p " . wfEscapeShellArg( $wgP4PORT );
if( $wgP4PASSWD != "" )
$cmdline .= " -P " . wfEscapeShellArg( $wgP4PASSWD );
$cmdline .= " changes " . wfEscapeShellArg( $range );
$text = `{$cmdline}`;
return formatShortChange( $text );
}
else
return "" . $input . "";
}
function renderRecentchanges( $input, $argv, &$parser, $format )
{
$parser->disableCache();
global $wgP4EXEC;
global $wgP4PORT;
global $wgP4USER;
global $wgP4PASSWD;
$path = $argv["path"];
$num = $argv["num"];
$desc = $argv["desc"];
$user = $argv["user"];
if( $path == "" || $num == "" )
return "Please provide both a depot path(path attribute) and the number of changes to show(num attribute).";
$arg = $path . '@' . $change;
$cmdline = $wgP4EXEC .
" -u " . $wgP4USER .
" -p " . $wgP4PORT ;
if( $wgP4PASSWD != "" )
$cmdline .= " -P " . $wgP4PASSWD ;
$cmdline .= " changes -m" . escapeshellarg( $num ) . " ";
if ( $desc == "long" )
$cmdline .= "-L ";
if ( $desc == "full" )
$cmdline .= "-l ";
if ( $user != "" )
$cmdline .= "-u " . escapeshellarg( $user ) . " ";
$cmdline .= escapeshellarg( $path );
$cmdline .= ' 2>&1';
$changes = array();
exec( $cmdline, $changes );
$isDarkStripe = true;
$output .= "";
$inList = false;
$inListList = false;
foreach( $changes as $value )
{
if ( !preg_match( '/^Change [0-9]+ on/', $value ) )
{
if ( !$inListList )
{
$output .= '';
$inListList = true;
}
$output .= htmlspecialchars( $value );
if ( $value )
$output .= '
';
continue;
}
if ( $inListList )
{
$output .= '
';
$inListList = false;
}
if ( $inList )
{
$output .= "\n";
$inList = false;
}
if( $isDarkStripe )
$output .= "- ";
else
$output .= "
- ";
$inList = true;
$output .= formatShortChange( $value, $format );
$isDarkStripe = !$isDarkStripe;
}
if ( $inListList )
{
$output .= '
';
$inListList = false;
}
if ( $inList )
{
$output .= "\n";
$inList = false;
}
$output .= "";
return $output;
}
function formatShortChange( $text, $format='html', $newwin=FALSE )
{
global $wgP4WEBURL;
$target = '';
if ( $newwin )
$target = 'target="_blank" ';
$pattern[0] = '/Change (\d+) /';
$pattern[1] = '/ (\S+)@(\S+)/';
switch( $format )
{
default:
case 'html':
$replacement[0] = 'Change ${1} ';
$replacement[1] = ' ${1}@${2} ';
break;
case 'wiki':
$replacement[0] = 'Change [' . $wgP4WEBURL . '${1}?ac=10 ${1}] ';
$replacement[1] = ' [' . $wgP4WEBURL . '${1}?ac=17 ${1}]@[' . $wgP4WEBURL . '${2}?ac=15 ${2}] ';
break;
}
return preg_replace( $pattern, $replacement, $text );
}
function renderPerforcePathLink( $path, $newwin=FALSE )
{
global $wgP4WEBURL;
$target = '';
$ac = 22;
if ( ( strpos( $path, '...' ) !== FALSE ) || ( strpos( $path, '*' ) !== FALSE ) )
$ac = 69;
if ( $newwin )
$target = 'target="_blank" ';
return ''.$path.'';
}
function getP4Variants( $path )
{
global $wgP4EXEC;
global $wgP4PORT;
global $wgP4USER;
global $wgP4CLIENT;
global $wgP4PASSWD;
$path = trim( $path );
if ( substr( $path, -1 ) == '/' )
{
$path .= '...';
}
$html = '';
$p4Cmd = $wgP4EXEC .
" -u " . $wgP4USER .
" -p " . $wgP4PORT .
" -c " . $wgP4CLIENT;
if( $wgP4PASSWD != "" )
$p4Cmd .= " -P " . $wgP4PASSWD;
#Infer branch relationships from integed output.
$toFile = '';
$fromFile = '';
$pleft = $path;
$pwild = '';
$pright = '';
if ( substr( $path, -1 ) == '*' )
{
$pleft = substr( $path, 0, -1 );
$pwild = substr( $path, -1 );
}
if ( substr( $path, -3 ) == '...' )
{
$pleft = substr( $path, 0, -3 );
$pwild = substr( $path, -3 );
}
$pllen = strlen( $pleft );
$prlen = strlen( $pright );
if ( ( strpos( $pleft, '...' ) !== FALSE ) || ( strpos( $pleft, '*' ) !== FALSE ) )
return 'Embedded wildcard in '.$path.' -- unable to figure out branch relationships.';
$cmdline = $p4Cmd . ' -Ztag integrated ' . escapeshellarg( $path );
$integs = array();
$branches = array();
exec( $cmdline, $integs );
foreach( $integs as $line )
{
if ( substr( $line, 0, 11 ) == '... toFile ' ) $toFile = substr( $line, 11 );
if ( substr( $line, 0, 13 ) == '... fromFile ' ) $fromFile = substr( $line, 13 );
if ( $toFile && $fromFile )
{
#toFile is our path, even if it's really the "from" of the integ. Handy!
if ( substr( $toFile, 0, $pllen ) == $pleft ) #this should always be true
{
$pright = substr( $toFile, $pllen );
$prlen = strlen( $pright );
if ( !$prlen || substr( $fromFile, -$prlen ) == $pright ) #check for a path match
{
if ( $prlen )
$branch = substr( $fromFile, 0, -$prlen ) . $pwild;
else
$branch = $fromFile;
$branches[$branch] = $branch;
}
}
$toFile = '';
$fromFile = '';
}
}
sort ( $branches );
if ( !count( $branches ) )
{
return '';
}
set_time_limit( 300 );
#We now have a list of $branches that each corresponds to $path.
foreach( $branches as $branch )
{
$cmdline = $p4Cmd . ' interchanges ' . escapeshellarg( $branch ) . ' ' . escapeshellarg( $path );
$changes = array();
exec( $cmdline, $changes );
$bvar = FALSE;
foreach( $changes as $change )
{
$cnum = '';
$cnums = array();
if ( preg_match( '/^Change (\d+) /', $change, $cnums ) ) $cnum = $cnums[1];
else continue;
$cvar = FALSE;
$cmdline = $p4Cmd . ' -Ztag integrate -n ' . escapeshellarg( $branch.'@'.$cnum.',@'.$cnum ) . ' ' . escapeshellarg( $path );
$integs = array();
exec( $cmdline, $integs );
foreach( $integs as $integ )
{
if ( $integ == '... action integrate' )
{
$cvar = TRUE;
break;
}
}
if ( $cvar )
{
if ( !$bvar )
{
$bvar = TRUE;
$html .= '- ';
$html .= renderPerforcePathLink( $branch, TRUE );
$html .= '
';
}
$html .= '- ';
$html .= formatShortChange( $change, 'html', TRUE );
$html .= '
';
}
}
if ( $bvar )
{
$html .= '
';
}
}
if ( strpos( $html, '- ' ) === FALSE )
{
$html .= '
- No branches have outstanding changes.
';
}
$html .= '
';
return $html;
}
?>