Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C# » How To » Downloads
 
Add your own
alternative version

Accessing CVS Repository with C#

, 24 Nov 2004
An article on accessing a CVS repositry using C#.
cvs_interface_source.zip
ConsoleApplication1
App.ico
ConsoleApplication1.csproj.user
CVSInterface
CVSInterface.csproj.user
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace CVSInterface
{

	/// <summary>
	/// Interface class for running CVS commands
	/// </summary>
	public class CVSCommand
	{

		/// <summary>
		/// The monitoring process
		/// </summary>
		protected Thread monitor = null;

		/// <summary>
		/// The process we are running
		/// </summary>
		protected Process p = null;

		/// <summary>
		/// The command string
		/// </summary>
		protected string command = "";

		/// <summary>
		/// The Working Directory in which to execute the command
		/// </summary>
		protected string workingDirectory = "";

		/// <summary>
		/// Get/Set the Working directory for running the command
		/// </summary>
		public string WorkingDirectory 
		{
			get
			{
				return workingDirectory;
			}
			set
			{
				workingDirectory = value;
			}
		}


		/// <summary>
		/// The CVS Root Environment Variable
		/// </summary>
		protected string cvsRoot = "";

		/// <summary>
		/// Get/Set the CVS Root Environment Variable
		/// </summary>
		public string CvsRoot
		{
			get
			{
				return cvsRoot;
			}
			set
			{
				cvsRoot = value;
			}
		}


		/// <summary>
		/// The CVS RSH Environment Variable
		/// </summary>
		protected string cvsRsh = "";

		/// <summary>
		/// Get/Set the CVS Root Environment Variable
		/// </summary>
		public string CvsRsh
		{
			get
			{
				return cvsRsh;
			}
			set
			{
				cvsRsh = value;
			}
		}


		/// <summary>
		/// Is the CVS command running 
		/// </summary>
		public bool Running
		{
			get
			{
				if (p == null)
					return false;
				return (p.HasExited == false);
			}
		}


		/// <summary>
		/// The output from the CVS command
		/// </summary>
		protected string output = "";

		/// <summary>
		/// Get the output from the cvs command
		/// </summary>
		public string Output
		{
			get
			{				
				return output;
			}
		}


		/// <summary>
		/// Default Constructor
		/// </summary>
		/// <param name="cmd">The command to perform</param>
		public CVSCommand (string cmd)
		{
			command = cmd;
		}


		/// <summary>
		/// Find a setion in the output log
		/// </summary>
		/// <param name="section">The name of the section to find</param>
		/// <returns>The section value</returns>
		protected string FindSection(string section)
		{
			int idx = this.Output.ToUpper().IndexOf(section.ToUpper());
			if (idx < 0)
				return "";

			string val = this.Output.Substring(idx+section.Length);
			string temp = "";
			for (int i=0; i<val.Length; i++)
			{
				if (Char.IsControl (val[i]) == true)
					break;
				temp += val[i];
			}
			return temp.Trim();

		}


		/// <summary>
		/// Find a list in the output log
		/// </summary>
		/// <param name="section">The name of the section to find</param>
		/// <returns>The section list values</returns>
		protected string[] FindList(string section)
		{

			// Make sure the section exists
			int idx = this.Output.ToUpper().IndexOf(section.ToUpper());
			if (idx < 0)
				return new string[0];

			string newItem = "\r"+"\n"+"\t";

			// Process through looking for items
			ArrayList list = new ArrayList();
			string val = this.Output.Substring(idx+section.Length);		
			while (val.StartsWith(newItem) == true)
			{
				val = val.Substring(newItem.Length);
				string item = "";
				for (int i=0; i<val.Length; i++)
				{
					if (Char.IsControl(val[i]) == true)
					{
						val = val.Substring(i);
						break;
					}
					item += val[i];
				}				
				list.Add(item.Trim());

			}
			
			string[] items = new string[list.Count];
			list.CopyTo(0, items, 0, list.Count);
			return items;

		}


		/// <summary>
		/// Start running the command
		/// </summary>
		public void Start()
		{

			// Do not allow if already running
			if (this.Running == true)
				return;

			ProcessStartInfo i = new ProcessStartInfo("cvs", command);			
			i.UseShellExecute = false;
			if (this.CvsRoot.Length != 0)
				i.EnvironmentVariables.Add("CVSROOT", this.CvsRoot);
			if (this.CvsRsh.Length != 0)
				i.EnvironmentVariables.Add("CVS_RSH", this.CvsRsh);		
			if (this.WorkingDirectory.Length != 0)
				i.WorkingDirectory = this.WorkingDirectory;
			i.RedirectStandardOutput = true;
			i.CreateNoWindow = true;
			p = Process.Start(i);		

			monitor = new Thread(new System.Threading.ThreadStart(MonitorMain));
			monitor.Start();

		}


		/// <summary>
		/// Stop the process from running
		/// </summary>
		public void Stop()
		{
			if (this.Running == false)
				return;
			p.Kill();
		}


		/// <summary>
		/// Wait until command has completed
		/// </summary>
		public void WaitDone()
		{
			if (p == null)
				return;
			p.WaitForExit();
		}
		

		/// <summary>
		/// Thread for monitoring the process
		/// </summary>
		protected void MonitorMain()
		{

			// While the command is running
			string txt = "";
			while (this.Running == true)
			{

				// Get lines from the port
				txt = p.StandardOutput.ReadLine();
	
				// Release time or add to buffer
				if (txt == null)
					Thread.Sleep(10);
				else
					this.output += txt + Environment.NewLine;

			}

			// Get any trailing lines
			do
			{

				// Get lines from the port
				txt = p.StandardOutput.ReadLine();
	
				// Add to buffer
				if (txt != null)
					this.output += txt + Environment.NewLine;

			} while (txt != null);


		}


	}


	/// <summary>
	/// Get the history of a file
	/// </summary>
	public class CVSGetFileHistory : CVSCommand
	{

		/// <summary>
		/// The RCS File
		/// </summary>
		public string RCSFile
		{
			get
			{
				return FindSection("RCS file:");
			}
		}


		/// <summary>
		/// The Working File
		/// </summary>
		public string WorkingFile
		{
			get
			{
				return FindSection("Working file:");
			}
		}


		/// <summary>
		/// The Head
		/// </summary>
		public string Head
		{
			get
			{
				return FindSection("Head:");
			}
		}


		/// <summary>
		/// The Branch
		/// </summary>
		public string Branch
		{
			get
			{
				return FindSection("Branch:");
			}
		}


		/// <summary>
		/// Lock State
		/// </summary>
		public string Locks
		{
			get
			{
				return FindSection("Locks:");
			}
		}


		/// <summary>
		/// The Access List
		/// </summary>
		public string AccessList
		{
			get
			{
				return FindSection("Access List:");
			}
		}


		/// <summary>
		/// The symbolic names for the class
		/// </summary>
		public CVSSymbolList SymbolicNames
		{
			get
			{
				string[] list = FindList("Symbolic Names:");
				CVSSymbolList sList = new CVSSymbolList();
				for (int i=0; i<list.Length; i++)
					sList.Add(new CVSSymbol(WorkingFile, list[i]));
				return sList;
			}
		}


		/// <summary>
		/// Get the file history
		/// </summary>
		public CVSHistoryItemList History
		{
			get
			{

				// Create empty history list
				CVSHistoryItemList list = new CVSHistoryItemList();

				// Find the section
				string section = "description:";
				int idx = this.Output.ToUpper().IndexOf(section.ToUpper());
				if (idx < 0)
					return list;

				// Get the items
				string val = this.Output.Substring(idx+section.Length);
				string separator = "\r\n--";
				while (val.StartsWith(separator) == true)
				{

					// Get the text for the history item
					val = val.Substring(separator.Length);

					// Strip of the full separator
					idx = val.IndexOf("\r\n");
					if (idx >= 0)
						val = val.Substring(idx);

					idx = val.IndexOf(separator);
					string txt = "";
					if (idx >= 0)
						txt = val.Substring(0, idx);
					else
						txt = val;

					// Create history item
					CVSHistoryItem item = new CVSHistoryItem(WorkingFile, WorkingDirectory, txt);
					list.Add(item);

					// Target to next history item
					val = val.Substring(txt.Length);

				}

				
				
				return list;
			}
		}


		/// <summary>
		/// Construct a CVS history command
		/// </summary>
		/// <param name="file">The file to extract</param>
		public CVSGetFileHistory(string file) : base("log "+file)
		{
		}


	}


	/// <summary>
	/// Defines a Symbol for a CVS File
	/// </summary>
	public class CVSSymbol
	{

		/// <summary>
		/// The name of the symbol
		/// </summary>
		private string name = "";

		/// <summary>
		/// Get the name of the symbol
		/// </summary>
		public string Name
		{
			get
			{
				return name;
			}
		}


		/// <summary>
		/// The version of the associated file 
		/// </summary>
		private CVSVersion version = null;

		/// <summary>
		/// Get the version of the associated file
		/// </summary>
		public CVSVersion Version
		{
			get
			{
				return version;
			}
		}


		/// <summary>
		/// The associated file 
		/// </summary>
		private string file = "";

		/// <summary>
		/// Get the associated file
		/// </summary>
		public string File
		{
			get
			{
				return file;
			}
		}


		/// <summary>
		/// Construct a Symbol reference
		/// </summary>
		/// <param name="f">The file the reference belongs to</param>
		/// <param name="line">The line defining the name and version</param>
		public CVSSymbol(string f, string line)
		{
			file = f;
			int idx = line.IndexOf(":");
			this.name = line.Substring(0, idx);
			this.version = new CVSVersion(line.Substring(idx+1).Trim());
		}

	}


	/// <summary>
	/// Collection of Symbol items
	/// </summary>
	public class CVSSymbolList : CollectionBase, IEnumerator
	{

		/// <summary>
		/// The Current Item In List
		/// </summary>
		private int current = 0;
		
		/// <summary>
		/// Add an item to the Collection
		/// </summary>
		/// <param name="item">The item to add</param>
		public void Add(CVSSymbol item)
		{
			List.Add(item);
		}


		/// <summary>
		/// Insert An item Into The List
		/// </summary>
		/// <param name="index">The zero based index position</param>
		/// <param name="item">The item to insert</param>
		public void Insert(int index, CVSSymbol item)
		{
			List.Insert(index, item);
		}

		
		/// <summary>
		/// Remove An item From The List
		/// </summary>
		/// <param name="index">The zero based index at which to remove</param>
		public void Remove(int index)
		{
			// Check to see if there is a block at the supplied index.
			if (index > Count - 1 || index < 0)
			{
				throw new System.ArgumentOutOfRangeException("index", index, "Index Is Invalid");
			}
			else
			{
				List.RemoveAt(index); 
			}
		}


		/// <summary>
		/// Indexer For The Item Property
		/// </summary>
		public CVSSymbol this[int Index]
		{

			get { return (CVSSymbol) List[Index]; }
			set { List[Index] = value; }

		}


		/// <summary>
		/// Indexer For The Item Property
		/// </summary>
		public CVSSymbol this[string Name]
		{

			get 
			{ 
				for (int i=0; i<List.Count; i++)
				{
					if (this[i].Name == Name)
						return this[i];
				}
				return null;
			}			

		}


		/// <summary>
		/// Enumerator Object: Move to Next Item
		/// </summary>
		/// <returns>Was the move next successful. false = end of list reached</returns>
		bool IEnumerator.MoveNext()
		{
			if (current >= List.Count) return false;
			current++;
			return true;
		}


		/// <summary>
		/// Enumerator Object: Reset Current Item
		/// </summary>
		void IEnumerator.Reset()
		{
			current = 0;
		}
		

		/// <summary>
		/// Enumerator Object: Return Current Item
		/// </summary>
		object IEnumerator.Current
		{
			get { return (CVSSymbol) List[current];}	
		}


	}


	/// <summary>
	/// Defines a CVS History Item
	/// </summary>
	public class CVSHistoryItem
	{

		/// <summary>
		/// The location of the file 
		/// </summary>
		private string directory = "";

		/// <summary>
		/// Get the location of the file
		/// </summary>
		public string Directory
		{
			get
			{
				return directory;
			}
		}


		/// <summary>
		/// The associated file 
		/// </summary>
		private string file = "";

		/// <summary>
		/// Get the associated file
		/// </summary>
		public string File
		{
			get
			{
				return file;
			}
		}


		/// <summary>
		/// The revision of the item
		/// </summary>
		private CVSVersion revision = null;

		/// <summary>
		/// Get the revision of the item
		/// </summary>
		public CVSVersion Revision
		{
			get
			{
				return revision;
			}
		}


		/// <summary>
		/// The date of the history item
		/// </summary>
		private DateTime date = DateTime.Now;

		/// <summary>
		/// Get the date of the history item
		/// </summary>
		public DateTime Date
		{
			get
			{
				return date;
			}
		}


		/// <summary>
		/// The author of the change
		/// </summary>
		private string author = "";

		/// <summary>
		/// Get the author of the change
		/// </summary>
		public string Author
		{
			get
			{
				return author;
			}
		}


		/// <summary>
		/// The state of the change
		/// </summary>
		private string state = "";

		/// <summary>
		/// Get the state of the changes
		/// </summary>
		public string State
		{
			get
			{
				return state;
			}
		}


		/// <summary>
		/// The lines involved in the change
		/// </summary>
		private string lines = "";

		/// <summary>
		/// Get the lines involved in the change
		/// </summary>
		public string Lines
		{
			get
			{
				return lines;
			}
		}


		/// <summary>
		/// The description of the change
		/// </summary>
		private string description = "";

		/// <summary>
		/// Get the description for the change
		/// </summary>
		public string Description
		{
			get
			{
				return description;
			}
		}


		/// <summary>
		/// Construct a History Item 
		/// </summary>
		/// <param name="f">The file the reference belongs to</param>
		/// <param name="dir">The directory the file is located in</param>
		/// <param name="line">The line defining the history item</param>
		public CVSHistoryItem(string f, string dir, string line)
		{
			file = f;
			string rev = FindItem("Revision", line);
			this.revision = new CVSVersion(rev);

			string d = FindItem("Date:", line);
			if (d.Length!=0)
			{
				try
				{
					date = DateTime.Parse(d);
				}
				catch (Exception)
				{
				}
			}
			author = FindItem("Author:", line);
			state = FindItem("State:", line);
			lines = FindItem("Lines:", line);
			description = FindDescription(line);
			directory = dir;
		}


		/// <summary>
		/// Find an item in the log text
		/// </summary>
		/// <param name="section">The name of the item to find</param>
		/// <param name="line">The line that contains the data</param>
		/// <returns>The item value</returns>
		private string FindItem(string name, string line)
		{
			int idx = line.ToUpper().IndexOf(name.ToUpper());
			if (idx < 0)
				return "";

			string val = line.Substring(idx+name.Length);
			string temp = "";
			for (int i=0; i<val.Length; i++)
			{
				if (Char.IsControl (val[i]) == true)
					break;
				if (val[i] == ';')
					break;
				temp += val[i];
			}
			return temp.Trim();

		}


		/// <summary>
		/// Get the history description
		/// </summary>		
		/// <param name="line">The line that contains the data</param>
		/// <returns>The description</returns>
		private string FindDescription(string line)
		{
			int idx = line.LastIndexOf("\r\n");
			if (idx < 0)
				return "";

			string val = line.Substring(idx+2);
			string temp = "";
			for (int i=0; i<val.Length; i++)
			{
				if (Char.IsControl (val[i]) == true)
					break;
				if (val[i] == ';')
					break;
				temp += val[i];
			}
			return temp.Trim();

		}


	}


	/// <summary>
	/// Collection of History items
	/// </summary>
	public class CVSHistoryItemList : CollectionBase, IEnumerator
	{

		/// <summary>
		/// The Current Item In List
		/// </summary>
		private int current = 0;
		
		/// <summary>
		/// Add an item to the Collection
		/// </summary>
		/// <param name="item">The item to add</param>
		public void Add(CVSHistoryItem item)
		{

			for (int i=0; i<List.Count; i++)
			{				
				if (item.Date > this[i].Date)
				{
					List.Insert(i, item);
					return;
				}
			}

			List.Add(item);

		}


		/// <summary>
		/// Insert An item Into The List
		/// </summary>
		/// <param name="index">The zero based index position</param>
		/// <param name="item">The item to insert</param>
		public void Insert(int index, CVSHistoryItem item)
		{
			List.Insert(index, item);
		}

		
		/// <summary>
		/// Remove An item From The List
		/// </summary>
		/// <param name="index">The zero based index at which to remove</param>
		public void Remove(int index)
		{
			// Check to see if there is a block at the supplied index.
			if (index > Count - 1 || index < 0)
			{
				throw new System.ArgumentOutOfRangeException("index", index, "Index Is Invalid");
			}
			else
			{
				List.RemoveAt(index); 
			}
		}


		/// <summary>
		/// Indexer For The Item Property
		/// </summary>
		public CVSHistoryItem this[int Index]
		{

			get { return (CVSHistoryItem) List[Index]; }
			set { List[Index] = value; }

		}


		/// <summary>
		/// Enumerator Object: Move to Next Item
		/// </summary>
		/// <returns>Was the move next successful. false = end of list reached</returns>
		bool IEnumerator.MoveNext()
		{
			if (current >= List.Count) return false;
			current++;
			return true;
		}


		/// <summary>
		/// Enumerator Object: Reset Current Item
		/// </summary>
		void IEnumerator.Reset()
		{
			current = 0;
		}
		

		/// <summary>
		/// Enumerator Object: Return Current Item
		/// </summary>
		object IEnumerator.Current
		{
			get { return (CVSHistoryItem) List[current];}	
		}


	}


	/// <summary>
	/// Represents a CVS Version number
	/// </summary>
	public class CVSVersion
	{

		/// <summary>
		/// The CVS Version string
		/// </summary>
		private string version;

		/// <summary>
		/// Get/Set the CVS Version string
		/// </summary>
		public string Version
		{
			get
			{
				return version;
			}
			set
			{
				version = "";
			}
		}


		/// <summary>
		/// Get the major version number
		/// </summary>
		protected int MajorVersion
		{
			get
			{

				// Make sure we are valid
				if (IsValid == false)
					return 0;

				// Find something of the format "x.y"
				int idx = version.IndexOf(".");
				
				// Get the major version part
				return int.Parse(version.Substring(0, idx));

			}
		}


		/// <summary>
		/// Get the Minor version number
		/// </summary>
		protected int MinorVersion
		{
			get
			{

				// Make sure we are valid
				if (IsValid == false)
					return 0;

				// Find something of the format "x.y"
				int idx = version.IndexOf(".");
				
				string temp = version.Substring(idx+1);
				idx = temp.IndexOf(".");
				if (idx >= 0)
					temp = temp.Substring(0, idx);

				// Get the major version part
				return int.Parse(temp);

			}
		}


		/// <summary>
		/// Determine if the string is valid
		/// </summary>
		public bool IsValid
		{
			get
			{

				// If version string does not exist
				if (version == null)
					return false;

				// Find something of the format "x.y"
				int idx = version.IndexOf(".");
				if (idx<0)
					return false;

				// Make sure all characters are numeric or "."
				foreach (char c in version)
				{
					if (Char.IsDigit(c) == false)
					{
						if (c != '.')
							return false;
					}
				}

				return true;

			}
		}


		/// <summary>
		/// Create a version string: Default Constructor
		/// </summary>		
		public CVSVersion ()
		{
			version = "0.0";
		}
		

		/// <summary>
		/// Create a version string 
		/// </summary>
		/// <param name="rev">The revision string</param>		
		public CVSVersion (string rev)
		{
			version = rev;
		}
		

		/// <summary>
		/// Determine if 2 version strings are equal
		/// </summary>
		/// <param name="v1">The first version to compare</param>
		/// <param name="v2">The second version to compare</param>
		/// <returns>Are the 2 versions equal</returns>
		public static bool operator ==(CVSVersion v1, CVSVersion v2) 
		{
			if (v1.MajorVersion != v2.MajorVersion)
				return false;
			if (v1.MinorVersion != v2.MinorVersion)
				return false;
			return true;
		}


		/// <summary>
		/// Determine if 2 version strings are NOT equal
		/// </summary>
		/// <param name="v1">The first version to compare</param>
		/// <param name="v2">The second version to compare</param>
		/// <returns>Are the 2 versions equal</returns>
		public static bool operator !=(CVSVersion v1, CVSVersion v2) 
		{
			return ((v1 == v2) == false);
		}


		/// <summary>
		/// Determine if 2 version strings are equal
		/// </summary>
		/// <param name="v1">The first version to compare</param>
		/// <param name="v2">The second version to compare</param>
		/// <returns>Are the 2 versions equal</returns>
		public static bool operator >(CVSVersion v1, CVSVersion v2) 
		{
			if (v1.MajorVersion > v2.MajorVersion)
				return true;
			if (v1.MinorVersion > v2.MinorVersion)
				return true;
			return false;
		}


		/// <summary>
		/// Determine if 2 version strings are equal
		/// </summary>
		/// <param name="v1">The first version to compare</param>
		/// <param name="v2">The second version to compare</param>
		/// <returns>Are the 2 versions equal</returns>
		public static bool operator <(CVSVersion v1, CVSVersion v2) 
		{
			if (v1.MajorVersion < v2.MajorVersion)
				return true;
			if (v1.MinorVersion < v2.MinorVersion)
				return true;
			return false;
		}


		/// <summary>
		/// Determine if 2 version strings are equal
		/// </summary>
		/// <param name="v1">The first version to compare</param>
		/// <param name="v2">The second version to compare</param>
		/// <returns>Are the 2 versions equal</returns>
		public static bool operator >=(CVSVersion v1, CVSVersion v2) 
		{
			if (v1.MajorVersion >= v2.MajorVersion)
				return true;
			if (v1.MinorVersion >= v2.MinorVersion)
				return true;
			return false;
		}


		/// <summary>
		/// Determine if 2 version strings are equal
		/// </summary>
		/// <param name="v1">The first version to compare</param>
		/// <param name="v2">The second version to compare</param>
		/// <returns>Are the 2 versions equal</returns>
		public static bool operator <=(CVSVersion v1, CVSVersion v2) 
		{
			if (v1.MajorVersion <= v2.MajorVersion)
				return true;
			if (v1.MinorVersion <= v2.MinorVersion)
				return true;
			return false;
		}


		/// <summary>
		/// Determine object equality
		/// </summary>
		/// <param name="obj"></param>
		/// <returns></returns>
		public override bool Equals(object obj)
		{
			return base.Equals (obj);
		}


		/// <summary>
		/// Return HasCode for object storeage
		/// </summary>
		/// <returns>The hascode</returns>
		public override int GetHashCode()
		{
			return base.GetHashCode ();
		}


		/// <summary>
		/// Print out the revision string
		/// </summary>
		/// <returns>The revision string</returns>
		public override string ToString()
		{
			return version;
		}


	}
	
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Jay Nelson
Web Developer
United States United States
I have been developing software professionaly since 1991 writing software in Automation and Manufacturing environments. For 14 years I worked for companies that built custom robotic automated equipment for the semiconductor, telecommunications, and other industies. Presently, I work for a medical device manufacturer developing applications for the compact framework.

My undergraduate degrees are in Mathematics and Philosopy. My graduate degree is in Management Information Systems. I am MCSD certified in Visual C++ 6.0 and MCSD.NET certified in C#.

I enjoy triathlons and reading.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.150414.1 | Last Updated 25 Nov 2004
Article Copyright 2004 by Jay Nelson
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid