1 package org.apache.maven.scm.provider.accurev.command.changelog;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.Collections;
25 import java.util.Date;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Map;
29
30 import org.apache.maven.scm.ChangeFile;
31 import org.apache.maven.scm.ChangeSet;
32 import org.apache.maven.scm.CommandParameter;
33 import org.apache.maven.scm.CommandParameters;
34 import org.apache.maven.scm.ScmBranch;
35 import org.apache.maven.scm.ScmException;
36 import org.apache.maven.scm.ScmFileSet;
37 import org.apache.maven.scm.ScmResult;
38 import org.apache.maven.scm.ScmRevision;
39 import org.apache.maven.scm.ScmVersion;
40 import org.apache.maven.scm.command.changelog.ChangeLogScmResult;
41 import org.apache.maven.scm.command.changelog.ChangeLogSet;
42 import org.apache.maven.scm.log.ScmLogger;
43 import org.apache.maven.scm.provider.ScmProviderRepository;
44 import org.apache.maven.scm.provider.accurev.AccuRev;
45 import org.apache.maven.scm.provider.accurev.AccuRevCapability;
46 import org.apache.maven.scm.provider.accurev.AccuRevException;
47 import org.apache.maven.scm.provider.accurev.AccuRevScmProviderRepository;
48 import org.apache.maven.scm.provider.accurev.AccuRevVersion;
49 import org.apache.maven.scm.provider.accurev.FileDifference;
50 import org.apache.maven.scm.provider.accurev.Stream;
51 import org.apache.maven.scm.provider.accurev.Transaction;
52 import org.apache.maven.scm.provider.accurev.Transaction.Version;
53 import org.apache.maven.scm.provider.accurev.command.AbstractAccuRevCommand;
54 import org.codehaus.plexus.util.StringUtils;
55
56
57
58
59
60
61
62
63
64
65 public class AccuRevChangeLogCommand
66 extends AbstractAccuRevCommand
67 {
68
69 public AccuRevChangeLogCommand( ScmLogger logger )
70 {
71 super( logger );
72 }
73
74 @Override
75 protected ScmResult executeAccurevCommand( AccuRevScmProviderRepository repository, ScmFileSet fileSet,
76 CommandParameters parameters )
77 throws ScmException, AccuRevException
78 {
79
80
81 ScmBranch branch = (ScmBranch) parameters.getScmVersion( CommandParameter.BRANCH, null );
82 AccuRevVersion branchVersion = repository.getAccuRevVersion( branch );
83 String stream = branchVersion.getBasisStream();
84 String fromSpec = branchVersion.getTimeSpec();
85 String toSpec = "highest";
86
87
88 ScmVersion startVersion = parameters.getScmVersion( CommandParameter.START_SCM_VERSION, null );
89 ScmVersion endVersion = parameters.getScmVersion( CommandParameter.END_SCM_VERSION, null );
90
91 if ( startVersion != null && StringUtils.isNotEmpty( startVersion.getName() ) )
92 {
93 AccuRevVersion fromVersion = repository.getAccuRevVersion( startVersion );
94
95 AccuRevVersion toVersion =
96 endVersion == null ? new AccuRevVersion( fromVersion.getBasisStream(), "now" )
97 : repository.getAccuRevVersion( endVersion );
98
99 if ( !StringUtils.equals( fromVersion.getBasisStream(), toVersion.getBasisStream() ) )
100 {
101 throw new AccuRevException( "Not able to provide change log between different streams " + fromVersion
102 + "," + toVersion );
103 }
104
105 stream = fromVersion.getBasisStream();
106 fromSpec = fromVersion.getTimeSpec();
107 toSpec = toVersion.getTimeSpec();
108
109 }
110
111 Date startDate = parameters.getDate( CommandParameter.START_DATE, null );
112 Date endDate = parameters.getDate( CommandParameter.END_DATE, null );
113 int numDays = parameters.getInt( CommandParameter.NUM_DAYS, 0 );
114
115 if ( numDays > 0 )
116 {
117 if ( ( startDate != null || endDate != null ) )
118 {
119 throw new ScmException( "Start or end date cannot be set if num days is set." );
120 }
121
122 int day = 24 * 60 * 60 * 1000;
123 startDate = new Date( System.currentTimeMillis() - (long) numDays * day );
124 endDate = new Date( System.currentTimeMillis() + day );
125 }
126
127 if ( endDate != null && startDate == null )
128 {
129 throw new ScmException( "The end date is set but the start date isn't." );
130 }
131
132
133 if ( startDate != null )
134 {
135 fromSpec = AccuRevScmProviderRepository.formatTimeSpec( startDate );
136 }
137 else if ( fromSpec == null )
138 {
139 fromSpec = "1";
140 }
141
142
143
144 Transaction fromTransaction = getDepotTransaction( repository, stream, fromSpec );
145
146 long fromTranId = 1;
147 if ( fromTransaction != null )
148 {
149
150 fromTranId = fromTransaction.getTranId();
151 if ( startDate == null )
152 {
153 startDate = fromTransaction.getWhen();
154 }
155 }
156
157 if ( endDate != null )
158 {
159 toSpec = AccuRevScmProviderRepository.formatTimeSpec( endDate );
160 }
161 else if ( toSpec == null )
162 {
163 toSpec = "highest";
164 }
165
166 Transaction toTransaction = getDepotTransaction( repository, stream, toSpec );
167 long toTranId = 1;
168 if ( toTransaction != null )
169 {
170 toTranId = toTransaction.getTranId();
171 if ( endDate == null )
172 {
173 endDate = toTransaction.getWhen();
174 }
175 }
176 startVersion = new ScmRevision( repository.getRevision( stream, fromTranId ) );
177 endVersion = new ScmRevision( repository.getRevision( stream, toTranId ) );
178
179
180
181 List<Transaction> streamHistory = Collections.emptyList();
182 List<Transaction> workspaceHistory = Collections.emptyList();
183 List<FileDifference> streamDifferences = Collections.emptyList();
184
185 StringBuilder errorMessage = new StringBuilder();
186
187 AccuRev accurev = repository.getAccuRev();
188
189 Stream changelogStream = accurev.showStream( stream );
190 if ( changelogStream == null )
191 {
192 errorMessage.append( "Unknown accurev stream -" ).append( stream ).append( "." );
193 }
194 else
195 {
196
197 String message =
198 "Changelog on stream " + stream + "(" + changelogStream.getStreamType() + ") from " + fromTranId + " ("
199 + startDate + "), to " + toTranId + " (" + endDate + ")";
200
201 if ( startDate != null && startDate.after( endDate ) || fromTranId >= toTranId )
202 {
203 getLogger().warn( "Skipping out of range " + message );
204 }
205 else
206 {
207
208 getLogger().info( message );
209
210
211
212
213 Stream diffStream = changelogStream;
214 if ( changelogStream.isWorkspace() )
215 {
216
217 workspaceHistory =
218 accurev.history( stream, Long.toString( fromTranId + 1 ), Long.toString( toTranId ), 0, false,
219 false );
220
221 if ( workspaceHistory == null )
222 {
223 errorMessage.append( "history on workspace " + stream + " from " + fromTranId + 1 + " to "
224 + toTranId + " failed." );
225
226 }
227
228
229 stream = changelogStream.getBasis();
230 diffStream = accurev.showStream( stream );
231
232 }
233
234 if ( AccuRevCapability.DIFF_BETWEEN_STREAMS.isSupported( accurev.getClientVersion() ) )
235 {
236 if ( startDate.before( diffStream.getStartDate() ) )
237 {
238 getLogger().warn( "Skipping diff of " + stream + " due to start date out of range" );
239 }
240 else
241 {
242 streamDifferences =
243 accurev.diff( stream, Long.toString( fromTranId ), Long.toString( toTranId ) );
244 if ( streamDifferences == null )
245 {
246 errorMessage.append( "Diff " + stream + "- " + fromTranId + " to " + toTranId + "failed." );
247 }
248 }
249 }
250
251
252
253 streamHistory =
254 accurev.history( stream, Long.toString( fromTranId + 1 ), Long.toString( toTranId ), 0, false,
255 false );
256 if ( streamHistory == null )
257 {
258 errorMessage.append( "history on stream " + stream + " from " + fromTranId + 1 + " to " + toTranId
259 + " failed." );
260 }
261
262 }
263 }
264
265 String errorString = errorMessage.toString();
266 if ( StringUtils.isBlank( errorString ) )
267 {
268 ChangeLogSet changeLog =
269 getChangeLog( changelogStream, streamDifferences, streamHistory, workspaceHistory, startDate, endDate );
270
271 changeLog.setEndVersion( endVersion );
272 changeLog.setStartVersion( startVersion );
273
274 return new ChangeLogScmResult( accurev.getCommandLines(), changeLog );
275 }
276 else
277 {
278 return new ChangeLogScmResult( accurev.getCommandLines(), "AccuRev errors: " + errorMessage,
279 accurev.getErrorOutput(), false );
280 }
281
282 }
283
284 private Transaction getDepotTransaction( AccuRevScmProviderRepository repo, String stream, String tranSpec )
285 throws AccuRevException
286 {
287 return repo.getDepotTransaction( stream, tranSpec );
288 }
289
290 private ChangeLogSet getChangeLog( Stream stream, List<FileDifference> streamDifferences,
291 List<Transaction> streamHistory, List<Transaction> workspaceHistory,
292 Date startDate, Date endDate )
293 {
294
295
296
297
298
299 Map<Long, FileDifference> differencesMap = new HashMap<Long, FileDifference>();
300 for ( FileDifference fileDifference : streamDifferences )
301 {
302 differencesMap.put( fileDifference.getElementId(), fileDifference );
303 }
304
305 List<Transaction> mergedHistory = new ArrayList<Transaction>( streamHistory );
306
307 String streamPrefix = "/";
308
309 mergedHistory.addAll( workspaceHistory );
310 streamPrefix = stream.getId() + "/";
311
312 List<ChangeSet> entries = new ArrayList<ChangeSet>( streamHistory.size() );
313 for ( Transaction t : mergedHistory )
314 {
315 if ( ( startDate != null && t.getWhen().before( startDate ) )
316 || ( endDate != null && t.getWhen().after( endDate ) ) )
317 {
318
319 continue;
320 }
321
322
323
324
325
326 if ( "mkstream".equals( t.getTranType() ) )
327 {
328 continue;
329 }
330
331 Collection<Version> versions = t.getVersions();
332 List<ChangeFile> files = new ArrayList<ChangeFile>( versions.size() );
333
334 for ( Version v : versions )
335 {
336
337
338 FileDifference difference = differencesMap.get( v.getElementId() );
339
340 if ( difference != null )
341 {
342 String newVersionSpec = difference.getNewVersionSpec();
343 if ( newVersionSpec != null && newVersionSpec.equals( v.getRealSpec() ) )
344 {
345 if ( getLogger().isDebugEnabled() )
346 {
347 getLogger().debug( "Removing difference for " + v );
348 }
349 differencesMap.remove( v.getElementId() );
350 }
351 }
352
353
354
355
356 if ( v.getRealSpec().startsWith( streamPrefix ) && !v.getVirtualSpec().startsWith( streamPrefix ) )
357 {
358 if ( getLogger().isDebugEnabled() )
359 {
360 getLogger().debug( "Skipping workspace to basis stream promote " + v );
361 }
362 }
363 else
364 {
365 ChangeFile f =
366 new ChangeFile( v.getElementName(), v.getVirtualSpec() + " (" + v.getRealSpec() + ")" );
367 files.add( f );
368 }
369
370 }
371
372 if ( versions.isEmpty() || !files.isEmpty() )
373 {
374 ChangeSet changeSet = new ChangeSet( t.getWhen(), t.getComment(), t.getAuthor(), files );
375
376 entries.add( changeSet );
377 }
378 else
379 {
380 if ( getLogger().isDebugEnabled() )
381 {
382 getLogger().debug( "All versions removed for " + t );
383 }
384 }
385
386 }
387
388
389
390
391 if ( !differencesMap.isEmpty() )
392 {
393 List<ChangeFile> upstreamFiles = new ArrayList<ChangeFile>();
394 for ( FileDifference difference : differencesMap.values() )
395 {
396 if ( difference.getNewVersionSpec() != null )
397 {
398 upstreamFiles.add( new ChangeFile( difference.getNewFile().getPath(),
399 difference.getNewVersionSpec() ) );
400 }
401 else
402 {
403
404 upstreamFiles.add( new ChangeFile( difference.getOldFile().getPath(), null ) );
405 }
406 }
407 entries.add( new ChangeSet( endDate, "Upstream changes", "various", upstreamFiles ) );
408 }
409
410 return new ChangeLogSet( entries, startDate, endDate );
411 }
412
413 public ChangeLogScmResult changelog( ScmProviderRepository repo, ScmFileSet testFileSet, CommandParameters params )
414 throws ScmException
415 {
416 return (ChangeLogScmResult) execute( repo, testFileSet, params );
417 }
418
419 }