1 package org.apache.maven.scm.provider.git.jgit.command;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import org.apache.maven.scm.ScmFile;
23 import org.apache.maven.scm.ScmFileSet;
24 import org.apache.maven.scm.ScmFileStatus;
25 import org.apache.maven.scm.log.ScmLogger;
26 import org.apache.maven.scm.provider.git.repository.GitScmProviderRepository;
27 import org.apache.maven.scm.util.FilenameUtils;
28 import org.codehaus.plexus.util.StringUtils;
29 import org.eclipse.jgit.api.AddCommand;
30 import org.eclipse.jgit.api.Git;
31 import org.eclipse.jgit.api.Status;
32 import org.eclipse.jgit.api.errors.GitAPIException;
33 import org.eclipse.jgit.api.errors.InvalidRemoteException;
34 import org.eclipse.jgit.api.errors.NoFilepatternException;
35 import org.eclipse.jgit.api.errors.TransportException;
36 import org.eclipse.jgit.diff.DiffEntry;
37 import org.eclipse.jgit.diff.DiffEntry.ChangeType;
38 import org.eclipse.jgit.diff.DiffFormatter;
39 import org.eclipse.jgit.diff.RawTextComparator;
40 import org.eclipse.jgit.errors.CorruptObjectException;
41 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
42 import org.eclipse.jgit.errors.MissingObjectException;
43 import org.eclipse.jgit.errors.StopWalkException;
44 import org.eclipse.jgit.lib.Constants;
45 import org.eclipse.jgit.lib.ObjectId;
46 import org.eclipse.jgit.lib.ProgressMonitor;
47 import org.eclipse.jgit.lib.Repository;
48 import org.eclipse.jgit.lib.RepositoryBuilder;
49 import org.eclipse.jgit.lib.StoredConfig;
50 import org.eclipse.jgit.lib.TextProgressMonitor;
51 import org.eclipse.jgit.revwalk.RevCommit;
52 import org.eclipse.jgit.revwalk.RevFlag;
53 import org.eclipse.jgit.revwalk.RevSort;
54 import org.eclipse.jgit.revwalk.RevWalk;
55 import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
56 import org.eclipse.jgit.revwalk.filter.RevFilter;
57 import org.eclipse.jgit.transport.CredentialsProvider;
58 import org.eclipse.jgit.transport.PushResult;
59 import org.eclipse.jgit.transport.RefSpec;
60 import org.eclipse.jgit.transport.RemoteRefUpdate;
61 import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
62 import org.eclipse.jgit.util.io.DisabledOutputStream;
63
64 import java.io.File;
65 import java.io.IOException;
66 import java.io.UnsupportedEncodingException;
67 import java.net.URI;
68 import java.net.URLEncoder;
69 import java.util.ArrayList;
70 import java.util.Collection;
71 import java.util.Date;
72 import java.util.HashSet;
73 import java.util.Iterator;
74 import java.util.List;
75 import java.util.Set;
76
77
78
79
80
81
82
83
84 public class JGitUtils
85 {
86
87 private JGitUtils()
88 {
89
90 }
91
92
93
94
95
96
97 public static Git openRepo( File basedir ) throws IOException
98 {
99 return new Git( new RepositoryBuilder().readEnvironment().findGitDir( basedir ).setMustExist( true ).build() );
100 }
101
102
103
104
105
106 public static void closeRepo( Git git )
107 {
108 if ( git != null && git.getRepository() != null )
109 {
110 git.getRepository().close();
111 }
112 }
113
114
115
116
117
118
119
120 public static ProgressMonitor getMonitor( ScmLogger logger )
121 {
122
123 return new TextProgressMonitor();
124 }
125
126
127
128
129
130
131
132
133
134
135
136
137
138 public static CredentialsProvider prepareSession( ScmLogger logger, Git git, GitScmProviderRepository repository )
139 {
140 StoredConfig config = git.getRepository().getConfig();
141 config.setString( "remote", "origin", "url", repository.getFetchUrl() );
142 config.setString( "remote", "origin", "pushURL", repository.getPushUrl() );
143
144
145 String password =
146 StringUtils.isNotBlank( repository.getPassword() ) ? repository.getPassword().trim() : "no-pwd-defined";
147
148
149 try
150 {
151 password = URLEncoder.encode( password, "UTF-8" );
152 }
153 catch ( UnsupportedEncodingException e )
154 {
155
156
157 System.out.println( "Ignore UnsupportedEncodingException when trying to encode password" );
158 }
159 logger.info( "fetch url: " + repository.getFetchUrl().replace( password, "******" ) );
160 logger.info( "push url: " + repository.getPushUrl().replace( password, "******" ) );
161 return getCredentials( repository );
162 }
163
164
165
166
167
168
169
170
171
172
173
174 public static CredentialsProvider getCredentials( GitScmProviderRepository repository )
175 {
176 if ( StringUtils.isNotBlank( repository.getUser() ) && StringUtils.isNotBlank( repository.getPassword() ) )
177 {
178 return new UsernamePasswordCredentialsProvider( repository.getUser().trim(),
179 repository.getPassword().trim() );
180 }
181 return null;
182 }
183
184 public static Iterable<PushResult> push( ScmLogger logger, Git git, GitScmProviderRepository repo, RefSpec refSpec )
185 throws GitAPIException, InvalidRemoteException, TransportException
186 {
187 CredentialsProvider credentials = JGitUtils.prepareSession( logger, git, repo );
188 Iterable<PushResult> pushResultList =
189 git.push().setCredentialsProvider( credentials ).setRefSpecs( refSpec ).call();
190 for ( PushResult pushResult : pushResultList )
191 {
192 Collection<RemoteRefUpdate> ru = pushResult.getRemoteUpdates();
193 for ( RemoteRefUpdate remoteRefUpdate : ru )
194 {
195 logger.info( remoteRefUpdate.getStatus() + " - " + remoteRefUpdate.toString() );
196 }
197 }
198 return pushResultList;
199 }
200
201
202
203
204
205
206
207 public static boolean hasCommits( Repository repo )
208 {
209 if ( repo != null && repo.getDirectory().exists() )
210 {
211 return ( new File( repo.getDirectory(), "objects" ).list().length > 2 ) || (
212 new File( repo.getDirectory(), "objects/pack" ).list().length > 0 );
213 }
214 return false;
215 }
216
217
218
219
220
221
222
223
224
225
226
227
228 public static List<ScmFile> getFilesInCommit( Repository repository, RevCommit commit )
229 throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException
230 {
231 List<ScmFile> list = new ArrayList<ScmFile>();
232 if ( JGitUtils.hasCommits( repository ) )
233 {
234 RevWalk rw = new RevWalk( repository );
235 RevCommit realParant = commit.getParentCount() > 0 ? commit.getParent( 0 ) : commit;
236 RevCommit parent = rw.parseCommit( realParant.getId() );
237 DiffFormatter df = new DiffFormatter( DisabledOutputStream.INSTANCE );
238 df.setRepository( repository );
239 df.setDiffComparator( RawTextComparator.DEFAULT );
240 df.setDetectRenames( true );
241 List<DiffEntry> diffs = df.scan( parent.getTree(), commit.getTree() );
242 for ( DiffEntry diff : diffs )
243 {
244 list.add( new ScmFile( diff.getNewPath(), ScmFileStatus.CHECKED_IN ) );
245 }
246 rw.release();
247 }
248 return list;
249 }
250
251
252
253
254
255
256
257 public static ScmFileStatus getScmFileStatus( ChangeType changeType )
258 {
259 switch ( changeType )
260 {
261 case ADD:
262 return ScmFileStatus.ADDED;
263 case MODIFY:
264 return ScmFileStatus.MODIFIED;
265 case DELETE:
266 return ScmFileStatus.DELETED;
267 case RENAME:
268 return ScmFileStatus.RENAMED;
269 case COPY:
270 return ScmFileStatus.COPIED;
271 default:
272 return ScmFileStatus.UNKNOWN;
273 }
274 }
275
276
277
278
279
280
281
282
283
284
285
286 public static List<ScmFile> addAllFiles( Git git, ScmFileSet fileSet )
287 throws GitAPIException, NoFilepatternException
288 {
289 URI baseUri = fileSet.getBasedir().toURI();
290 AddCommand add = git.add();
291 for ( File file : fileSet.getFileList() )
292 {
293 if ( !file.isAbsolute() )
294 {
295 file = new File( fileSet.getBasedir().getPath(), file.getPath() );
296 }
297
298 if ( file.exists() )
299 {
300 String path = relativize( baseUri, file );
301 add.addFilepattern( path );
302 add.addFilepattern( file.getAbsolutePath() );
303 }
304 }
305 add.call();
306
307 Status status = git.status().call();
308
309 Set<String> allInIndex = new HashSet<String>();
310 allInIndex.addAll( status.getAdded() );
311 allInIndex.addAll( status.getChanged() );
312
313
314
315 List<ScmFile> addedFiles = new ArrayList<ScmFile>( allInIndex.size() );
316
317
318 for ( String entry : allInIndex )
319 {
320 ScmFile scmfile = new ScmFile( entry, ScmFileStatus.ADDED );
321
322
323
324 for ( Iterator<File> itfl = fileSet.getFileList().iterator(); itfl.hasNext(); )
325 {
326 String path = FilenameUtils.normalizeFilename( relativize( baseUri, itfl.next() ) );
327 if ( path.equals( FilenameUtils.normalizeFilename( scmfile.getPath() ) ) )
328 {
329 addedFiles.add( scmfile );
330 }
331 }
332 }
333 return addedFiles;
334 }
335
336 private static String relativize( URI baseUri, File f )
337 {
338 String path = f.getPath();
339 if ( f.isAbsolute() )
340 {
341 path = baseUri.relativize( new File( path ).toURI() ).getPath();
342 }
343 return path;
344 }
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361 public static List<RevCommit> getRevCommits( Repository repo, RevSort[] sortings, String fromRev, String toRev,
362 final Date fromDate, final Date toDate, int maxLines )
363 throws IOException, MissingObjectException, IncorrectObjectTypeException
364 {
365
366 List<RevCommit> revs = new ArrayList<RevCommit>();
367 RevWalk walk = new RevWalk( repo );
368
369 ObjectId fromRevId = fromRev != null ? repo.resolve( fromRev ) : null;
370 ObjectId toRevId = toRev != null ? repo.resolve( toRev ) : null;
371
372 if ( sortings == null || sortings.length == 0 )
373 {
374 sortings = new RevSort[]{ RevSort.TOPO, RevSort.COMMIT_TIME_DESC };
375 }
376
377 for ( final RevSort s : sortings )
378 {
379 walk.sort( s, true );
380 }
381
382 if ( fromDate != null && toDate != null )
383 {
384
385 walk.setRevFilter( new RevFilter()
386 {
387 @Override
388 public boolean include( RevWalk walker, RevCommit cmit )
389 throws StopWalkException, MissingObjectException, IncorrectObjectTypeException, IOException
390 {
391 int cmtTime = cmit.getCommitTime();
392
393 return ( cmtTime >= ( fromDate.getTime() / 1000 ) ) && ( cmtTime <= ( toDate.getTime() / 1000 ) );
394 }
395
396 @Override
397 public RevFilter clone()
398 {
399 return this;
400 }
401 } );
402 }
403 else
404 {
405 if ( fromDate != null )
406 {
407 walk.setRevFilter( CommitTimeRevFilter.after( fromDate ) );
408 }
409 if ( toDate != null )
410 {
411 walk.setRevFilter( CommitTimeRevFilter.before( toDate ) );
412 }
413 }
414
415 if ( fromRevId != null )
416 {
417 RevCommit c = walk.parseCommit( fromRevId );
418 c.add( RevFlag.UNINTERESTING );
419 RevCommit real = walk.parseCommit( c );
420 walk.markUninteresting( real );
421 }
422
423 if ( toRevId != null )
424 {
425 RevCommit c = walk.parseCommit( toRevId );
426 c.remove( RevFlag.UNINTERESTING );
427 RevCommit real = walk.parseCommit( c );
428 walk.markStart( real );
429 }
430 else
431 {
432 final ObjectId head = repo.resolve( Constants.HEAD );
433 if ( head == null )
434 {
435 throw new RuntimeException( "Cannot resolve " + Constants.HEAD );
436 }
437 RevCommit real = walk.parseCommit( head );
438 walk.markStart( real );
439 }
440
441 int n = 0;
442 for ( final RevCommit c : walk )
443 {
444 n++;
445 if ( maxLines != -1 && n > maxLines )
446 {
447 break;
448 }
449
450 revs.add( c );
451 }
452 return revs;
453 }
454
455 }