'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( 'p4change', 'renderChangelist' ); $wgParser->setHook( 'p4changes', 'tagP4Changes' ); $wgParser->setHook( 'p4variants', 'tagP4Variants' ); $wgParser->setFunctionHook( 'p4changes', 'runP4Changes' ); $wgParser->setFunctionHook( 'p4variants', 'parseP4Variants' ); } function wfPerforceLanguageGetMagic( &$magicWords, $langCode = "en" ) { switch( $langCode ) { default: $magicWords['p4changes'] = array ( 0, 'p4changes' ); $magicWords['p4variants'] = array ( 0, 'p4variants' ); } 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' ); } # {{#p4variants:path}} function parseP4Variants( &$parser, $path = '' ) { return ''; } 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 "" . htmlspecialchars( $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 ''.htmlspecialchars( $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 '.htmlspecialchars( $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 '
      No branches found.
    '; } 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; } ?>