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