1 19 20 package org.netbeans.modules.subversion; 21 22 import javax.swing.SwingUtilities ; 23 import org.netbeans.modules.subversion.util.FileUtils; 24 import org.netbeans.modules.subversion.util.SvnUtils; 25 import org.netbeans.modules.subversion.client.SvnClient; 26 import org.openide.ErrorManager; 27 28 import java.io.File ; 29 import java.io.IOException ; 30 import java.util.*; 31 import java.util.logging.Logger ; 32 import java.util.logging.Level ; 33 34 import org.netbeans.modules.versioning.spi.VCSInterceptor; 35 import org.netbeans.modules.versioning.util.Utils; 36 import org.tigris.subversion.svnclientadapter.*; 37 38 43 class FilesystemHandler extends VCSInterceptor { 44 45 private final Subversion svn; 46 private final FileStatusCache cache; 47 48 51 private final Set<File > invalidMetadata = new HashSet<File >(5); 52 53 public FilesystemHandler(Subversion svn) { 54 this.svn = svn; 55 cache = svn.getStatusCache(); 56 } 57 58 public boolean beforeDelete(File file) { 59 if (SvnUtils.isPartOfSubversionMetadata(file)) return true; 60 return !file.isFile() && hasMetadata(file); 62 } 63 64 69 public void doDelete(File file) throws IOException { 70 boolean isMetadata = SvnUtils.isPartOfSubversionMetadata(file); 71 if (!isMetadata) { 72 remove(file); 73 } 74 } 75 76 public void afterDelete(final File file) { 77 Utils.post(new Runnable () { 78 public void run() { 79 fileDeletedImpl(file); 80 } 81 }); 82 } 83 84 public boolean beforeMove(File from, File to) { 85 File destDir = to.getParentFile(); 86 if (from != null && destDir != null) { 87 FileInformation info = cache.getStatus(from); 88 if ((info.getStatus() & FileInformation.STATUS_VERSIONED) != 0) { 89 return Subversion.getInstance().isManaged(to); 90 } 91 } 94 95 return false; 96 } 97 98 public void doMove(final File from, final File to) throws IOException { 99 if (SwingUtilities.isEventDispatchThread()) { 100 101 Logger.getLogger("org.netbeans.modules.subversion").log(Level.INFO, "Warning: launching external process in AWT", new Exception ().fillInStackTrace()); 102 final Throwable innerT[] = new Throwable [1]; 103 Runnable outOfAwt = new Runnable () { 104 public void run() { 105 try { 106 svnMoveImplementation(from, to); 107 } catch (Throwable t) { 108 innerT[0] = t; 109 } 110 } 111 }; 112 113 Subversion.getInstance().getRequestProcessor().post(outOfAwt).waitFinished(); 114 if (innerT[0] != null) { 115 if (innerT[0] instanceof IOException ) { 116 throw (IOException ) innerT[0]; 117 } else if (innerT[0] instanceof RuntimeException ) { 118 throw (RuntimeException ) innerT[0]; 119 } else if (innerT[0] instanceof Error ) { 120 throw (Error ) innerT[0]; 121 } else { 122 throw new IllegalStateException ("Unexpected exception class: " + innerT[0]); } 124 } 125 126 128 } else { 129 svnMoveImplementation(from, to); 130 } 131 } 132 133 public void afterMove(final File from, final File to) { 134 Utils.post(new Runnable () { 135 public void run() { 136 cache.refresh(to, FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 137 File parent = to.getParentFile(); 138 if (parent != null) { 139 if (from.equals(to)) { 140 ErrorManager.getDefault().log(ErrorManager.WARNING, "Wrong (identity) rename event for " + from.getAbsolutePath()); } 142 cache.refresh(from, FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 143 } 144 } 145 }); 146 } 147 148 public boolean beforeCreate(File file, boolean isDirectory) { 149 if (svn.isAdministrative(file.getName())) { 150 if (file.isDirectory()) { 151 File f = new File (file, Subversion.INVALID_METADATA_MARKER); 152 try { 153 f.createNewFile(); 154 } catch (IOException e) { 155 ErrorManager.getDefault().log(ErrorManager.ERROR, "Unable to create marker: " + f.getAbsolutePath()); } 157 invalidMetadata.add(file); 158 } 159 return true; 160 } else { 161 if (!file.exists()) { 162 int status = cache.getStatus(file).getStatus(); 163 if (status == FileInformation.STATUS_VERSIONED_REMOVEDLOCALLY) { 164 try { 165 SvnClient client = Subversion.getInstance().getClient(true); 166 client.revert(file, false); 167 file.delete(); 168 } catch (SVNClientException ex) { 169 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); 170 } 171 } 172 } 173 return false; 174 } 175 } 176 177 public void doCreate(File file, boolean isDirectory) throws IOException { 178 } 179 180 public void afterCreate(final File file) { 181 Utils.post(new Runnable () { 182 public void run() { 183 if (file == null) return; 184 int status = cache.refresh(file, FileStatusCache.REPOSITORY_STATUS_UNKNOWN).getStatus(); 185 186 if ((status & FileInformation.STATUS_MANAGED) == 0) return; 187 188 if (file.isDirectory()) cache.directoryContentChanged(file); 190 } 191 }); 192 } 193 194 public void afterChange(final File file) { 195 Utils.post(new Runnable () { 196 public void run() { 197 if ((cache.getStatus(file).getStatus() & FileInformation.STATUS_MANAGED) != 0) { 198 cache.refreshCached(file, FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 199 } 200 } 201 }); 202 } 203 204 207 void removeInvalidMetadata() { 208 synchronized(invalidMetadata) { 209 for (File file : invalidMetadata) { 210 Utils.deleteRecursively(file); 211 } 212 invalidMetadata.clear(); 213 } 214 } 215 216 218 223 private void fileDeletedImpl(File file) { 224 if (file == null) return; 225 int status = cache.getStatus(file).getStatus(); 226 if (status != FileInformation.STATUS_NOTVERSIONED_EXCLUDED && status != FileInformation.STATUS_NOTVERSIONED_NEWLOCALLY) { 227 try { 228 SvnClient client = Subversion.getInstance().getClient(false); 229 client.remove(new File [] { file }, true); 230 231 } catch (SVNClientException e) { 232 } 234 } 235 cache.refresh(file, FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 238 } 239 240 private boolean hasMetadata(File file) { 241 return new File (file, ".svn/entries").canRead() || new File (file, "_svn/entries").canRead(); 242 } 243 244 private boolean remove(File file) { 245 try { 246 SvnClient client = Subversion.getInstance().getClient(false); 247 client.remove(new File [] { file }, true); 249 return true; 250 } catch (SVNClientException e) { 251 return false; 252 } 253 } 254 255 public void svnMoveImplementation(final File srcFile, final File dstFile) throws IOException { 256 try { 257 boolean force = true; SvnClient client = Subversion.getInstance().getClient(false); 259 260 File tmpMetadata = null; 261 try { 262 removeInvalidMetadata(); 264 265 File parent; 266 if (dstFile.isDirectory()) { 267 parent = dstFile; 268 } else { 269 parent = dstFile.getParentFile(); 270 } 271 272 if (parent != null) { 273 int status = cache.getStatus(parent).getStatus(); 274 assert Subversion.getInstance().isManaged(parent); 276 if ((FileInformation.STATUS_VERSIONED & status) == 0) { 277 addDirectories(parent); 278 } 279 } 280 281 int retryCounter = 6; 283 while (true) { 284 try { 285 client.move(srcFile, dstFile, force); 286 break; 287 } catch (SVNClientException e) { 288 if (e.getMessage().endsWith("' locked") && retryCounter > 0) { try { 293 Thread.sleep(107); 294 } catch (InterruptedException ex) { 295 } 297 retryCounter--; 298 continue; 299 } 300 301 if (srcFile.renameTo(dstFile)) { 304 ErrorManager.getDefault().annotate(e, "Relaxing Subversion rename error...."); ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, e); break; 307 } else { 308 IOException ex = new IOException ("Subversion failed to rename " + srcFile.getAbsolutePath() + " to: " + dstFile.getAbsolutePath()); ex.initCause(e); 310 throw ex; 311 } 312 } 313 } 314 } finally { 315 if (tmpMetadata != null) { 316 FileUtils.deleteRecursively(tmpMetadata); 317 } 318 } 319 } catch (SVNClientException e) { 320 IOException ex = new IOException ("Subversion failed to rename " + srcFile.getAbsolutePath() + " to: " + dstFile.getAbsolutePath()); ex.initCause(e); 322 throw ex; 323 } 324 } 325 326 330 private void addDirectories(File dir) throws SVNClientException { 331 File parent = dir.getParentFile(); 332 if (parent != null) { 333 int status = cache.getStatus(parent).getStatus(); 334 if ((FileInformation.STATUS_VERSIONED & status) == 0) { 335 addDirectories(parent); } 337 SvnClient client = Subversion.getInstance().getClient(false); 338 client.addDirectory(dir, false); 339 cache.refresh(dir, FileStatusCache.REPOSITORY_STATUS_UNKNOWN); 340 } else { 341 throw new SVNClientException("Reached FS root, but it's still not Subversion versioned!"); } 343 } 344 } 345 | Popular Tags |