/// (c) 2007 James A Briant /// /// Permission is granted to use or modify this source code provided that /// a) this notice is kept intact /// b) if you make any modications to this file you assign the /// copyright of those modifications to James Briant. /// c) you acknowledge that Mr. Briant offers no warranty /// and will not be liable for any loss, damages, time, etc. /// /// Any doubt, email me: firstname (nospace) lastname at persuasivesoftware.com /// /// This package is inspired by Noel Llopis's P4AddIn (also available from /// the perforce public depot), and also a similar package that I developed /// at Bunkspeed, Inc ( www.bunkspeed.com ) makers of real-time raytracing /// tools that anyone can use. using System.IO; using DevDriven.P4Vs; using DevDriven.P4Vs.External; namespace DevDriven.P4Vs.External { class PerforceCmds { private readonly ICmdExec exec; private readonly ILogger log; private readonly P4Wrapper wrapper; public PerforceCmds(ICmdExec exec, ILogger log) { this.exec = exec; this.log = log; wrapper = new P4Wrapper(exec, log); } public bool CheckInstallation() { if (exec.Exec("p4.exe", "info", "C:\\") != 0) { log.WriteLine(5, "Error executing p4.exe"); return false; } return true; } public void AddFile(string filename) { if (filename==null || filename=="" || Directory.Exists(filename)) return; FileStatus stat = wrapper.GetFileStatus(filename); if (stat == FileStatus.OpenedForDelete) { wrapper.Revert(filename, true); } wrapper.Add(filename); } public void RenameFile( string oldpath, string newpath) { FileStatus estat = wrapper.GetFileStatus(newpath); switch( estat) { case FileStatus.OpenedForDelete: case FileStatus.OpenedForAdd: case FileStatus.OpenedForBranch: wrapper.Revert(newpath, true); break; case FileStatus.InDepot: case FileStatus.NotInDepot: break; case FileStatus.Error: case FileStatus.OpenedForIntegrate: case FileStatus.OpenedForEdit: log.WriteLine(5,"Error: target file {1} status is {0}", estat, newpath); return; } string tempfile = Path.GetTempFileName(); log.WriteLine(1,"{0}: saving local changes to temp file {1}", oldpath, tempfile); try { File.Copy(newpath, tempfile,true); } catch( IOException e) { log.WriteLine(5, "Attempted to save file {0} as {1} for backup but got error {2}", newpath, tempfile, e); return; } bool deleteTemp = true; FileStatus stat = wrapper.GetFileStatus(oldpath); switch( stat ) { case FileStatus.InDepot: // need to delete the current one wrapper.Integrate(oldpath, newpath); wrapper.Delete(oldpath); wrapper.Edit(newpath); File.Copy(tempfile,newpath,true); break; case FileStatus.OpenedForAdd: wrapper.Revert(oldpath, false); wrapper.Add(newpath); break; case FileStatus.OpenedForDelete: // eh? Whats it doing there then? wrapper.Add(newpath); break; case FileStatus.OpenedForEdit: wrapper.Integrate(oldpath, newpath); wrapper.Edit(newpath); wrapper.Revert(oldpath, true); wrapper.Delete(oldpath); try { File.Copy(tempfile, newpath, true); } catch( IOException e ) { log.WriteLine(5,"Failed to recreate copy on top of p4 when renaming {0} to {1} using tempfile {2}. Error {3}", oldpath, newpath, tempfile, e); deleteTemp = false; } break; case FileStatus.NotInDepot: case FileStatus.Error: wrapper.Add(newpath); wrapper.Edit(newpath); break; case FileStatus.OpenedForBranch: case FileStatus.OpenedForIntegrate: log.WriteLine(5, "Unable to rename file {0} in perforce because it is already opened for branch/integrate. You will need to resolve this manually.", oldpath); break; } if ( deleteTemp) { DeleteCmd(tempfile); } } private void DeleteCmd(string tempfile) { exec.Exec("cmd.exe",string.Format("/c del /F \"{0}\"", tempfile), Path.GetDirectoryName(tempfile)); } public void CheckBeforeSave(string filename) { FileInfo fi = new FileInfo(filename); if (!fi.Exists) { // Cannot do things like open for add, because we can't figure out what type it is. return; } OpenForEdit(filename); } public void DeleteFile(string s) { FileStatus stat = wrapper.GetFileStatus(s); switch(stat) { case FileStatus.InDepot: wrapper.Delete(s); break; case FileStatus.OpenedForAdd: wrapper.Revert(s, false); break; case FileStatus.OpenedForEdit: case FileStatus.OpenedForIntegrate: case FileStatus.OpenedForBranch: wrapper.Revert(s, false); wrapper.Delete(s); break; } } public void DisplayDiff( string path) { exec.Start("p4win", string.Format("-D {0}", path),Path.GetDirectoryName(path)); } public void DisplayHistory(string path) { exec.Start("p4win", string.Format("-H {0}", path), Path.GetDirectoryName(path)); } public void DisplayBrowser(string path) { exec.Start("p4win", string.Format("-s {0}", path), Path.GetDirectoryName(path)); } public void Revert(string path) { wrapper.Revert(path, false); } public void OpenForEdit(string filename) { FileStatus stat = wrapper.GetFileStatus(filename); if (stat == FileStatus.OpenedForDelete) { wrapper.Revert(filename, true); } else if (stat == FileStatus.NotInDepot) { wrapper.Add(filename); return; } else if (stat == FileStatus.OpenedForAdd) { return; } else if (stat == FileStatus.OpenedForEdit) { // system thinks its already open, check to see if its writable. FileInfo fi = new FileInfo(filename); if (fi.Exists && fi.IsReadOnly) { try { fi.IsReadOnly = false; } catch( System.IO.IOException e) { log.Write(5,"Error attempting to make file {0} writable:\n{1}",e); } } } wrapper.Edit(filename); } public void CheckAfterSave(string filename) { OpenForEdit(filename); } } }