void SetState(SvnItemState set, SvnItemState unset) { // NOTE: This method is /not/ thread safe, but its callers have race conditions anyway // Setting an integer could worst case completely destroy the integer; nothing a refresh can't fix var st = (_currentState & ~unset) | set; if (st != _currentState) { // Calculate whether we have a change or just new information var changed = (st & _onceValid & _noBroadcastFor) != (_currentState & _onceValid & _noBroadcastFor); if (changed && !_enqueued) { _enqueued = true; // Schedule a stat changed broadcast lock (_stateChanged) { _stateChanged.Enqueue(this); ScheduleUpdateNotify(); } } _currentState = st; } _validState |= (set | unset); _onceValid |= _validState; }
private void SetDirty(SvnItemState dirty) { // NOTE: This method is /not/ thread safe, but its callers have race conditions anyway // Setting an integer could worst case completely destroy the integer; nothing a refresh can't fix _validState &= ~dirty; }
bool TryGetState(SvnItemState mask, out SvnItemState result) { if ((mask & _validState) != mask) { result = SvnItemState.None; return(false); } result = _currentState & mask; return(true); }
void UpdateMustLock() { SvnItemState fastValue = SvnItemState.IsDiskFile | SvnItemState.ReadOnly; SvnItemState slowValue = SvnItemState.Versioned; SvnItemState v; bool mustLock; if (TryGetState(SvnItemState.Versioned, out v) && (v == 0)) { mustLock = false; } else if (TryGetState(SvnItemState.HasProperties, out v) && (v == 0)) { mustLock = false; } else if (TryGetState(SvnItemState.ReadOnly, out v) && (v == 0)) { mustLock = false; } else if (GetState(fastValue) != fastValue) { mustLock = false; } else if (GetState(slowValue) != slowValue) { mustLock = false; } else { using (SvnClient client = _context.GetService <ISvnClientPool>().GetNoUIClient()) { string propVal; if (client.TryGetProperty(FullPath, SvnPropertyNames.SvnNeedsLock, out propVal)) { mustLock = propVal != null; // Value should be equal to SvnPropertyNames.SvnBooleanValue } else { mustLock = false; } } } if (mustLock) { SetState(SvnItemState.MustLock, SvnItemState.None); } else { SetState(SvnItemState.None, SvnItemState.MustLock); } }
void UpdateTextFile() { SvnItemState value = SvnItemState.IsDiskFile | SvnItemState.Versioned; SvnItemState v; bool isTextFile; if (TryGetState(SvnItemState.Versioned, out v) && (v == 0)) { isTextFile = false; } else if (GetState(value) != value) { isTextFile = false; } else { using (SvnWorkingCopyClient client = _context.GetService <ISvnClientPool>().GetWcClient()) { SvnWorkingCopyStateArgs a = new SvnWorkingCopyStateArgs(); a.ThrowOnError = false; a.RetrieveFileData = true; SvnWorkingCopyState state; if (client.GetState(FullPath, out state)) { isTextFile = state.IsTextFile; } else { isTextFile = false; } } } if (isTextFile) { SetState(SvnItemState.IsTextFile, SvnItemState.None); } else { SetState(SvnItemState.None, SvnItemState.IsTextFile); } }
void UpdateAttributeInfo() { // One call of the kernel's GetFileAttributesW() gives us most info we need uint value = NativeMethods.GetFileAttributes(FullPath); if (value == NativeMethods.INVALID_FILE_ATTRIBUTES) { // File does not exist / no rights, etc. SetState(SvnItemState.None, SvnItemState.Exists | SvnItemState.ReadOnly | SvnItemState.MustLock | SvnItemState.Versionable | SvnItemState.IsDiskFolder | SvnItemState.IsDiskFile); return; } SvnItemState set = SvnItemState.Exists; SvnItemState unset = SvnItemState.None; if ((value & NativeMethods.FILE_ATTRIBUTE_READONLY) != 0) { set |= SvnItemState.ReadOnly; } else { unset = SvnItemState.ReadOnly; } if ((value & NativeMethods.FILE_ATTRIBUTE_DIRECTORY) != 0) { unset |= SvnItemState.IsDiskFile | SvnItemState.ReadOnly; set = SvnItemState.IsDiskFolder | (set & ~SvnItemState.ReadOnly); // Don't set readonly } else { set |= SvnItemState.IsDiskFile; unset |= SvnItemState.IsDiskFolder; } SetState(set, unset); }
/// <summary> /// Copies all information from other. /// </summary> /// <param name="lead"></param> /// <remarks>When this method is called the other item will eventually replace this item</remarks> void ISvnItemUpdate.RefreshTo(SvnItem lead) { if (lead == null) { throw new ArgumentNullException("lead"); } else if (lead._status == null) { throw new InvalidOperationException("Lead status = null"); } _status = lead._status; _statusDirty = lead._statusDirty; SvnItemState current = lead._currentState; SvnItemState valid = lead._validState; SetState(current & valid, (~current) & valid); _ticked = false; _modified = lead._modified; _cookie = NextCookie(); // Status 100% the same, but changed... Cookies are free ;) }
void RefreshTo(NoSccStatus status, SvnNodeKind nodeKind) { _cookie = NextCookie(); _statusDirty = XBool.False; SvnItemState set = SvnItemState.None; SvnItemState unset = SvnItemState.Modified | SvnItemState.Added | SvnItemState.HasCopyOrigin | SvnItemState.Deleted | SvnItemState.ContentConflicted | SvnItemState.Ignored | SvnItemState.Obstructed | SvnItemState.Replaced | SvnItemState.Versioned | SvnItemState.SvnDirty | SvnItemState.PropertyModified | SvnItemState.PropertiesConflicted | SvnItemState.Conflicted | SvnItemState.Obstructed | SvnItemState.MustLock | SvnItemState.IsWCRoot | SvnItemState.HasProperties | SvnItemState.HasLockToken | SvnItemState.HasCopyOrigin | SvnItemState.MovedHere; switch (status) { case NoSccStatus.NotExisting: SetState(set, SvnItemState.Exists | SvnItemState.ReadOnly | SvnItemState.IsDiskFile | SvnItemState.IsDiskFolder | SvnItemState.Versionable | unset); _status = SvnStatusData.NotExisting; break; case NoSccStatus.NotVersionable: unset |= SvnItemState.Versionable; goto case NoSccStatus.NotVersioned; // fall through case NoSccStatus.NotVersioned: SetState(SvnItemState.Exists | set, SvnItemState.None | unset); _status = SvnStatusData.NotVersioned; break; case NoSccStatus.Unknown: default: SetDirty(set | unset); _statusDirty = XBool.True; break; } InitializeFromKind(nodeKind); }
void RefreshTo(SvnStatusData status) { if (status == null) { throw new ArgumentNullException("status"); } if (status.LocalNodeStatus == SvnStatus.External) { // When iterating the status of an external in it's parent directory // We get an external status and no really usefull information SetState(SvnItemState.Exists | SvnItemState.Versionable | SvnItemState.IsDiskFolder, SvnItemState.IsDiskFile | SvnItemState.ReadOnly | SvnItemState.MustLock | SvnItemState.IsTextFile); if (_statusDirty != XBool.False) { _statusDirty = XBool.True; // Walk the path itself to get the data you want } return; } else if (MightBeNestedWorkingCopy(status) && IsDirectory) { // A not versioned directory might be a working copy by itself! if (_statusDirty == XBool.False) { return; // No need to remove valid cache entries } if (SvnTools.IsManagedPath(FullPath)) { _statusDirty = XBool.True; // Walk the path itself to get the data // Extract useful information we got anyway SetState(SvnItemState.Exists | SvnItemState.Versionable | SvnItemState.Versioned | SvnItemState.IsWCRoot | SvnItemState.IsDiskFolder, SvnItemState.IsDiskFile | SvnItemState.ReadOnly | SvnItemState.MustLock | SvnItemState.IsTextFile); return; } else { SetState(SvnItemState.None, SvnItemState.IsWCRoot); } // Fall through } _cookie = NextCookie(); _statusDirty = XBool.False; _status = status; const SvnItemState unset = SvnItemState.Modified | SvnItemState.Added | SvnItemState.HasCopyOrigin | SvnItemState.Deleted | SvnItemState.ContentConflicted | SvnItemState.Ignored | SvnItemState.Obstructed | SvnItemState.Replaced | SvnItemState.MovedHere; const SvnItemState managed = SvnItemState.Versioned; // Let's assume status is more recent than our internal property cache // Set all caching properties we can bool svnDirty = true; bool exists = true; bool provideDiskInfo = true; switch (status.LocalNodeStatus) { case SvnStatus.None: SetState(SvnItemState.None, managed | unset); svnDirty = false; exists = false; provideDiskInfo = false; break; case SvnStatus.NotVersioned: // Node exists but is not managed by us in this directory // (Might be from an other location as in the nested case) SetState(SvnItemState.None, unset | managed); svnDirty = false; break; case SvnStatus.Ignored: // Node exists but is not managed by us in this directory // (Might be from an other location as in the nested case) SetState(SvnItemState.Ignored, unset | managed); svnDirty = false; break; case SvnStatus.Added: if (status.IsMoved && status.IsCopied) { SetState(managed | SvnItemState.Added | SvnItemState.HasCopyOrigin | SvnItemState.MovedHere, unset); } else if (status.IsCopied) { SetState(managed | SvnItemState.Added | SvnItemState.HasCopyOrigin, unset); } else { SetState(managed | SvnItemState.Added, unset); } if (status.LocalTextStatus == SvnStatus.Modified) { SetState(SvnItemState.Modified, SvnItemState.None); } else if (status.LocalTextStatus == SvnStatus.Normal) { SetState(SvnItemState.None, SvnItemState.Modified); } break; case SvnStatus.Replaced: if (status.IsMoved && status.IsCopied) { SetState(managed | SvnItemState.Replaced | SvnItemState.HasCopyOrigin | SvnItemState.MovedHere, unset); } else if (status.IsCopied) { SetState(managed | SvnItemState.Replaced | SvnItemState.HasCopyOrigin, unset); } else { SetState(managed | SvnItemState.Replaced, unset); } if (status.LocalTextStatus == SvnStatus.Modified) { SetState(SvnItemState.Modified, SvnItemState.None); } else if (status.LocalTextStatus == SvnStatus.Normal) { SetState(SvnItemState.None, SvnItemState.Modified); } break; case SvnStatus.Modified: case SvnStatus.Conflicted: { bool done = false; switch (status.LocalTextStatus) { case SvnStatus.Modified: SetState(managed | SvnItemState.Modified, unset); done = true; break; case SvnStatus.Conflicted: SetState(managed | SvnItemState.ContentConflicted | SvnItemState.Conflicted, unset); done = true; break; } if (!done) { goto case SvnStatus.Normal; } break; } case SvnStatus.Obstructed: // node exists but is of the wrong type SetState(SvnItemState.None, managed | unset); provideDiskInfo = false; // Info is wrong break; case SvnStatus.Missing: exists = false; provideDiskInfo = false; // Info is wrong SetState(managed, unset); break; case SvnStatus.Deleted: SetState(managed | SvnItemState.Deleted, unset); if (status.LocalFileExists) { exists = provideDiskInfo = true; } else { exists = false; provideDiskInfo = false; // Folder might still exist } break; case SvnStatus.External: // Should be handled above throw new InvalidOperationException(); case SvnStatus.Incomplete: SetState(managed, unset); break; default: Trace.WriteLine(string.Format("Ignoring undefined status {0} in SvnItem.Refresh()", status.LocalNodeStatus)); provideDiskInfo = false; // Can't trust an unknown status goto case SvnStatus.Normal; case SvnStatus.Normal: SetState(managed | SvnItemState.Exists, unset); svnDirty = false; break; } if (exists) { SetState(SvnItemState.Versionable, SvnItemState.None); } else { SetState(SvnItemState.None, SvnItemState.Versionable); } if (status.Conflicted) { SetState(SvnItemState.Conflicted, SvnItemState.None); } else { SetState(SvnItemState.None, SvnItemState.Conflicted); } bool hasProperties = true; switch (status.LocalPropertyStatus) { case SvnStatus.None: hasProperties = false; SetState(SvnItemState.None, SvnItemState.PropertiesConflicted | SvnItemState.PropertyModified | SvnItemState.HasProperties); break; case SvnStatus.Modified: SetState(SvnItemState.PropertyModified | SvnItemState.HasProperties, SvnItemState.PropertiesConflicted); svnDirty = true; break; case SvnStatus.Conflicted: SetState(SvnItemState.PropertyModified | SvnItemState.PropertiesConflicted | SvnItemState.HasProperties, SvnItemState.None); svnDirty = true; break; case SvnStatus.Normal: default: SetState(SvnItemState.HasProperties, SvnItemState.PropertiesConflicted | SvnItemState.PropertyModified); break; } if (svnDirty) { SetState(SvnItemState.SvnDirty, SvnItemState.None); } else { SetState(SvnItemState.None, SvnItemState.SvnDirty); } if (!hasProperties) { SetState(SvnItemState.None, SvnItemState.MustLock); } if (provideDiskInfo) { if (exists) // Behaviour must match updating from UpdateAttributeInfo() { switch (status.NodeKind) { case SvnNodeKind.Directory: SetState(SvnItemState.IsDiskFolder | SvnItemState.Exists, SvnItemState.ReadOnly | SvnItemState.MustLock | SvnItemState.IsTextFile | SvnItemState.IsDiskFile); break; case SvnNodeKind.File: SetState(SvnItemState.IsDiskFile | SvnItemState.Exists, SvnItemState.IsDiskFolder); break; default: // Handle direct replacement without an additional stat if (status.LocalFileExists) { goto case SvnNodeKind.File; } break; } } else { SetState(SvnItemState.None, SvnItemState.Exists); } } if (status.IsLockedLocal) { SetState(SvnItemState.HasLockToken, SvnItemState.None); } else { SetState(SvnItemState.None, SvnItemState.HasLockToken); } }
public SvnItemState GetState(SvnItemState flagsToGet) { var unavailable = flagsToGet & ~_validState; if (unavailable == 0) { return(_currentState & flagsToGet); // We have everything we need } if (0 != (unavailable & _maskRefreshTo)) { Debug.Assert(_statusDirty != XBool.False); RefreshStatus(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskRefreshTo) == 0, "RefreshMe() set all attributes it should"); } if (0 != (unavailable & _maskGetAttributes)) { UpdateAttributeInfo(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskGetAttributes) == 0, "UpdateAttributeInfo() set all attributes it should"); } if (0 != (unavailable & _maskUpdateSolution)) { UpdateSolutionInfo(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskUpdateSolution) == 0, "UpdateSolution() set all attributes it should"); } if (0 != (unavailable & _maskDocumentInfo)) { UpdateDocumentInfo(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskDocumentInfo) == 0, "UpdateDocumentInfo() set all attributes it should"); } if (0 != (unavailable & _maskVersionable)) { UpdateVersionable(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskVersionable) == 0, "UpdateVersionable() set all attributes it should"); } if (0 != (unavailable & _maskMustLock)) { UpdateMustLock(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskMustLock) == 0, "UpdateMustLock() set all attributes it should"); } if (0 != (unavailable & _maskTextFile)) { UpdateTextFile(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskTextFile) == 0, "UpdateTextFile() set all attributes it should"); } if (0 != (unavailable & _maskWCRoot)) { UpdateWCRoot(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskWCRoot) == 0, "UpdateWCRoot() set all attributes it should"); } if (0 != (unavailable & _maskIsAdministrativeArea)) { UpdateAdministrativeArea(); unavailable = flagsToGet & ~_validState; Debug.Assert((~_validState & _maskIsAdministrativeArea) == 0, "UpdateIsAdministrativeArea() set all attributes it should"); } if (unavailable != 0) { Trace.WriteLine(string.Format("Don't know how to retrieve {0:X} state; clearing dirty flag", (int)unavailable)); _validState |= unavailable; } return(_currentState & flagsToGet); }
bool ISvnItemUpdate.TryGetState(SvnItemState get, out SvnItemState value) { return(TryGetState(get, out value)); }
void ISvnItemUpdate.SetDirty(SvnItemState dirty) { SetDirty(dirty); }
void ISvnItemUpdate.SetState(SvnItemState set, SvnItemState unset) { SetState(set, unset); }