|
@@ -27,12 +27,18 @@ |
27 |
27 |
|
throws Exception |
28 |
28 |
|
{ |
29 |
29 |
|
System.out.println( "3 (Tri) Directory Updater vs " + VERSION ); |
|
30 |
+ |
String zEditor = System.getenv( "Editor" ); |
|
31 |
+ |
if ( zEditor == null ) |
|
32 |
+ |
{ |
|
33 |
+ |
throw new IllegalStateException( "No 'Editor' environment variable" ); |
|
34 |
+ |
} |
30 |
35 |
|
if ( args.length != 3 ) |
31 |
36 |
|
{ |
32 |
37 |
|
showHelp(); |
33 |
38 |
|
} |
34 |
39 |
|
|
35 |
|
- |
new TriDirUpdater( checkPath( "Update", args[0] ), |
|
40 |
+ |
new TriDirUpdater( zEditor, |
|
41 |
+ |
checkPath( "Update", args[0] ), |
36 |
42 |
|
checkPath( "Original", args[1] ), |
37 |
43 |
|
checkPath( "Working", args[2] ) ).process(); |
38 |
44 |
|
} |
|
@@ -77,11 +83,13 @@ |
77 |
83 |
|
System.exit( 1 ); |
78 |
84 |
|
} |
79 |
85 |
|
|
|
86 |
+ |
private final String mEditor; |
80 |
87 |
|
private final File mUpdatePath; |
81 |
88 |
|
private final TargetTree mOriginal, mWorking; |
82 |
89 |
|
|
83 |
|
- |
private TriDirUpdater( File pUpdatePath, File pOriginalPath, File pWorkingPath ) |
|
90 |
+ |
private TriDirUpdater( String pEditor, File pUpdatePath, File pOriginalPath, File pWorkingPath ) |
84 |
91 |
|
{ |
|
92 |
+ |
mEditor = pEditor; |
85 |
93 |
|
mUpdatePath = pUpdatePath; |
86 |
94 |
|
mOriginal = new TargetTree( pOriginalPath ); |
87 |
95 |
|
mWorking = new TargetTree( pWorkingPath ); |
|
@@ -112,7 +120,7 @@ |
112 |
120 |
|
File zFile = new File( mUpdatePath, zRelativePath ); |
113 |
121 |
|
if ( zFile.isFile() ) |
114 |
122 |
|
{ |
115 |
|
- |
processFile( zRelativePath ); |
|
123 |
+ |
processUpdateFile( zRelativePath ); |
116 |
124 |
|
continue; |
117 |
125 |
|
} |
118 |
126 |
|
if ( zFile.isDirectory() ) |
|
@@ -178,7 +186,7 @@ |
178 |
186 |
|
return mEntries.get( pRelativePath ); |
179 |
187 |
|
} |
180 |
188 |
|
|
181 |
|
- |
public void remove( String pRelativePath ) |
|
189 |
+ |
public void removeEntry( String pRelativePath ) |
182 |
190 |
|
{ |
183 |
191 |
|
mEntries.remove( pRelativePath ); |
184 |
192 |
|
} |
|
@@ -196,7 +204,7 @@ |
196 |
204 |
|
public void save( String pRelativePath, File pFile, byte[] pContents ) |
197 |
205 |
|
{ |
198 |
206 |
|
save( pFile, pContents ); |
199 |
|
- |
remove( pRelativePath ); |
|
207 |
+ |
removeEntry( pRelativePath ); |
200 |
208 |
|
} |
201 |
209 |
|
|
202 |
210 |
|
public void save( String pRelativePath, byte[] pContents ) |
|
@@ -211,6 +219,11 @@ |
211 |
219 |
|
} |
212 |
220 |
|
} |
213 |
221 |
|
|
|
222 |
+ |
private byte[] load( File pUpdateFile ) |
|
223 |
+ |
{ |
|
224 |
+ |
return FileUtils.load( pUpdateFile, MAX_FILE_SIZE ); |
|
225 |
+ |
} |
|
226 |
+ |
|
214 |
227 |
|
private boolean different( byte[] pBytes1, byte[] pBytes2 ) |
215 |
228 |
|
{ |
216 |
229 |
|
return !Arrays.equals( pBytes1, pBytes2 ); |
|
@@ -221,57 +234,57 @@ |
221 |
234 |
|
// No 'Original' file... |
222 |
235 |
|
// Same - No Action taken... |
223 |
236 |
|
// Different... |
224 |
|
- |
private void processFile( String pRelativePath ) |
|
237 |
+ |
private void processUpdateFile( String pRelativePath ) |
225 |
238 |
|
{ |
226 |
239 |
|
File zUpdateFile = new File( mUpdatePath, pRelativePath ); |
227 |
|
- |
byte[] zUpdateContents = FileUtils.load( zUpdateFile, MAX_FILE_SIZE ); |
|
240 |
+ |
byte[] zUpdateContents = load( zUpdateFile ); |
228 |
241 |
|
File zOriginalFile = mOriginal.getFile( pRelativePath ); |
229 |
242 |
|
if ( zOriginalFile == null ) |
230 |
243 |
|
{ |
231 |
|
- |
processNoOriginalFile( pRelativePath, zUpdateFile, zUpdateContents ); |
|
244 |
+ |
processUpdateButNoOriginal( pRelativePath, zUpdateFile, zUpdateContents ); |
232 |
245 |
|
return; |
233 |
246 |
|
} |
234 |
|
- |
byte[] zOriginalContents = FileUtils.load( zOriginalFile, MAX_FILE_SIZE ); |
|
247 |
+ |
byte[] zOriginalContents = load( zOriginalFile ); |
235 |
248 |
|
if ( different( zUpdateContents, zOriginalContents ) ) |
236 |
249 |
|
{ |
237 |
|
- |
processFilesDifferent( pRelativePath, zUpdateFile, zUpdateContents, zOriginalFile, zOriginalContents ); |
|
250 |
+ |
processUpdateDifferentThanOriginal( pRelativePath, zUpdateFile, zUpdateContents, zOriginalFile, zOriginalContents ); |
238 |
251 |
|
return; |
239 |
252 |
|
} |
240 |
253 |
|
// Same! |
241 |
|
- |
mOriginal.remove( pRelativePath ); |
242 |
|
- |
mWorking.remove( pRelativePath ); |
|
254 |
+ |
mOriginal.removeEntry( pRelativePath ); |
|
255 |
+ |
mWorking.removeEntry( pRelativePath ); |
243 |
256 |
|
} |
244 |
257 |
|
|
245 |
|
- |
// Different: |
|
258 |
+ |
// No 'Update' file: |
246 |
259 |
|
// a) 'Working' same as 'Original' |
247 |
|
- |
// - Copy 'Update' to 'Working'. |
|
260 |
+ |
// - Delete 'Working'. |
248 |
261 |
|
// b) 'Working' differs from 'Original' |
249 |
|
- |
// - Offer 3-way Merge: |
250 |
|
- |
// 'Update', 'Original', and 'Working'. |
251 |
|
- |
// Copy 'Update' to 'Original'. |
252 |
|
- |
private void processFilesDifferent( String pRelativePath, File pUpdateFile, byte[] pUpdateContents, File pOriginalFile, byte[] pOriginalContents ) |
|
262 |
+ |
// - Offer Delete 'Working'? |
|
263 |
+ |
// (if 'Working' is 0 length, then delete). |
|
264 |
+ |
// Delete 'Original'. |
|
265 |
+ |
private void processNoUpdateFile( String pRelativePath ) |
253 |
266 |
|
{ |
254 |
267 |
|
File zWorkingFile = mWorking.getFile( pRelativePath ); |
255 |
|
- |
if ( zWorkingFile == null ) |
256 |
|
- |
{ |
257 |
|
- |
mWorking.save( pRelativePath, zWorkingFile, pUpdateContents ); |
258 |
|
- |
} |
259 |
|
- |
else |
|
268 |
+ |
if ( zWorkingFile != null ) |
260 |
269 |
|
{ |
261 |
|
- |
byte[] zWorkingContents = FileUtils.load( zWorkingFile, MAX_FILE_SIZE ); |
262 |
|
- |
if ( !different( pOriginalContents, zWorkingContents ) ) |
263 |
|
- |
{ |
264 |
|
- |
mWorking.save( pRelativePath, zWorkingFile, pUpdateContents ); |
265 |
|
- |
} |
266 |
|
- |
else if ( !threeWayMerge( pRelativePath, zWorkingFile, pOriginalFile, pUpdateFile ) ) |
|
270 |
+ |
File zOriginalFile = mOriginal.getFile( pRelativePath ); |
|
271 |
+ |
byte[] zWorkingContents = load( zWorkingFile ); |
|
272 |
+ |
byte[] zOriginalContents = load( zOriginalFile ); |
|
273 |
+ |
if ( different( zOriginalContents, zWorkingContents ) ) |
267 |
274 |
|
{ |
268 |
|
- |
// Ignore! |
269 |
|
- |
mOriginal.remove( pRelativePath ); |
270 |
|
- |
mWorking.remove( pRelativePath ); |
271 |
|
- |
return; |
|
275 |
+ |
checkWorkingChangedButNoUpdate( pRelativePath, zWorkingFile, zOriginalFile ); |
|
276 |
+ |
// ************************************* If Working is Empty, then complete merge! |
|
277 |
+ |
if ( zWorkingFile.length() != 0 ) |
|
278 |
+ |
{ |
|
279 |
+ |
// Ignore! |
|
280 |
+ |
mOriginal.removeEntry( pRelativePath ); |
|
281 |
+ |
mWorking.removeEntry( pRelativePath ); |
|
282 |
+ |
return; |
|
283 |
+ |
} |
272 |
284 |
|
} |
|
285 |
+ |
mWorking.delete( pRelativePath ); |
273 |
286 |
|
} |
274 |
|
- |
mOriginal.save( pRelativePath, pOriginalFile, pUpdateContents ); |
|
287 |
+ |
mOriginal.delete( pRelativePath ); |
275 |
288 |
|
} |
276 |
289 |
|
|
277 |
290 |
|
// No 'Original' file: |
|
@@ -280,113 +293,80 @@ |
280 |
293 |
|
// b) No 'Working' file |
281 |
294 |
|
// - copy 'Update' to 'Working'. |
282 |
295 |
|
// Copy 'Update' to 'Original'. |
283 |
|
- |
private void processNoOriginalFile( String pRelativePath, File pUpdateFile, byte[] pUpdateContents ) |
|
296 |
+ |
private void processUpdateButNoOriginal( String pRelativePath, File pUpdateFile, byte[] pUpdateContents ) |
284 |
297 |
|
{ |
285 |
298 |
|
File zWorkingFile = mWorking.getFile( pRelativePath ); |
286 |
299 |
|
if ( zWorkingFile != null ) |
287 |
300 |
|
{ |
288 |
|
- |
twoWayMerge( pRelativePath, zWorkingFile, pUpdateFile ); |
289 |
|
- |
mWorking.remove( pRelativePath ); |
290 |
|
- |
return; |
|
301 |
+ |
checkNewUpdateCollidesWithExistingWorking( pRelativePath, zWorkingFile, pUpdateFile ); |
|
302 |
+ |
// ************************************* If Working is Empty, then complete merge! |
|
303 |
+ |
if ( zWorkingFile.length() != 0 ) |
|
304 |
+ |
{ |
|
305 |
+ |
// Ignore! |
|
306 |
+ |
mWorking.removeEntry( pRelativePath ); |
|
307 |
+ |
return; |
|
308 |
+ |
} |
291 |
309 |
|
} |
292 |
310 |
|
mWorking.save( pRelativePath, pUpdateContents ); |
293 |
311 |
|
mOriginal.save( pRelativePath, pUpdateContents ); |
294 |
312 |
|
} |
295 |
313 |
|
|
296 |
|
- |
// No 'Update' file: |
|
314 |
+ |
// Different: |
297 |
315 |
|
// a) 'Working' same as 'Original' |
298 |
|
- |
// - Delete 'Working'. |
|
316 |
+ |
// - Copy 'Update' to 'Working'. |
299 |
317 |
|
// b) 'Working' differs from 'Original' |
300 |
|
- |
// - Offer Delete 'Working'? |
301 |
|
- |
// (if 'Working' is 0 length, then delete). |
302 |
|
- |
// Delete 'Original'. |
303 |
|
- |
private void processNoUpdateFile( String pRelativePath ) |
|
318 |
+ |
// - Offer 3-way Merge: |
|
319 |
+ |
// 'Update', 'Original', and 'Working'. |
|
320 |
+ |
// Copy 'Update' to 'Original'. |
|
321 |
+ |
private void processUpdateDifferentThanOriginal( String pRelativePath, File pUpdateFile, byte[] pUpdateContents, File pOriginalFile, |
|
322 |
+ |
byte[] pOriginalContents ) |
304 |
323 |
|
{ |
305 |
324 |
|
File zWorkingFile = mWorking.getFile( pRelativePath ); |
306 |
325 |
|
if ( zWorkingFile == null ) |
307 |
326 |
|
{ |
308 |
|
- |
mOriginal.delete( pRelativePath ); |
309 |
|
- |
return; |
|
327 |
+ |
mWorking.save( pRelativePath, zWorkingFile, pUpdateContents ); |
310 |
328 |
|
} |
311 |
|
- |
File zOriginalFile = mOriginal.getFile( pRelativePath ); |
312 |
|
- |
byte[] zOriginalContents = FileUtils.load( zOriginalFile, MAX_FILE_SIZE ); |
313 |
|
- |
|
314 |
|
- |
byte[] zWorkingContents = FileUtils.load( zWorkingFile, MAX_FILE_SIZE ); |
315 |
|
- |
if ( different( zOriginalContents, zWorkingContents ) && !deleteNoUpdateButOriginalWithChangedWorking( pRelativePath ) ) |
|
329 |
+ |
else |
316 |
330 |
|
{ |
317 |
|
- |
// Ignore! |
318 |
|
- |
mOriginal.remove( pRelativePath ); |
319 |
|
- |
mWorking.remove( pRelativePath ); |
320 |
|
- |
return; |
|
331 |
+ |
byte[] zWorkingContents = load( zWorkingFile ); |
|
332 |
+ |
if ( !different( pOriginalContents, zWorkingContents ) ) |
|
333 |
+ |
{ |
|
334 |
+ |
mWorking.save( pRelativePath, zWorkingFile, pUpdateContents ); |
|
335 |
+ |
} |
|
336 |
+ |
else |
|
337 |
+ |
{ |
|
338 |
+ |
checkUpdateAndWorkingDifferentThanOriginal_threeWayMerge( pRelativePath, zWorkingFile, pUpdateFile, pOriginalFile ); |
|
339 |
+ |
// ************************************* If Working changed, then complete merge! |
|
340 |
+ |
if ( !different( zWorkingContents, load( zWorkingFile ) ) ) |
|
341 |
+ |
{ |
|
342 |
+ |
// Ignore! |
|
343 |
+ |
mOriginal.removeEntry( pRelativePath ); |
|
344 |
+ |
mWorking.removeEntry( pRelativePath ); |
|
345 |
+ |
return; |
|
346 |
+ |
} |
|
347 |
+ |
} |
321 |
348 |
|
} |
322 |
|
- |
mWorking.delete( pRelativePath ); |
323 |
|
- |
mOriginal.delete( pRelativePath ); |
|
349 |
+ |
mOriginal.save( pRelativePath, pOriginalFile, pUpdateContents ); |
|
350 |
+ |
} |
|
351 |
+ |
|
|
352 |
+ |
private void checkWorkingChangedButNoUpdate( String pRelativePath, File pWorkingFile, File pOriginalFile ) |
|
353 |
+ |
{ |
|
354 |
+ |
System.out.println( "Working Changed But No Update: " + pRelativePath + "\n" + |
|
355 |
+ |
" So Working shouldn't exist - Empty Working to complete merge..." ); |
|
356 |
+ |
ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pOriginalFile.getAbsolutePath() ); |
324 |
357 |
|
} |
325 |
358 |
|
|
326 |
|
- |
// /** |
327 |
|
- |
// * Move Dir - Assume same volume! |
328 |
|
- |
// */ |
329 |
|
- |
// @Override |
330 |
|
- |
// protected boolean moveDir( File pSource, File pDestination ) |
331 |
|
- |
// { |
332 |
|
- |
// Directories.deleteIfExists( pDestination ); |
333 |
|
- |
// Directories.moveFile( pSource, pDestination ); |
334 |
|
- |
// return true; |
335 |
|
- |
// } |
336 |
|
- |
// |
337 |
|
- |
// /** |
338 |
|
- |
// * Move File - Assume same volume! |
339 |
|
- |
// */ |
340 |
|
- |
// @Override |
341 |
|
- |
// protected boolean moveFile( File pSource, File pDestination ) |
342 |
|
- |
// { |
343 |
|
- |
// FileUtils.deleteIfExists( pDestination ); |
344 |
|
- |
// Directories.moveFile( pSource, pDestination ); |
345 |
|
- |
// return true; |
346 |
|
- |
// } |
347 |
|
- |
// |
348 |
|
- |
// /** |
349 |
|
- |
// * Update the existing pDestination from the pSource - Assume NOT the same volume! |
350 |
|
- |
// */ |
351 |
|
- |
// @Override |
352 |
|
- |
// protected boolean updateFile( File pSource, File pDestination ) |
353 |
|
- |
// { |
354 |
|
- |
// byte[] srcBytes = FileUtils.load( pSource, MAX_FILE_SIZE ); |
355 |
|
- |
// byte[] dstBytes = FileUtils.load( pDestination, MAX_FILE_SIZE ); |
356 |
|
- |
// if ( !Bytes.areArraysEqual( srcBytes, dstBytes ) ) |
357 |
|
- |
// { |
358 |
|
- |
// FileUtils.deleteIfExists( pDestination ); |
359 |
|
- |
// FileUtils.store( pDestination, srcBytes ); |
360 |
|
- |
// return true; |
361 |
|
- |
// } |
362 |
|
- |
// return false; |
363 |
|
- |
// } |
364 |
|
- |
// |
365 |
|
- |
// /** |
366 |
|
- |
// * Copy the pSource to the pDestination - Assume NOT the same volume! |
367 |
|
- |
// */ |
368 |
|
- |
// @Override |
369 |
|
- |
// protected boolean copyAddFile( File pSource, File pDestination ) |
370 |
|
- |
// { |
371 |
|
- |
// byte[] zBytes = FileUtils.load( pSource, MAX_FILE_SIZE ); |
372 |
|
- |
// FileUtils.store( pDestination, zBytes ); |
373 |
|
- |
// return true; |
374 |
|
- |
// } |
375 |
|
- |
|
376 |
|
- |
private void twoWayMerge( String pRelativePath, File pWorkingFile, File pUpdateFile ) |
377 |
|
- |
{ |
378 |
|
- |
System.out.println( "twoWayMerge Working & Update: " + pRelativePath ); // TODO: XXX |
379 |
|
- |
} |
380 |
|
- |
|
381 |
|
- |
private boolean threeWayMerge( String pRelativePath, File pWorkingFile, File pOriginalFile, File pUpdateFile ) |
|
359 |
+ |
private void checkNewUpdateCollidesWithExistingWorking( String pRelativePath, File pWorkingFile, File pUpdateFile ) |
382 |
360 |
|
{ |
383 |
|
- |
System.out.println( "threeWayMerge: " + pRelativePath ); |
384 |
|
- |
return false; // TODO: XXX |
|
361 |
+ |
System.out.println( "New Update Collides With Existing Working: " + pRelativePath + "\n" + |
|
362 |
+ |
" Move contents of Working to new file (leaving Working empty) to complete merge..." ); |
|
363 |
+ |
ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pUpdateFile.getAbsolutePath() ); |
385 |
364 |
|
} |
386 |
365 |
|
|
387 |
|
- |
private boolean deleteNoUpdateButOriginalWithChangedWorking( String pRelativePath ) |
|
366 |
+ |
private void checkUpdateAndWorkingDifferentThanOriginal_threeWayMerge( String pRelativePath, File pWorkingFile, File pUpdateFile, File pOriginalFile ) |
388 |
367 |
|
{ |
389 |
|
- |
System.out.println( "deleteNoUpdateButOriginalWithChangedWorking: " + pRelativePath ); |
390 |
|
- |
return false; // TODO: XXX |
|
368 |
+ |
System.out.println( "Change Collition, both Update AND Working differ from Original: " + pRelativePath + "\n" + |
|
369 |
+ |
" Change Working to complete merge..." ); |
|
370 |
+ |
ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pUpdateFile.getAbsolutePath(), pOriginalFile.getAbsolutePath() ); |
391 |
371 |
|
} |
392 |
372 |
|
} |