package jetbrains.mps.internal.make.runtime.util; /*Generated by MPS */ import jetbrains.mps.make.delta.IDelta; import org.apache.log4j.Logger; import org.apache.log4j.LogManager; import java.util.Map; import jetbrains.mps.vfs.IFile; import jetbrains.mps.internal.collections.runtime.MapSequence; import java.util.HashMap; import jetbrains.mps.make.delta.IDeltaVisitor; import jetbrains.mps.vfs.FileSystem; import jetbrains.mps.internal.collections.runtime.IVisitor; import jetbrains.mps.internal.collections.runtime.IMapping; import java.util.Set; import jetbrains.mps.internal.collections.runtime.SetSequence; import java.util.HashSet; public class FilesDelta implements IDelta { private static Logger LOG = LogManager.getLogger(FilesDelta.class); private Map<IFile, FilesDelta.Status> files = MapSequence.fromMap(new HashMap<IFile, FilesDelta.Status>()); private final String key; public FilesDelta(IFile dir) { this.key = DirUtil.asDir(DirUtil.straighten(DirUtil.urlToPath(dir.getPath()))); } private FilesDelta(FilesDelta copyFrom) { this.key = copyFrom.key; MapSequence.fromMap(this.files).putAll(copyFrom.files); } public void written(IFile file) { MapSequence.fromMap(files).put(file, FilesDelta.Status.WRITTEN); } public void kept(IFile file) { MapSequence.fromMap(files).put(file, FilesDelta.Status.KEPT); } public void deleted(IFile file) { MapSequence.fromMap(files).put(file, FilesDelta.Status.DELETED); } public void stale(IFile file) { if (!(MapSequence.fromMap(files).containsKey(file))) { MapSequence.fromMap(files).put(file, FilesDelta.Status.STALE); } } @Override public boolean reconcile() { return acceptVisitor(new FilesDelta.Visitor() { @Override public boolean acceptDeleted(IFile file) { FilesDelta.LOG.debug("Reconciled: deleting " + file); try { file.delete(); } catch (RuntimeException ignore) { FilesDelta.LOG.error("Exception deleting file " + file, ignore); } return true; } }); } @Override public boolean acceptVisitor(IDeltaVisitor visitor) { if (!(visitor instanceof FilesDelta.Visitor)) { return true; } return acceptFilesVisitor(((FilesDelta.Visitor) visitor)); } @Override public IDelta merge(IDelta toMerge) { if (!(toMerge instanceof FilesDelta)) { throw new IllegalArgumentException(); } FilesDelta that = (FilesDelta) toMerge; if (this.contains(that)) { return new FilesDelta(this).copy(that); } else if (toMerge.contains(this)) { return new FilesDelta(that).copy(this); } String commonPrefix = DirUtil.commonDirPrefix(this.key, that.key); if (!(commonPrefix.isEmpty())) { return new FilesDelta(FileSystem.getInstance().getFileByPath(commonPrefix)).copy(this).copy(that); } throw new IllegalArgumentException(); } private boolean acceptFilesVisitor(final FilesDelta.Visitor visitor) { MapSequence.fromMap(files).visitAll(new IVisitor<IMapping<IFile, FilesDelta.Status>>() { public void visit(IMapping<IFile, FilesDelta.Status> m) { if (m.value() == FilesDelta.Status.KEPT && !(m.key().isDirectory())) { visitor.acceptKept(m.key()); } else if (m.value() == FilesDelta.Status.WRITTEN) { visitor.acceptWritten(m.key()); } else if (m.value() == FilesDelta.Status.DELETED || m.value() == FilesDelta.Status.STALE) { visitor.acceptDeleted(m.key()); } } }); return true; } private FilesDelta copy(FilesDelta that) { // provided there's this.contains(that) call before copy() // DirUtil.startsWith(that, this) == true if (!(DirUtil.startsWith(that.key, this.key))) { throw new IllegalArgumentException(); } Set<IFile> newlyTouchedDirs = SetSequence.fromSet(new HashSet<IFile>()); // copy all but stale values, stale entries shall not override explicitly set for (IFile file : MapSequence.fromMap(that.files).keySet()) { FilesDelta.Status newStatus = MapSequence.fromMap(that.files).get(file); if (newStatus == FilesDelta.Status.STALE && MapSequence.fromMap(files).containsKey(file)) { continue; } else { MapSequence.fromMap(files).put(file, newStatus); } SetSequence.fromSet(newlyTouchedDirs).addElement((file.isDirectory() ? file : file.getParent())); } // in case we've got stale directory, check if any updates from that didn't touch it for (IFile file : MapSequence.fromMap(files).keySet()) { if (MapSequence.fromMap(files).get(file) == FilesDelta.Status.STALE && file.isDirectory()) { String staleDir = DirUtil.normalizeAsDir(file.getPath()); for (IFile touchDir : newlyTouchedDirs) { // if staleDir is parent of any newly touched directories, it's not stale any more if (DirUtil.startsWith(DirUtil.normalizeAsDir(touchDir.getPath()), staleDir)) { MapSequence.fromMap(files).put(file, FilesDelta.Status.KEPT); break; } } } } return this; } @Override public boolean contains(IDelta other) { if (!(other instanceof FilesDelta)) { return false; } FilesDelta that = (FilesDelta) other; if (that.key.equals(this.key)) { return true; } return DirUtil.startsWith(that.key, this.key); } public static class Visitor implements IDeltaVisitor { public Visitor() { } public boolean acceptWritten(IFile file) { return true; } public boolean acceptKept(IFile file) { return true; } public boolean acceptDeleted(IFile file) { return true; } } /** * DELETED are files explicitly requested to be removed * STALE are files that are likely to need removal, unless there's another subsequent * delta that bring them back to life. */ public enum Status { WRITTEN(), KEPT(), DELETED(), STALE(); private Status() { } } }