| /* |
| * Copyright 2000-2012 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package com.intellij.openapi.vcs.changes; |
| |
| import com.intellij.openapi.diagnostic.Logger; |
| import com.intellij.openapi.util.Key; |
| import com.intellij.openapi.vfs.VirtualFile; |
| import com.intellij.openapi.vfs.newvfs.FileAttribute; |
| import com.intellij.openapi.vfs.newvfs.ManagingFS; |
| import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| import java.io.DataInputStream; |
| import java.io.DataOutputStream; |
| import java.io.IOException; |
| |
| /** |
| * @author peter |
| */ |
| public class LastUnchangedContentTracker { |
| private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.LastUnchangedContentTracker"); |
| private static final Key<Long> LAST_TS_KEY = Key.create("LAST_TS_KEY"); |
| private static final FileAttribute LAST_TS_ATTR = new FileAttribute("LAST_TS_ATTR", 0, true); |
| private static final FileAttribute ACQUIRED_CONTENT_ATTR = new FileAttribute("ACQUIRED_CONTENT_ATTR", 1, true); |
| private static final Key<Boolean> VCS_INVALID_FILE_STATUS = Key.create("VCS_INVALID_FILE_STATUS"); |
| |
| public static void updateLastUnchangedContent(@NotNull VirtualFile file) { |
| if (isTouched(file)) { |
| return; |
| } |
| |
| Long lastTs = getLastSavedStamp(file); |
| final long stamp = file.getTimeStamp(); |
| if (lastTs != null && stamp == lastTs) { |
| return; |
| } |
| |
| Integer oldContentId = getSavedContentId(file); |
| if (oldContentId != null && oldContentId > 0) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("releasing content for " + file + ", id = " + oldContentId); |
| } |
| getFS().releaseContent(oldContentId); |
| } |
| |
| saveContentReference(file, getFS().acquireContent(file)); |
| markTouched(file); |
| } |
| |
| private static boolean isTouched(VirtualFile file) { |
| return Boolean.TRUE.equals(file.getUserData(VCS_INVALID_FILE_STATUS)); |
| } |
| |
| public static void markTouched(VirtualFile file) { |
| file.putUserData(VCS_INVALID_FILE_STATUS, Boolean.TRUE); |
| } |
| |
| public static void markUntouched(VirtualFile file) { |
| file.putUserData(VCS_INVALID_FILE_STATUS, null); |
| } |
| |
| @Nullable |
| public static byte[] getLastUnchangedContent(@NotNull VirtualFile file) { |
| final Integer id = getSavedContentId(file); |
| try { |
| return id == null ? null : getFS().contentsToByteArray(id); |
| } |
| catch (IOException e) { |
| LOG.info(e); |
| } |
| return null; |
| } |
| |
| private static PersistentFS getFS() { |
| return (PersistentFS)ManagingFS.getInstance(); |
| } |
| |
| private static void saveContentReference(VirtualFile file, int contentId) { |
| if (contentId == 0) { |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("saveContentReference without content for file = " + file); |
| } |
| return; // content not loaded yet, nothing to save |
| } |
| |
| LOG.assertTrue(contentId > 0, contentId); |
| |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("saveContentReference file = " + file + ", id = " + contentId); |
| } |
| |
| long stamp = file.getTimeStamp(); |
| try { |
| final DataOutputStream contentStream = ACQUIRED_CONTENT_ATTR.writeAttribute(file); |
| try { |
| contentStream.writeInt(contentId); |
| } |
| finally { |
| contentStream.close(); |
| } |
| |
| final DataOutputStream tsStream = LAST_TS_ATTR.writeAttribute(file); |
| try { |
| tsStream.writeLong(stamp); |
| } |
| finally { |
| tsStream.close(); |
| } |
| |
| file.putUserData(LAST_TS_KEY, stamp); |
| } |
| catch (IOException e) { |
| LOG.info(e); |
| } |
| } |
| |
| public static boolean hasSavedContent(VirtualFile file) { |
| return getSavedContentId(file) != null; |
| } |
| |
| public static void forceSavedContent(VirtualFile file, @NotNull String content) { |
| saveContentReference(file, getFS().storeUnlinkedContent(content.getBytes(file.getCharset()))); |
| } |
| |
| @Nullable |
| private static Integer getSavedContentId(VirtualFile file) { |
| if (!file.isValid()) { |
| return null; |
| } |
| |
| Integer oldContentId = null; |
| try { |
| final DataInputStream stream = ACQUIRED_CONTENT_ATTR.readAttribute(file); |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("getSavedContentId for " + file + "; stream=" + stream); |
| } |
| if (stream != null) { |
| try { |
| oldContentId = stream.readInt(); |
| } |
| finally { |
| stream.close(); |
| } |
| if (LOG.isDebugEnabled()) { |
| LOG.debug("oldContentId=" + oldContentId); |
| } |
| LOG.assertTrue(oldContentId > 0, oldContentId); |
| } |
| } |
| catch (IOException e) { |
| LOG.info(e); |
| } |
| return oldContentId; |
| } |
| |
| @Nullable |
| private static Long getLastSavedStamp(VirtualFile file) { |
| Long l = file.getUserData(LAST_TS_KEY); |
| if (l == null) { |
| try { |
| final DataInputStream stream = LAST_TS_ATTR.readAttribute(file); |
| if (stream != null) { |
| try { |
| l = stream.readLong(); |
| } |
| finally { |
| stream.close(); |
| } |
| } |
| } |
| catch (IOException e) { |
| LOG.info(e); |
| } |
| } |
| return l; |
| } |
| } |