29
29
import java .io .IOException ;
30
30
import java .io .InputStream ;
31
31
import java .io .InputStreamReader ;
32
+ import java .io .OutputStream ;
32
33
import java .io .Reader ;
33
34
import java .nio .charset .StandardCharsets ;
34
35
import java .nio .file .Paths ;
53
54
import org .eclipse .jgit .api .Git ;
54
55
import org .eclipse .jgit .api .errors .GitAPIException ;
55
56
import org .eclipse .jgit .lib .Constants ;
57
+ import org .eclipse .jgit .lib .ObjectId ;
58
+ import org .eclipse .jgit .lib .ObjectLoader ;
56
59
import org .eclipse .jgit .lib .ObjectReader ;
57
60
import org .eclipse .jgit .lib .Ref ;
58
61
import org .eclipse .jgit .revwalk .RevCommit ;
62
+ import org .eclipse .jgit .revwalk .RevTree ;
59
63
import org .eclipse .jgit .revwalk .RevWalk ;
60
64
import org .eclipse .jgit .storage .file .FileRepositoryBuilder ;
65
+ import org .eclipse .jgit .treewalk .TreeWalk ;
66
+ import org .eclipse .jgit .treewalk .filter .PathFilter ;
67
+ import org .eclipse .jgit .util .io .CountingOutputStream ;
61
68
import org .jetbrains .annotations .NotNull ;
62
69
import org .opengrok .indexer .configuration .CommandTimeoutType ;
63
70
import org .opengrok .indexer .configuration .RuntimeEnvironment ;
64
71
import org .opengrok .indexer .logger .LoggerFactory ;
65
- import org .opengrok .indexer .util .BufferSink ;
66
72
import org .opengrok .indexer .util .Executor ;
67
73
import org .opengrok .indexer .util .HeadHandler ;
68
74
import org .opengrok .indexer .util .LazilyInstantiate ;
@@ -224,57 +230,74 @@ Executor getRenamedFilesExecutor(final File file, String sinceRevision) throws I
224
230
/**
225
231
* Try to get file contents for given revision.
226
232
*
227
- * @param sink a required target sink
233
+ * @param out a required OutputStream
228
234
* @param fullpath full pathname of the file
229
- * @param rev revision
235
+ * @param rev revision string
230
236
* @return a defined instance with {@code success} == {@code true} if no
231
- * error occurred and with non-zero {@code iterations} if some data was
232
- * transferred
237
+ * error occurred and with non-zero {@code iterations} if some data was transferred
233
238
*/
234
- private HistoryRevResult getHistoryRev (
235
- BufferSink sink , String fullpath , String rev ) {
239
+ private HistoryRevResult getHistoryRev (OutputStream out , String fullpath , String rev ) {
236
240
237
241
HistoryRevResult result = new HistoryRevResult ();
238
242
File directory = new File (getDirectoryName ());
243
+
244
+ /*
245
+ * Be careful, git uses only forward slashes in its command and output (not in file path).
246
+ * Using backslashes together with git show will get empty output and 0 status code.
247
+ */
248
+ String filename ;
249
+ result .success = false ;
239
250
try {
240
- /*
241
- * Be careful, git uses only forward slashes in its command and output (not in file path).
242
- * Using backslashes together with git show will get empty output and 0 status code.
243
- */
244
- String filename = Paths .get (getCanonicalDirectoryName ()).relativize (
251
+ filename = Paths .get (getCanonicalDirectoryName ()).relativize (
245
252
Paths .get (fullpath )).toString ().replace (File .separatorChar , '/' );
246
- ensureCommand (CMD_PROPERTY_KEY , CMD_FALLBACK );
247
- String [] argv = {
248
- RepoCommand ,
249
- "show" ,
250
- rev + ":" + filename
251
- };
253
+ } catch (IOException e ) {
254
+ LOGGER .log (Level .WARNING , String .format ("Failed to relativize '%s' in for repository '%s'" ,
255
+ fullpath , directory ), e );
256
+ return result ;
257
+ }
252
258
253
- Executor executor = new Executor (Arrays .asList (argv ), directory ,
254
- RuntimeEnvironment .getInstance ().getInteractiveCommandTimeout ());
255
- int status = executor .exec ();
256
- result .iterations = copyBytes (sink , executor .getOutputStream ());
259
+ try (org .eclipse .jgit .lib .Repository repository = getJGitRepository (directory .getAbsolutePath ())) {
260
+ ObjectId commitId = repository .resolve (rev );
261
+
262
+ // a RevWalk allows to walk over commits based on some filtering that is defined
263
+ try (RevWalk revWalk = new RevWalk (repository )) {
264
+ RevCommit commit = revWalk .parseCommit (commitId );
265
+ // and using commit's tree find the path
266
+ RevTree tree = commit .getTree ();
267
+
268
+ // now try to find a specific file
269
+ try (TreeWalk treeWalk = new TreeWalk (repository )) {
270
+ treeWalk .addTree (tree );
271
+ treeWalk .setRecursive (true );
272
+ treeWalk .setFilter (PathFilter .create (filename ));
273
+ if (!treeWalk .next ()) {
274
+ LOGGER .log (Level .FINEST ,
275
+ String .format ("Did not find expected file '%s' in revision %s for repository '%s'" ,
276
+ filename , rev , directory ));
277
+ return result ;
278
+ }
257
279
258
- /*
259
- * If exit value of the process was not 0 then the file did
260
- * not exist or internal git error occured.
261
- */
262
- result .success = (status == 0 );
263
- } catch (Exception exception ) {
264
- LOGGER .log (Level .SEVERE ,
265
- String .format (
266
- "Failed to get history for file %s in revision %s:" ,
267
- fullpath , rev
268
- ),
269
- exception
270
- );
280
+ ObjectId objectId = treeWalk .getObjectId (0 );
281
+ ObjectLoader loader = repository .open (objectId );
282
+
283
+ CountingOutputStream countingOutputStream = new CountingOutputStream (out );
284
+ loader .copyTo (countingOutputStream );
285
+ result .iterations = countingOutputStream .getCount ();
286
+ result .success = true ;
287
+ }
288
+
289
+ revWalk .dispose ();
290
+ }
291
+ } catch (IOException e ) {
292
+ LOGGER .log (Level .WARNING , String .format ("Failed to get file '%s' in revision %s for repository '%s'" ,
293
+ filename , rev , directory ), e );
271
294
}
295
+
272
296
return result ;
273
297
}
274
298
275
299
@ Override
276
- boolean getHistoryGet (
277
- BufferSink sink , String parent , String basename , String rev ) {
300
+ boolean getHistoryGet (OutputStream out , String parent , String basename , String rev ) {
278
301
279
302
String fullpath ;
280
303
try {
@@ -285,7 +308,7 @@ boolean getHistoryGet(
285
308
return false ;
286
309
}
287
310
288
- HistoryRevResult result = getHistoryRev (sink :: write , fullpath , rev );
311
+ HistoryRevResult result = getHistoryRev (out , fullpath , rev );
289
312
if (!result .success && result .iterations < 1 ) {
290
313
/*
291
314
* If we failed to get the contents it might be that the file was
@@ -312,7 +335,7 @@ boolean getHistoryGet(
312
335
return false ;
313
336
}
314
337
if (!fullRenamedPath .equals (fullpath )) {
315
- result = getHistoryRev (sink , fullRenamedPath , rev );
338
+ result = getHistoryRev (out , fullRenamedPath , rev );
316
339
}
317
340
}
318
341
}
0 commit comments