Skip to content

Commit df44b2d

Browse files
authored
Rewrite and document git log parsing (#180)
1 parent ed660d4 commit df44b2d

File tree

7 files changed

+245
-54
lines changed

7 files changed

+245
-54
lines changed

scripts/translation/genrevdb.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,8 @@ function generate( SQLite3 $db , string $lang )
112112
}
113113
catch ( Exception $e )
114114
{
115-
$db->exec( 'ROLLBACK TRANSACTION' );
116115
consolelog( "Throw: " . $e->getMessage() );
116+
$db->exec( 'ROLLBACK TRANSACTION' );
117117
exit;
118118
}
119119
}

scripts/translation/lib/GitDiffParser.php

Lines changed: 0 additions & 48 deletions
This file was deleted.

scripts/translation/lib/GitLogParser.php

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,140 @@ static function parseInto( string $lang , RevcheckFileList & $list )
8989

9090
pclose( $fp );
9191
}
92+
93+
static function parseDir( string $gdir , RevcheckFileList $list )
94+
{
95+
$gdir = escapeshellarg( $gdir );
96+
$proc = new GitLogParserProc( "git -C $gdir log --name-only" );
97+
98+
$hash = "";
99+
$date = "";
100+
$skip = false;
101+
$lcnt = 0;
102+
103+
while ( $proc->live )
104+
{
105+
// Hash
106+
107+
if ( str_starts_with( $proc->line , "commit " ) )
108+
{
109+
$hash = trim( substr( $proc->line , 7 ) );
110+
$date = "";
111+
$skip = false;
112+
$lcnt = 0;
113+
$proc->next();
114+
}
115+
else
116+
throw new Exception( "Expected commit hash." );
117+
118+
// Headers
119+
120+
while ( $proc->live && strlen( trim( $proc->line ) ) > 0 )
121+
{
122+
// Date
123+
if ( str_starts_with( $proc->line , 'Date:' ) )
124+
{
125+
$line = trim( substr( $proc->line , 5 ) );
126+
$date = strtotime( $line );
127+
$proc->next();
128+
continue;
129+
}
130+
// Other headers
131+
if ( $proc->line[0] != ' ' && strpos( $proc->line , ':' ) > 0 )
132+
{
133+
$proc->next();
134+
continue;
135+
}
136+
break;
137+
}
138+
139+
$proc->skip(); // Empty Line
140+
141+
// Message
142+
143+
while ( $proc->live && str_starts_with( $proc->line , ' ' ) )
144+
{
145+
if ( LOOSE_SKIP_REVCHECK ) // https://github.com/php/doc-base/pull/132
146+
{
147+
// Messages that contains [skip-revcheck] flags entire commit as ignored.
148+
if ( str_contains( $proc->line , '[skip-revcheck]' ) )
149+
$skip = true;
150+
}
151+
else
152+
{
153+
// Messages that start with [skip-revcheck] flags entire commit as ignored.
154+
$lcnt++;
155+
if ( $lcnt == 1 && str_starts_with( trim( $line ) , '[skip-revcheck]' ) )
156+
$skip = true;
157+
}
158+
$proc->next();
159+
}
160+
161+
$proc->skip(); // Empty Line
162+
163+
// Merge commits and empty files commits
164+
165+
// Merge commits are not followed with file listings.
166+
// Some normal commits also not have file listings
167+
// (see b73609198d4606621f57e165efc457f30e403217).
168+
169+
if ( str_starts_with( $proc->line , "commit " ) )
170+
continue;
171+
172+
// Files
173+
174+
while ( $proc->live && strlen( trim( $proc->line ) ) > 0 )
175+
{
176+
$file = $list->get( trim( $proc->line ) );
177+
178+
if ( $file != null )
179+
$file->addGitLogData( $hash , $date , $skip );
180+
181+
$proc->next();
182+
}
183+
184+
$proc->skip(); // Empty Line
185+
}
186+
}
92187
}
188+
189+
class GitLogParserProc
190+
{
191+
public bool $live;
192+
public string $line;
193+
private $proc = null;
194+
195+
function __construct( string $command )
196+
{
197+
$this->proc = popen( $command , "r" );
198+
$this->live = true;
199+
$this->next();
200+
}
201+
202+
function next()
203+
{
204+
if ( $this->proc == null )
205+
return;
206+
207+
$ret = fgets( $this->proc );
208+
if ( $ret === false )
209+
$this->stop();
210+
else
211+
$this->line = $ret;
212+
}
213+
214+
function skip()
215+
{
216+
if ( trim( $this->line ) != "" )
217+
throw new Exception( "Skipping non-blank line." );
218+
$this->next();
219+
}
220+
221+
function stop()
222+
{
223+
pclose( $this->proc );
224+
$this->live = false;
225+
$this->line = "";
226+
$this->proc = null;
227+
}
228+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
# +----------------------------------------------------------------------+
3+
# | Copyright (c) 1997-2024 The PHP Group |
4+
# +----------------------------------------------------------------------+
5+
# | This source file is subject to version 3.01 of the PHP license, |
6+
# | that is bundled with this package in the file LICENSE, and is |
7+
# | available through the world-wide-web at the following url: |
8+
# | https://www.php.net/license/3_01.txt. |
9+
# | If you did not receive a copy of the PHP license and are unable to |
10+
# | obtain it through the world-wide-web, please send a note to |
11+
# | [email protected], so we can mail you a copy immediately. |
12+
# +----------------------------------------------------------------------+
13+
# | Authors: André L F S Bacci <ae php.net> |
14+
# +----------------------------------------------------------------------+
15+
# | Description: Common functions that interact with git command line. |
16+
# +----------------------------------------------------------------------+
17+
18+
require_once __DIR__ . '/all.php';
19+
20+
class GitSlowUtils
21+
{
22+
public static function checkDiffOnlyWsChange( string $gdir , RevcheckDataFile $file ) : bool
23+
{
24+
$hash = $file->hashRvtg;
25+
$flnm = $file->path == "" ? $file->name : $file->path . "/" . $file->name;
26+
27+
$gdir = escapeshellarg( $gdir );
28+
$flnm = escapeshellarg( $flnm );
29+
$hash = escapeshellarg( $hash );
30+
31+
$func = '[' . __CLASS__ . ':' . __FUNCTION__ . ']';
32+
33+
// Fast path
34+
35+
// The git -b option is a bit misleading. It will ignore ws change
36+
// on existing ws runs, but will report insertion or remotion of
37+
// ws runs. This suffices for detecting significant ws changes and
38+
// also ignoring insignificant ws changes in most cases we are
39+
// interessed.
40+
41+
$output = `git -C $gdir diff -b $hash -- $flnm`;
42+
$onlyws = $output == "";
43+
44+
// Slow path
45+
46+
if ( $onlyws )
47+
{
48+
$prev = `git -C $gdir show $hash:$flnm )`;
49+
$next = `git -C $gdir show HEAD:$flnm )`;
50+
51+
if ( $prev == "" || $next == "" )
52+
{
53+
fprintf( STDERR , "$func Failed to read file contents.\n" );
54+
return $onlyws;
55+
}
56+
57+
$prev = GitUtils::discardPrefixSuffixEmptyWs( $prev );
58+
$next = GitUtils::discardPrefixSuffixEmptyWs( $next );
59+
60+
if ( $prev != $next )
61+
{
62+
// Not really an error, but a theory. Report this bug/issue
63+
// to start a discussion if this ws change must be ignored
64+
// or tracked.
65+
66+
fprintf( STDERR , "$func Debug: Fast and slow path differ.\n" );
67+
return false;
68+
}
69+
}
70+
71+
return $onlyws;
72+
}
73+
74+
private static function discardPrefixSuffixEmptyWs( string $text ) : string
75+
{
76+
$lines = explode( "\n" , $text );
77+
$trimLines = [];
78+
foreach ( $lines as $line )
79+
$trimLines[] = trim( $line );
80+
return implode( "" , $trimLines );
81+
}
82+
83+
public static function parseAddsDels( string $gdir , RevcheckDataFile $file )
84+
{
85+
$hash = $file->hashRvtg;
86+
$name = $file->path == "" ? $file->name : $file->path . "/" . $file->name;
87+
88+
$gdir = escapeshellarg( $gdir );
89+
$hash = escapeshellarg( $hash );
90+
$name = escapeshellarg( $name );
91+
92+
$output = `git -C $gdir diff --numstat $hash -- $name`;
93+
if ( $output )
94+
{
95+
preg_match( '/(\d+)\s+(\d+)/' , $output , $matches );
96+
if ( $matches )
97+
{
98+
$file->adds = $matches[1];
99+
$file->dels = $matches[2];
100+
}
101+
}
102+
}
103+
}

scripts/translation/lib/RevcheckRun.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ function __construct( string $sourceDir , string $targetDir , bool $writeResults
4848
$this->targetFiles = new RevcheckFileList( $targetDir );
4949

5050
// Source files get info from version control
51-
GitLogParser::parseInto( $sourceDir , $this->sourceFiles );
51+
GitLogParser::parseDir( $sourceDir , $this->sourceFiles );
5252

5353
// Target files get info from revtags
54-
RevtagParser::parseInto( $targetDir , $this->targetFiles );
54+
RevtagParser::parseDir( $targetDir , $this->targetFiles );
5555

5656
// match and mix
5757
$this->parseTranslationXml();
@@ -197,7 +197,7 @@ private function addData( RevcheckFileItem $info , RevtagInfo|null $revtag = nul
197197
case RevcheckStatus::TranslatedOld:
198198
case RevcheckStatus::TranslatedWip:
199199
$this->slowPathCount++;
200-
GitDiffParser::parseAddsDels( $this->sourceDir , $file );
200+
GitSlowUtils::parseAddsDels( $this->sourceDir , $file );
201201
}
202202
}
203203
}

scripts/translation/lib/RevtagParser.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class RevtagInfo
3030

3131
class RevtagParser
3232
{
33-
static function parseInto( string $lang , RevcheckFileList & $list )
33+
static function parseDir( string $lang , RevcheckFileList $list )
3434
{
3535
foreach( $list->iterator() as $entry )
3636
$entry->revtag = RevtagParser::parseFile( $lang . '/' . $entry->file );

scripts/translation/lib/all.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@
2424
require_once __DIR__ . '/backport.php';
2525
require_once __DIR__ . '/CacheFile.php';
2626
require_once __DIR__ . '/CacheUtil.php';
27-
require_once __DIR__ . '/GitDiffParser.php';
2827
require_once __DIR__ . '/GitLogParser.php';
28+
require_once __DIR__ . '/GitSlowUtils.php';
2929
require_once __DIR__ . '/OutputIgnoreArgv.php';
3030
require_once __DIR__ . '/OutputIgnoreBuffer.php';
3131
require_once __DIR__ . '/QaFileInfo.php';

0 commit comments

Comments
 (0)