MediaWiki REL1_33
GitInfo.php
Go to the documentation of this file.
1<?php
27
28class GitInfo {
29
33 protected static $repo = null;
34
38 protected $basedir;
39
43 protected $repoDir;
44
48 protected $cacheFile;
49
53 protected $cache = [];
54
58 private static $viewers = false;
59
65 public function __construct( $repoDir, $usePrecomputed = true ) {
66 $this->repoDir = $repoDir;
67 $this->cacheFile = self::getCacheFilePath( $repoDir );
68 wfDebugLog( 'gitinfo',
69 "Computed cacheFile={$this->cacheFile} for {$repoDir}"
70 );
71 if ( $usePrecomputed &&
72 $this->cacheFile !== null &&
73 is_readable( $this->cacheFile )
74 ) {
75 $this->cache = FormatJson::decode(
76 file_get_contents( $this->cacheFile ),
77 true
78 );
79 wfDebugLog( 'gitinfo', "Loaded git data from cache for {$repoDir}" );
80 }
81
82 if ( !$this->cacheIsComplete() ) {
83 wfDebugLog( 'gitinfo', "Cache incomplete for {$repoDir}" );
84 $this->basedir = $repoDir . DIRECTORY_SEPARATOR . '.git';
85 if ( is_readable( $this->basedir ) && !is_dir( $this->basedir ) ) {
86 $GITfile = file_get_contents( $this->basedir );
87 if ( strlen( $GITfile ) > 8 &&
88 substr( $GITfile, 0, 8 ) === 'gitdir: '
89 ) {
90 $path = rtrim( substr( $GITfile, 8 ), "\r\n" );
91 if ( $path[0] === '/' || substr( $path, 1, 1 ) === ':' ) {
92 // Path from GITfile is absolute
93 $this->basedir = $path;
94 } else {
95 $this->basedir = $repoDir . DIRECTORY_SEPARATOR . $path;
96 }
97 }
98 }
99 }
100 }
101
110 protected static function getCacheFilePath( $repoDir ) {
112
114 // Convert both $IP and $repoDir to canonical paths to protect against
115 // $IP having changed between the settings files and runtime.
116 $realIP = realpath( $IP );
117 $repoName = realpath( $repoDir );
118 if ( $repoName === false ) {
119 // Unit tests use fake path names
120 $repoName = $repoDir;
121 }
122 if ( strpos( $repoName, $realIP ) === 0 ) {
123 // Strip $IP from path
124 $repoName = substr( $repoName, strlen( $realIP ) );
125 }
126 // Transform path to git repo to something we can safely embed in
127 // a filename
128 $repoName = strtr( $repoName, DIRECTORY_SEPARATOR, '-' );
129 $fileName = 'info' . $repoName . '.json';
130 $cachePath = "{$wgGitInfoCacheDirectory}/{$fileName}";
131 if ( is_readable( $cachePath ) ) {
132 return $cachePath;
133 }
134 }
135
136 return "$repoDir/gitinfo.json";
137 }
138
144 public static function repo() {
145 if ( is_null( self::$repo ) ) {
146 global $IP;
147 self::$repo = new self( $IP );
148 }
149 return self::$repo;
150 }
151
158 public static function isSHA1( $str ) {
159 return (bool)preg_match( '/^[0-9A-F]{40}$/i', $str );
160 }
161
167 public function getHead() {
168 if ( !isset( $this->cache['head'] ) ) {
169 $headFile = "{$this->basedir}/HEAD";
170 $head = false;
171
172 if ( is_readable( $headFile ) ) {
173 $head = file_get_contents( $headFile );
174
175 if ( preg_match( "/ref: (.*)/", $head, $m ) ) {
176 $head = rtrim( $m[1] );
177 } else {
178 $head = rtrim( $head );
179 }
180 }
181 $this->cache['head'] = $head;
182 }
183 return $this->cache['head'];
184 }
185
191 public function getHeadSHA1() {
192 if ( !isset( $this->cache['headSHA1'] ) ) {
193 $head = $this->getHead();
194 $sha1 = false;
195
196 // If detached HEAD may be a SHA1
197 if ( self::isSHA1( $head ) ) {
198 $sha1 = $head;
199 } else {
200 // If not a SHA1 it may be a ref:
201 $refFile = "{$this->basedir}/{$head}";
202 $packedRefs = "{$this->basedir}/packed-refs";
203 $headRegex = preg_quote( $head, '/' );
204 if ( is_readable( $refFile ) ) {
205 $sha1 = rtrim( file_get_contents( $refFile ) );
206 } elseif ( is_readable( $packedRefs ) &&
207 preg_match( "/^([0-9A-Fa-f]{40}) $headRegex$/m", file_get_contents( $packedRefs ), $matches )
208 ) {
209 $sha1 = $matches[1];
210 }
211 }
212 $this->cache['headSHA1'] = $sha1;
213 }
214 return $this->cache['headSHA1'];
215 }
216
223 public function getHeadCommitDate() {
224 global $wgGitBin;
225
226 if ( !isset( $this->cache['headCommitDate'] ) ) {
227 $date = false;
228 if ( is_file( $wgGitBin ) &&
230 !Shell::isDisabled() &&
231 $this->getHead() !== false
232 ) {
233 $cmd = [
234 $wgGitBin,
235 'show',
236 '-s',
237 '--format=format:%ct',
238 'HEAD',
239 ];
240 $gitDir = realpath( $this->basedir );
241 $result = Shell::command( $cmd )
242 ->environment( [ 'GIT_DIR' => $gitDir ] )
243 ->restrict( Shell::RESTRICT_DEFAULT | Shell::NO_NETWORK )
244 ->whitelistPaths( [ $gitDir, $this->repoDir ] )
245 ->execute();
246
247 if ( $result->getExitCode() === 0 ) {
248 $date = (int)$result->getStdout();
249 }
250 }
251 $this->cache['headCommitDate'] = $date;
252 }
253 return $this->cache['headCommitDate'];
254 }
255
261 public function getCurrentBranch() {
262 if ( !isset( $this->cache['branch'] ) ) {
263 $branch = $this->getHead();
264 if ( $branch &&
265 preg_match( "#^refs/heads/(.*)$#", $branch, $m )
266 ) {
267 $branch = $m[1];
268 }
269 $this->cache['branch'] = $branch;
270 }
271 return $this->cache['branch'];
272 }
273
279 public function getHeadViewUrl() {
280 $url = $this->getRemoteUrl();
281 if ( $url === false ) {
282 return false;
283 }
284 foreach ( self::getViewers() as $repo => $viewer ) {
285 $pattern = '#^' . $repo . '$#';
286 if ( preg_match( $pattern, $url, $matches ) ) {
287 $viewerUrl = preg_replace( $pattern, $viewer, $url );
288 $headSHA1 = $this->getHeadSHA1();
289 $replacements = [
290 '%h' => substr( $headSHA1, 0, 7 ),
291 '%H' => $headSHA1,
292 '%r' => urlencode( $matches[1] ),
293 '%R' => $matches[1],
294 ];
295 return strtr( $viewerUrl, $replacements );
296 }
297 }
298 return false;
299 }
300
305 protected function getRemoteUrl() {
306 if ( !isset( $this->cache['remoteURL'] ) ) {
307 $config = "{$this->basedir}/config";
308 $url = false;
309 if ( is_readable( $config ) ) {
311 $configArray = parse_ini_file( $config, true );
313 $remote = false;
314
315 // Use the "origin" remote repo if available or any other repo if not.
316 if ( isset( $configArray['remote origin'] ) ) {
317 $remote = $configArray['remote origin'];
318 } elseif ( is_array( $configArray ) ) {
319 foreach ( $configArray as $sectionName => $sectionConf ) {
320 if ( substr( $sectionName, 0, 6 ) == 'remote' ) {
321 $remote = $sectionConf;
322 }
323 }
324 }
325
326 if ( $remote !== false && isset( $remote['url'] ) ) {
327 $url = $remote['url'];
328 }
329 }
330 $this->cache['remoteURL'] = $url;
331 }
332 return $this->cache['remoteURL'];
333 }
334
344 public function cacheIsComplete() {
345 return isset( $this->cache['head'] ) &&
346 isset( $this->cache['headSHA1'] ) &&
347 isset( $this->cache['headCommitDate'] ) &&
348 isset( $this->cache['branch'] ) &&
349 isset( $this->cache['remoteURL'] );
350 }
351
361 public function precomputeValues() {
362 if ( $this->cacheFile !== null ) {
363 // Try to completely populate the cache
364 $this->getHead();
365 $this->getHeadSHA1();
366 $this->getHeadCommitDate();
367 $this->getCurrentBranch();
368 $this->getRemoteUrl();
369
370 if ( !$this->cacheIsComplete() ) {
371 wfDebugLog( 'gitinfo',
372 "Failed to compute GitInfo for \"{$this->basedir}\""
373 );
374 return;
375 }
376
377 $cacheDir = dirname( $this->cacheFile );
378 if ( !file_exists( $cacheDir ) &&
379 !wfMkdirParents( $cacheDir, null, __METHOD__ )
380 ) {
381 throw new MWException( "Unable to create GitInfo cache \"{$cacheDir}\"" );
382 }
383
384 file_put_contents( $this->cacheFile, FormatJson::encode( $this->cache ) );
385 }
386 }
387
392 public static function headSHA1() {
393 return self::repo()->getHeadSHA1();
394 }
395
400 public static function currentBranch() {
401 return self::repo()->getCurrentBranch();
402 }
403
408 public static function headViewUrl() {
409 return self::repo()->getHeadViewUrl();
410 }
411
416 protected static function getViewers() {
418
419 if ( self::$viewers === false ) {
420 self::$viewers = $wgGitRepositoryViewers;
421 Hooks::run( 'GitViewers', [ &self::$viewers ] );
422 }
423
424 return self::$viewers;
425 }
426}
and that you know you can do these things To protect your we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights These restrictions translate to certain responsibilities for you if you distribute copies of the or if you modify it For if you distribute copies of such a whether gratis or for a you must give the recipients all the rights that you have You must make sure that receive or can get the source code And you must show them these terms so they know their rights We protect your rights with two and(2) offer you this license which gives you legal permission to copy
$wgGitRepositoryViewers
Map GIT repository URLs to viewer URLs to provide links in Special:Version.
$wgGitInfoCacheDirectory
Directory where GitInfo will look for pre-computed cache files.
$wgGitBin
Fully specified path to git binary.
wfDebugLog( $logGroup, $text, $dest='all', array $context=[])
Send a line to a supplementary debug log file, if configured, or main debug log if not.
wfMkdirParents( $dir, $mode=null, $caller=null)
Make directory, and make all parent directories if they don't exist.
static repo()
Get the singleton for the repo at $IP.
Definition GitInfo.php:144
getHead()
Get the HEAD of the repo (without any opening "ref: ")
Definition GitInfo.php:167
static getCacheFilePath( $repoDir)
Compute the path to the cache file for a given directory.
Definition GitInfo.php:110
static array false $viewers
Map of repo URLs to viewer URLs.
Definition GitInfo.php:58
$cacheFile
Path to JSON cache file for pre-computed git information.
Definition GitInfo.php:48
$basedir
Location of the .git directory.
Definition GitInfo.php:38
getRemoteUrl()
Get the URL of the remote origin.
Definition GitInfo.php:305
static headSHA1()
Definition GitInfo.php:392
getHeadCommitDate()
Get the commit date of HEAD entry of the git code repository.
Definition GitInfo.php:223
static headViewUrl()
Definition GitInfo.php:408
precomputeValues()
Precompute and cache git information.
Definition GitInfo.php:361
$cache
Cached git information.
Definition GitInfo.php:53
cacheIsComplete()
Check to see if the current cache is fully populated.
Definition GitInfo.php:344
static $repo
Singleton for the repo at $IP.
Definition GitInfo.php:33
$repoDir
Location of the repository.
Definition GitInfo.php:43
static currentBranch()
Definition GitInfo.php:400
getHeadViewUrl()
Get an URL to a web viewer link to the HEAD revision.
Definition GitInfo.php:279
__construct( $repoDir, $usePrecomputed=true)
Definition GitInfo.php:65
static isSHA1( $str)
Check if a string looks like a hex encoded SHA1 hash.
Definition GitInfo.php:158
getHeadSHA1()
Get the SHA1 for the current HEAD of the repo.
Definition GitInfo.php:191
getCurrentBranch()
Get the name of the current branch, or HEAD if not found.
Definition GitInfo.php:261
static getViewers()
Gets the list of repository viewers.
Definition GitInfo.php:416
MediaWiki exception.
Executes shell commands.
Definition Shell.php:44
$IP
Definition update.php:3
you have access to all of the normal MediaWiki so you can get a DB use the cache
The wiki should then use memcached to cache various data To use multiple just add more items to the array To increase the weight of a make its entry a array("192.168.0.1:11211", 2))