Subversion Repository Public Repository

litesoft

Diff Revisions 948 vs 950 for /trunk/Java/core/Server/src/org/litesoft/util/TriDirUpdater.java

Diff revisions: vs.
  @@ -1,317 +1,317 @@
1 - // This Source Code is in the Public Domain per: http://unlicense.org
2 - package org.litesoft.util;
3 -
4 - import org.litesoft.commonfoundation.typeutils.*;
5 -
6 - import java.io.*;
7 - import java.util.*;
8 -
9 - public class TriDirUpdater {
10 - public static final String VERSION = "1.0";
11 -
12 - public static final int MAX_FILE_SIZE = 32 * 1024 * 1024;
13 -
14 - private static File checkPath( String pType, String pPath ) {
15 - File zPath = new File( pPath );
16 - if ( !zPath.isDirectory() ) {
17 - System.out.println( pType + " Path, Not a Directory: " + zPath.getAbsolutePath() );
18 - System.exit( 2 );
19 - }
20 - return zPath;
21 - }
22 -
23 - public static void main( String[] args )
24 - throws Exception {
25 - System.out.println( "3 (Tri) Directory Updater vs " + VERSION );
26 - String zEditor = System.getenv( "Editor" );
27 - if ( zEditor == null ) {
28 - throw new IllegalStateException( "No 'Editor' environment variable" );
29 - }
30 - if ( args.length != 3 ) {
31 - showHelp();
32 - }
33 -
34 - new TriDirUpdater( zEditor,
35 - checkPath( "Update", args[0] ),
36 - checkPath( "Original", args[1] ),
37 - checkPath( "Working", args[2] ) ).process();
38 - }
39 -
40 - private static void showHelp() {
41 - System.out.println( "Requires 3 parameters:" );
42 - System.out.println();
43 - System.out.println( " 1) Update Directory Path" );
44 - System.out.println( " 2) Original Directory Path" );
45 - System.out.println( " 3) Working Directory Path" );
46 - System.out.println();
47 - System.out.println( "All the entries in the 'Update Directory Path' are compared with" );
48 - System.out.println( "all the entries in the 'Original Directory Path' and are processed" );
49 - System.out.println( "on a file by file basis in one of the following ways (affecting" );
50 - System.out.println( "the 'Working Directory Path'):" );
51 - System.out.println();
52 - System.out.println( " 1) Same - No Action taken." );
53 - System.out.println();
54 - System.out.println( " 2) No 'Original' file:" );
55 - System.out.println( " a) 'Working' file exists" );
56 - System.out.println( " - Offer Merge between: 'Update' and 'Working'." );
57 - System.out.println( " b) No 'Working' file" );
58 - System.out.println( " - copy 'Update' to 'Working'." );
59 - System.out.println( " Copy 'Update' to 'Original'." );
60 - System.out.println();
61 - System.out.println( " 3) No 'Update' file:" );
62 - System.out.println( " a) 'Working' same as 'Original' " );
63 - System.out.println( " - Delete 'Working'." );
64 - System.out.println( " b) 'Working' differs from 'Original' " );
65 - System.out.println( " - Offer Delete 'Working'?" );
66 - System.out.println( " (if 'Working' is 0 length, then delete)." );
67 - System.out.println( " Delete 'Original'." );
68 - System.out.println();
69 - System.out.println( " 4) Different:" );
70 - System.out.println( " a) 'Working' same as 'Original' " );
71 - System.out.println( " - Copy 'Update' to 'Working'." );
72 - System.out.println( " b) 'Working' differs from 'Original' " );
73 - System.out.println( " - Offer 3-way Merge: " );
74 - System.out.println( " 'Update', 'Original', and 'Working'." );
75 - System.out.println( " Copy 'Update' to 'Original'." );
76 - System.exit( 1 );
77 - }
78 -
79 - private final String mEditor;
80 - private final File mUpdatePath;
81 - private final TargetTree mOriginal, mWorking;
82 -
83 - private TriDirUpdater( String pEditor, File pUpdatePath, File pOriginalPath, File pWorkingPath ) {
84 - mEditor = pEditor;
85 - mUpdatePath = pUpdatePath;
86 - mOriginal = new TargetTree( pOriginalPath );
87 - mWorking = new TargetTree( pWorkingPath );
88 - }
89 -
90 - private void process() {
91 - mOriginal.populate();
92 - mWorking.populate();
93 - Queue<String> zDirectoriesToProcess = new LinkedList<String>();
94 - process( zDirectoriesToProcess, "", getDirectoryEntries( mUpdatePath ) );
95 - while ( !zDirectoriesToProcess.isEmpty() ) {
96 - String zRelativeDirectoryPath = zDirectoriesToProcess.remove();
97 - process( zDirectoriesToProcess, zRelativeDirectoryPath, getDirectoryEntries( new File( mUpdatePath, zRelativeDirectoryPath ) ) );
98 - }
99 - for ( String zUnmatchedOriginalRelativePath : mOriginal.getRelativePaths() ) {
100 - processNoUpdateFile( zUnmatchedOriginalRelativePath );
101 - }
102 - }
103 -
104 - private void process( Queue<String> pDirectoryCollector, String pRelativeDirectoryPath, String[] pNames ) {
105 - for ( String zName : pNames ) {
106 - String zRelativePath = relativePath( pRelativeDirectoryPath, zName );
107 - File zFile = new File( mUpdatePath, zRelativePath );
108 - if ( zFile.isFile() ) {
109 - processUpdateFile( zRelativePath );
110 - continue;
111 - }
112 - if ( zFile.isDirectory() ) {
113 - pDirectoryCollector.add( zRelativePath );
114 - continue;
115 - }
116 - throw new IllegalStateException( "Neither a File or a Directory: " + zFile.getAbsolutePath() );
117 - }
118 - }
119 -
120 - private static String[] getDirectoryEntries( File pDirectory ) {
121 - String[] zFiles = pDirectory.list();
122 - if ( zFiles != null ) {
123 - return zFiles;
124 - }
125 - throw new IllegalStateException( "Unable to get Directory Listing from: " + pDirectory.getAbsolutePath() );
126 - }
127 -
128 - private static String relativePath( String pRelativeDirectoryPath, String pName ) {
129 - return (pRelativeDirectoryPath.length() == 0) ? pName : pRelativeDirectoryPath + "/" + pName;
130 - }
131 -
132 - private static class TargetTree {
133 - private final Map<String, File> mEntries = Maps.newHashMap();
134 - private final File mBasePath;
135 -
136 - public TargetTree( File pBasePath ) {
137 - mBasePath = pBasePath;
138 - }
139 -
140 - public void populate() {
141 - populate( "", getDirectoryEntries( mBasePath ) );
142 - }
143 -
144 - private void populate( String pRelativeDirectoryPath, String[] pNames ) {
145 - for ( String zName : pNames ) {
146 - String zRelativePath = relativePath( pRelativeDirectoryPath, zName );
147 - File zFile = new File( mBasePath, zRelativePath );
148 - if ( zFile.isFile() ) {
149 - mEntries.put( zRelativePath, zFile );
150 - continue;
151 - }
152 - if ( !zFile.isDirectory() ) {
153 - throw new IllegalStateException( "Neither a File or a Directory: " + zFile.getAbsolutePath() );
154 - }
155 - populate( zRelativePath, getDirectoryEntries( zFile ) );
156 - }
157 - }
158 -
159 - public File getFile( String pRelativePath ) {
160 - return mEntries.get( pRelativePath );
161 - }
162 -
163 - public void removeEntry( String pRelativePath ) {
164 - mEntries.remove( pRelativePath );
165 - }
166 -
167 - public String[] getRelativePaths() {
168 - return mEntries.keySet().toArray( new String[mEntries.size()] );
169 - }
170 -
171 - public void delete( String pRelativePath ) {
172 - FileUtils.deleteIfExists( mEntries.remove( pRelativePath ) );
173 - }
174 -
175 - public void save( String pRelativePath, File pFile, byte[] pContents ) {
176 - save( pFile, pContents );
177 - removeEntry( pRelativePath );
178 - }
179 -
180 - public void save( String pRelativePath, byte[] pContents ) {
181 - save( new File( mBasePath, pRelativePath ), pContents );
182 - }
183 -
184 - private void save( File pFile, byte[] pContents ) {
185 - FileUtils.store( pFile, pContents );
186 - FileUtils.deleteIfExists( new File( pFile.getAbsolutePath() + ".bak" ) );
187 - }
188 - }
189 -
190 - private byte[] load( File pUpdateFile ) {
191 - return FileUtils.load( pUpdateFile, MAX_FILE_SIZE );
192 - }
193 -
194 - private boolean different( byte[] pBytes1, byte[] pBytes2 ) {
195 - return !Arrays.equals( pBytes1, pBytes2 );
196 - }
197 -
198 - // Options:
199 - //
200 - // No 'Original' file...
201 - // Same - No Action taken...
202 - // Different...
203 - private void processUpdateFile( String pRelativePath ) {
204 - File zUpdateFile = new File( mUpdatePath, pRelativePath );
205 - byte[] zUpdateContents = load( zUpdateFile );
206 - File zOriginalFile = mOriginal.getFile( pRelativePath );
207 - if ( zOriginalFile == null ) {
208 - processUpdateButNoOriginal( pRelativePath, zUpdateFile, zUpdateContents );
209 - return;
210 - }
211 - byte[] zOriginalContents = load( zOriginalFile );
212 - if ( different( zUpdateContents, zOriginalContents ) ) {
213 - processUpdateDifferentThanOriginal( pRelativePath, zUpdateFile, zUpdateContents, zOriginalFile, zOriginalContents );
214 - return;
215 - }
216 - // Same!
217 - mOriginal.removeEntry( pRelativePath );
218 - mWorking.removeEntry( pRelativePath );
219 - }
220 -
221 - // No 'Update' file:
222 - // a) 'Working' same as 'Original'
223 - // - Delete 'Working'.
224 - // b) 'Working' differs from 'Original'
225 - // - Offer Delete 'Working'?
226 - // (if 'Working' is 0 length, then delete).
227 - // Delete 'Original'.
228 - private void processNoUpdateFile( String pRelativePath ) {
229 - File zWorkingFile = mWorking.getFile( pRelativePath );
230 - if ( zWorkingFile != null ) {
231 - File zOriginalFile = mOriginal.getFile( pRelativePath );
232 - byte[] zWorkingContents = load( zWorkingFile );
233 - byte[] zOriginalContents = load( zOriginalFile );
234 - if ( different( zOriginalContents, zWorkingContents ) ) {
235 - checkWorkingChangedButNoUpdate( pRelativePath, zWorkingFile, zOriginalFile );
236 - // ************************************* If Working is Empty, then complete merge!
237 - if ( zWorkingFile.length() != 0 ) {
238 - // Ignore!
239 - mOriginal.removeEntry( pRelativePath );
240 - mWorking.removeEntry( pRelativePath );
241 - return;
242 - }
243 - }
244 - mWorking.delete( pRelativePath );
245 - }
246 - mOriginal.delete( pRelativePath );
247 - }
248 -
249 - // No 'Original' file:
250 - // a) 'Working' file exists
251 - // - Offer Merge between: 'Update' and 'Working'.
252 - // b) No 'Working' file
253 - // - copy 'Update' to 'Working'.
254 - // Copy 'Update' to 'Original'.
255 - private void processUpdateButNoOriginal( String pRelativePath, File pUpdateFile, byte[] pUpdateContents ) {
256 - File zWorkingFile = mWorking.getFile( pRelativePath );
257 - if ( zWorkingFile != null ) {
258 - checkNewUpdateCollidesWithExistingWorking( pRelativePath, zWorkingFile, pUpdateFile );
259 - // ************************************* If Working is Empty, then complete merge!
260 - if ( zWorkingFile.length() != 0 ) {
261 - // Ignore!
262 - mWorking.removeEntry( pRelativePath );
263 - return;
264 - }
265 - }
266 - mWorking.save( pRelativePath, pUpdateContents );
267 - mOriginal.save( pRelativePath, pUpdateContents );
268 - }
269 -
270 - // Different:
271 - // a) 'Working' same as 'Original'
272 - // - Copy 'Update' to 'Working'.
273 - // b) 'Working' differs from 'Original'
274 - // - Offer 3-way Merge:
275 - // 'Update', 'Original', and 'Working'.
276 - // Copy 'Update' to 'Original'.
277 - private void processUpdateDifferentThanOriginal( String pRelativePath, File pUpdateFile, byte[] pUpdateContents, File pOriginalFile,
278 - byte[] pOriginalContents ) {
279 - File zWorkingFile = mWorking.getFile( pRelativePath );
280 - if ( zWorkingFile == null ) {
281 - mWorking.save( pRelativePath, zWorkingFile, pUpdateContents );
282 - } else {
283 - byte[] zWorkingContents = load( zWorkingFile );
284 - if ( !different( pOriginalContents, zWorkingContents ) ) {
285 - mWorking.save( pRelativePath, zWorkingFile, pUpdateContents );
286 - } else {
287 - checkUpdateAndWorkingDifferentThanOriginal_threeWayMerge( pRelativePath, zWorkingFile, pUpdateFile, pOriginalFile );
288 - // ************************************* If Working changed, then complete merge!
289 - if ( !different( zWorkingContents, load( zWorkingFile ) ) ) {
290 - // Ignore!
291 - mOriginal.removeEntry( pRelativePath );
292 - mWorking.removeEntry( pRelativePath );
293 - return;
294 - }
295 - }
296 - }
297 - mOriginal.save( pRelativePath, pOriginalFile, pUpdateContents );
298 - }
299 -
300 - private void checkWorkingChangedButNoUpdate( String pRelativePath, File pWorkingFile, File pOriginalFile ) {
301 - System.out.println( "Working Changed But No Update: " + pRelativePath + "\n" +
302 - " So Working shouldn't exist - Empty Working to complete merge..." );
303 - ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pOriginalFile.getAbsolutePath() );
304 - }
305 -
306 - private void checkNewUpdateCollidesWithExistingWorking( String pRelativePath, File pWorkingFile, File pUpdateFile ) {
307 - System.out.println( "New Update Collides With Existing Working: " + pRelativePath + "\n" +
308 - " Move contents of Working to new file (leaving Working empty) to complete merge..." );
309 - ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pUpdateFile.getAbsolutePath() );
310 - }
311 -
312 - private void checkUpdateAndWorkingDifferentThanOriginal_threeWayMerge( String pRelativePath, File pWorkingFile, File pUpdateFile, File pOriginalFile ) {
313 - System.out.println( "Change Collition, both Update AND Working differ from Original: " + pRelativePath + "\n" +
314 - " Change Working to complete merge..." );
315 - ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pUpdateFile.getAbsolutePath(), pOriginalFile.getAbsolutePath() );
316 - }
317 - }
1 + // This Source Code is in the Public Domain per: http://unlicense.org
2 + package org.litesoft.util;
3 +
4 + import org.litesoft.commonfoundation.typeutils.*;
5 +
6 + import java.io.*;
7 + import java.util.*;
8 +
9 + public class TriDirUpdater {
10 + public static final String VERSION = "1.0";
11 +
12 + public static final int MAX_FILE_SIZE = 32 * 1024 * 1024;
13 +
14 + private static File checkPath( String pType, String pPath ) {
15 + File zPath = new File( pPath );
16 + if ( !zPath.isDirectory() ) {
17 + System.out.println( pType + " Path, Not a Directory: " + zPath.getAbsolutePath() );
18 + System.exit( 2 );
19 + }
20 + return zPath;
21 + }
22 +
23 + public static void main( String[] args )
24 + throws Exception {
25 + System.out.println( "3 (Tri) Directory Updater vs " + VERSION );
26 + String zEditor = System.getenv( "Editor" );
27 + if ( zEditor == null ) {
28 + throw new IllegalStateException( "No 'Editor' environment variable" );
29 + }
30 + if ( args.length != 3 ) {
31 + showHelp();
32 + }
33 +
34 + new TriDirUpdater( zEditor,
35 + checkPath( "Update", args[0] ),
36 + checkPath( "Original", args[1] ),
37 + checkPath( "Working", args[2] ) ).process();
38 + }
39 +
40 + private static void showHelp() {
41 + System.out.println( "Requires 3 parameters:" );
42 + System.out.println();
43 + System.out.println( " 1) Update Directory Path" );
44 + System.out.println( " 2) Original Directory Path" );
45 + System.out.println( " 3) Working Directory Path" );
46 + System.out.println();
47 + System.out.println( "All the entries in the 'Update Directory Path' are compared with" );
48 + System.out.println( "all the entries in the 'Original Directory Path' and are processed" );
49 + System.out.println( "on a file by file basis in one of the following ways (affecting" );
50 + System.out.println( "the 'Working Directory Path'):" );
51 + System.out.println();
52 + System.out.println( " 1) Same - No Action taken." );
53 + System.out.println();
54 + System.out.println( " 2) No 'Original' file:" );
55 + System.out.println( " a) 'Working' file exists" );
56 + System.out.println( " - Offer Merge between: 'Update' and 'Working'." );
57 + System.out.println( " b) No 'Working' file" );
58 + System.out.println( " - copy 'Update' to 'Working'." );
59 + System.out.println( " Copy 'Update' to 'Original'." );
60 + System.out.println();
61 + System.out.println( " 3) No 'Update' file:" );
62 + System.out.println( " a) 'Working' same as 'Original' " );
63 + System.out.println( " - Delete 'Working'." );
64 + System.out.println( " b) 'Working' differs from 'Original' " );
65 + System.out.println( " - Offer Delete 'Working'?" );
66 + System.out.println( " (if 'Working' is 0 length, then delete)." );
67 + System.out.println( " Delete 'Original'." );
68 + System.out.println();
69 + System.out.println( " 4) Different:" );
70 + System.out.println( " a) 'Working' same as 'Original' " );
71 + System.out.println( " - Copy 'Update' to 'Working'." );
72 + System.out.println( " b) 'Working' differs from 'Original' " );
73 + System.out.println( " - Offer 3-way Merge: " );
74 + System.out.println( " 'Update', 'Original', and 'Working'." );
75 + System.out.println( " Copy 'Update' to 'Original'." );
76 + System.exit( 1 );
77 + }
78 +
79 + private final String mEditor;
80 + private final File mUpdatePath;
81 + private final TargetTree mOriginal, mWorking;
82 +
83 + private TriDirUpdater( String pEditor, File pUpdatePath, File pOriginalPath, File pWorkingPath ) {
84 + mEditor = pEditor;
85 + mUpdatePath = pUpdatePath;
86 + mOriginal = new TargetTree( pOriginalPath );
87 + mWorking = new TargetTree( pWorkingPath );
88 + }
89 +
90 + private void process() {
91 + mOriginal.populate();
92 + mWorking.populate();
93 + Queue<String> zDirectoriesToProcess = new LinkedList<String>();
94 + process( zDirectoriesToProcess, "", getDirectoryEntries( mUpdatePath ) );
95 + while ( !zDirectoriesToProcess.isEmpty() ) {
96 + String zRelativeDirectoryPath = zDirectoriesToProcess.remove();
97 + process( zDirectoriesToProcess, zRelativeDirectoryPath, getDirectoryEntries( new File( mUpdatePath, zRelativeDirectoryPath ) ) );
98 + }
99 + for ( String zUnmatchedOriginalRelativePath : mOriginal.getRelativePaths() ) {
100 + processNoUpdateFile( zUnmatchedOriginalRelativePath );
101 + }
102 + }
103 +
104 + private void process( Queue<String> pDirectoryCollector, String pRelativeDirectoryPath, String[] pNames ) {
105 + for ( String zName : pNames ) {
106 + String zRelativePath = relativePath( pRelativeDirectoryPath, zName );
107 + File zFile = new File( mUpdatePath, zRelativePath );
108 + if ( zFile.isFile() ) {
109 + processUpdateFile( zRelativePath );
110 + continue;
111 + }
112 + if ( zFile.isDirectory() ) {
113 + pDirectoryCollector.add( zRelativePath );
114 + continue;
115 + }
116 + throw new IllegalStateException( "Neither a File or a Directory: " + zFile.getAbsolutePath() );
117 + }
118 + }
119 +
120 + private static String[] getDirectoryEntries( File pDirectory ) {
121 + String[] zFiles = pDirectory.list();
122 + if ( zFiles != null ) {
123 + return zFiles;
124 + }
125 + throw new IllegalStateException( "Unable to get Directory Listing from: " + pDirectory.getAbsolutePath() );
126 + }
127 +
128 + private static String relativePath( String pRelativeDirectoryPath, String pName ) {
129 + return (pRelativeDirectoryPath.length() == 0) ? pName : pRelativeDirectoryPath + "/" + pName;
130 + }
131 +
132 + private static class TargetTree {
133 + private final Map<String, File> mEntries = Maps.newHashMap();
134 + private final File mBasePath;
135 +
136 + public TargetTree( File pBasePath ) {
137 + mBasePath = pBasePath;
138 + }
139 +
140 + public void populate() {
141 + populate( "", getDirectoryEntries( mBasePath ) );
142 + }
143 +
144 + private void populate( String pRelativeDirectoryPath, String[] pNames ) {
145 + for ( String zName : pNames ) {
146 + String zRelativePath = relativePath( pRelativeDirectoryPath, zName );
147 + File zFile = new File( mBasePath, zRelativePath );
148 + if ( zFile.isFile() ) {
149 + mEntries.put( zRelativePath, zFile );
150 + continue;
151 + }
152 + if ( !zFile.isDirectory() ) {
153 + throw new IllegalStateException( "Neither a File or a Directory: " + zFile.getAbsolutePath() );
154 + }
155 + populate( zRelativePath, getDirectoryEntries( zFile ) );
156 + }
157 + }
158 +
159 + public File getFile( String pRelativePath ) {
160 + return mEntries.get( pRelativePath );
161 + }
162 +
163 + public void removeEntry( String pRelativePath ) {
164 + mEntries.remove( pRelativePath );
165 + }
166 +
167 + public String[] getRelativePaths() {
168 + return mEntries.keySet().toArray( new String[mEntries.size()] );
169 + }
170 +
171 + public void delete( String pRelativePath ) {
172 + FileUtils.deleteIfExists( mEntries.remove( pRelativePath ) );
173 + }
174 +
175 + public void save( String pRelativePath, File pFile, byte[] pContents ) {
176 + save( pFile, pContents );
177 + removeEntry( pRelativePath );
178 + }
179 +
180 + public void save( String pRelativePath, byte[] pContents ) {
181 + save( new File( mBasePath, pRelativePath ), pContents );
182 + }
183 +
184 + private void save( File pFile, byte[] pContents ) {
185 + FileUtils.store( pFile, pContents );
186 + FileUtils.deleteIfExists( new File( pFile.getAbsolutePath() + ".bak" ) );
187 + }
188 + }
189 +
190 + private byte[] load( File pUpdateFile ) {
191 + return FileUtils.load( pUpdateFile, MAX_FILE_SIZE );
192 + }
193 +
194 + private boolean different( byte[] pBytes1, byte[] pBytes2 ) {
195 + return !Arrays.equals( pBytes1, pBytes2 );
196 + }
197 +
198 + // Options:
199 + //
200 + // No 'Original' file...
201 + // Same - No Action taken...
202 + // Different...
203 + private void processUpdateFile( String pRelativePath ) {
204 + File zUpdateFile = new File( mUpdatePath, pRelativePath );
205 + byte[] zUpdateContents = load( zUpdateFile );
206 + File zOriginalFile = mOriginal.getFile( pRelativePath );
207 + if ( zOriginalFile == null ) {
208 + processUpdateButNoOriginal( pRelativePath, zUpdateFile, zUpdateContents );
209 + return;
210 + }
211 + byte[] zOriginalContents = load( zOriginalFile );
212 + if ( different( zUpdateContents, zOriginalContents ) ) {
213 + processUpdateDifferentThanOriginal( pRelativePath, zUpdateFile, zUpdateContents, zOriginalFile, zOriginalContents );
214 + return;
215 + }
216 + // Same!
217 + mOriginal.removeEntry( pRelativePath );
218 + mWorking.removeEntry( pRelativePath );
219 + }
220 +
221 + // No 'Update' file:
222 + // a) 'Working' same as 'Original'
223 + // - Delete 'Working'.
224 + // b) 'Working' differs from 'Original'
225 + // - Offer Delete 'Working'?
226 + // (if 'Working' is 0 length, then delete).
227 + // Delete 'Original'.
228 + private void processNoUpdateFile( String pRelativePath ) {
229 + File zWorkingFile = mWorking.getFile( pRelativePath );
230 + if ( zWorkingFile != null ) {
231 + File zOriginalFile = mOriginal.getFile( pRelativePath );
232 + byte[] zWorkingContents = load( zWorkingFile );
233 + byte[] zOriginalContents = load( zOriginalFile );
234 + if ( different( zOriginalContents, zWorkingContents ) ) {
235 + checkWorkingChangedButNoUpdate( pRelativePath, zWorkingFile, zOriginalFile );
236 + // ************************************* If Working is Empty, then complete merge!
237 + if ( zWorkingFile.length() != 0 ) {
238 + // Ignore!
239 + mOriginal.removeEntry( pRelativePath );
240 + mWorking.removeEntry( pRelativePath );
241 + return;
242 + }
243 + }
244 + mWorking.delete( pRelativePath );
245 + }
246 + mOriginal.delete( pRelativePath );
247 + }
248 +
249 + // No 'Original' file:
250 + // a) 'Working' file exists
251 + // - Offer Merge between: 'Update' and 'Working'.
252 + // b) No 'Working' file
253 + // - copy 'Update' to 'Working'.
254 + // Copy 'Update' to 'Original'.
255 + private void processUpdateButNoOriginal( String pRelativePath, File pUpdateFile, byte[] pUpdateContents ) {
256 + File zWorkingFile = mWorking.getFile( pRelativePath );
257 + if ( zWorkingFile != null ) {
258 + checkNewUpdateCollidesWithExistingWorking( pRelativePath, zWorkingFile, pUpdateFile );
259 + // ************************************* If Working is Empty, then complete merge!
260 + if ( zWorkingFile.length() != 0 ) {
261 + // Ignore!
262 + mWorking.removeEntry( pRelativePath );
263 + return;
264 + }
265 + }
266 + mWorking.save( pRelativePath, pUpdateContents );
267 + mOriginal.save( pRelativePath, pUpdateContents );
268 + }
269 +
270 + // Different:
271 + // a) 'Working' same as 'Original'
272 + // - Copy 'Update' to 'Working'.
273 + // b) 'Working' differs from 'Original'
274 + // - Offer 3-way Merge:
275 + // 'Update', 'Original', and 'Working'.
276 + // Copy 'Update' to 'Original'.
277 + private void processUpdateDifferentThanOriginal( String pRelativePath, File pUpdateFile, byte[] pUpdateContents, File pOriginalFile,
278 + byte[] pOriginalContents ) {
279 + File zWorkingFile = mWorking.getFile( pRelativePath );
280 + if ( zWorkingFile == null ) {
281 + mWorking.save( pRelativePath, zWorkingFile, pUpdateContents );
282 + } else {
283 + byte[] zWorkingContents = load( zWorkingFile );
284 + if ( !different( pOriginalContents, zWorkingContents ) ) {
285 + mWorking.save( pRelativePath, zWorkingFile, pUpdateContents );
286 + } else {
287 + checkUpdateAndWorkingDifferentThanOriginal_threeWayMerge( pRelativePath, zWorkingFile, pUpdateFile, pOriginalFile );
288 + // ************************************* If Working changed, then complete merge!
289 + if ( !different( zWorkingContents, load( zWorkingFile ) ) ) {
290 + // Ignore!
291 + mOriginal.removeEntry( pRelativePath );
292 + mWorking.removeEntry( pRelativePath );
293 + return;
294 + }
295 + }
296 + }
297 + mOriginal.save( pRelativePath, pOriginalFile, pUpdateContents );
298 + }
299 +
300 + private void checkWorkingChangedButNoUpdate( String pRelativePath, File pWorkingFile, File pOriginalFile ) {
301 + System.out.println( "Working Changed But No Update: " + pRelativePath + "\n" +
302 + " So Working shouldn't exist - Empty Working to complete merge..." );
303 + ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pOriginalFile.getAbsolutePath() );
304 + }
305 +
306 + private void checkNewUpdateCollidesWithExistingWorking( String pRelativePath, File pWorkingFile, File pUpdateFile ) {
307 + System.out.println( "New Update Collides With Existing Working: " + pRelativePath + "\n" +
308 + " Move contents of Working to new file (leaving Working empty) to complete merge..." );
309 + ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pUpdateFile.getAbsolutePath() );
310 + }
311 +
312 + private void checkUpdateAndWorkingDifferentThanOriginal_threeWayMerge( String pRelativePath, File pWorkingFile, File pUpdateFile, File pOriginalFile ) {
313 + System.out.println( "Change Collition, both Update AND Working differ from Original: " + pRelativePath + "\n" +
314 + " Change Working to complete merge..." );
315 + ShellUtils.shell( mEditor, pWorkingFile.getAbsolutePath(), pUpdateFile.getAbsolutePath(), pOriginalFile.getAbsolutePath() );
316 + }
317 + }