用C#去除代码的SourceSafe管理
2024-07-21 02:19:24
供稿:网友
 
用c#去除代码的sourcesafe管理
作者:秋枫
 经常看一些的程序,有些一个解决方案带有多个项目,由于代码比较多,多人开发,所以好多vs.net下的工程是用source safe进行版本控制的。而用source safe进行版本控制需要局域网路径共享,因此好多项目换一台机器打开会出现一些问题,比如“解决方案看起来是受源代码管理,但无法找到它的绑定信息……”之类的提示信息很多。有时候修改了代码还保存不了,所以想把他去掉,下面是对项目管理前后的一些对比。
 
 一、工程项目比较
同没有受source safe代码管理的工程相比:
1. 多出了.scc、.vssscc和.vspscc文件;
2. c#项目文件(.csproj)里面添加了几行标签:
sccprojectname = "sak"
scclocalpath = "sak"
sccauxpath = "sak"
sccprovider = "sak"
3.在解决方案文件(.sln)中,中增加了如下节点原素:
 globalsection(sourcecodecontrol) = presolution
 sccnumberofprojects = 4
 scclocalpath0 = .
 ……
scclocalpath3 = subscribe_tools
 cancheckoutshared = false
 endglobalsection
 
二、编写实现的类
既然文件增多了,还有有些文件被修改,所以想通过编程把他修改回原样,这样可能可以去掉那些提示信息,所以就写了下面的代码。
//**********************************************************
// 程序:郑佐 [email protected] 2004/06/10 
// 功能:去除c#.net的原代码source safe 管理
//**********************************************************
using system;
using system.io;
using system.text;
using system.threading;
namespace zz
{
 /// <summary>
 /// 操作信息事件代理
 /// </summary>
 public delegate void operatenotifyhandler(object sender,vsseventargs e);
 /// <summary>
 /// vssconverter 处理解决方案或项目的sourcesafe关联。
 /// </summary>
 public class vssconverter
 {
 //操作根目录
 private string operatepath;
 /// <summary>
 /// 操作信息事件
 /// </summary>
 public event operatenotifyhandler operatenotify;
 /// <summary>
 /// 线程结束通知事件
 /// </summary>
 public event eventhandler threadcompleted;
 /// <summary>
 /// 构造函数
 /// </summary>
 /// <param name="operatepath">项目路径</param>
 public vssconverter(string operatepath)
 {
 this.operatepath = operatepath;
 }
 operatepath属性,用来设置或获取当前需要处理的工程路径,不过在运行时最好不要设置他,
 /// <summary>
 /// 设置解决方案工程路径
 /// </summary>
 public string operatepath
 {
 get{return this.operatepath;}
 set{this.operatepath = value;}
 }
 下面是一个public 修饰符的函数,也是类实例的惟一对外公开的方法,里面用了两个线程来分别删除文件和修改文件。
 /// <summary>
 /// 去除source safe代码管理
 /// </summary>
 public void removevss()
 {
 thread deletethread = new thread(new threadstart(deletevssfile));
 thread removevssidentifythread = new thread(new threadstart(removevssidentify));
 deletethread.start();
 removevssidentifythread.start();
 }
后来测试了一下deletethread的完成要比removevssidentifythread快一些,当然也可以再开一个线程来分担文件的修改,不过这里需要注意的是好多文件是带只读属性的,所以还要把文件属性设置成normal才能顺利完成操作,否则会抛出异常。
这里使用了递归来删除相关文件,由三个函数构成:
 /// <summary>
 /// 线程委托函数,完成删除"*.scc","*.vssscc"以及*.vspscc文件功能。
 /// </summary>
 private void deletevssfile()
 {
 deletevssfile(this.operatepath);
 //通知删除文件结束
 onthreadcompleted(this,new eventargs());
 }
 /// <summary>
 /// 递归函数,删除"*.scc","*.vssscc"以及*.vspscc文件。
 /// </summary>
 /// <param name="path">当前处理路径</param>
 private void deletevssfile(string path)
 {
 deletefile(directory.getfiles(path,"*.scc"));
 deletefile(directory.getfiles(path,"*.vssscc"));
 deletefile(directory.getfiles(path,"*.vspscc"));
 foreach(string dir in directory.getdirectories(path))
 deletevssfile(dir);
 }
 /// <summary>
 /// 删除文件,真正删除文件
 /// </summary>
 /// <param name="files"></param>
 private void deletefile(string [] files)
 {
 foreach(string file in files)
 {
  fileinfo fi = new fileinfo(file);
 fi.attributes = fileattributes.normal;
 file.delete(file);
 onoperatenotify(this,new vsseventargs(file+"删除完成"));
 }
 }
对于".sln"解决方案文件和".csproj’"c#项目文件的修改也采用了递归实现:
 /// <summary>
 /// 线程委托函数,去除"*.sln"解决方案文件和"*.csproj"c#项目文件的.vss关联标签。
 /// </summary>
 private void removevssidentify()
 {
 removevsstag(this.operatepath);
 //通知去除标签结束
 onthreadcompleted(this,new eventargs());
 }
 
 /// <summary>
 /// 去除"*.sln"解决方案文件和"*.csproj"c#项目文件的.vss关联标签。
 /// </summary>
 /// <param name="path">当前处理路径</param>
 private void removevsstag(string path)
 {
 removetagcontent(directory.getfiles(path,"*.sln")); 
 removetagcontent(directory.getfiles(path,"*.csproj"));
 foreach(string dir in directory.getdirectories(path))
 removevsstag(dir);
 }
 下面的函数用来分析处理文件的修改,因为都是做删除部分文件内容的工作,所以把处理函数写成了一个,
 /// <summary>
 /// 去除"*.sln"解决方案文件和"*.csproj"c#项目文件的.vss关联标签。
 /// </summary>
 /// <param name="file">当前处理文件</param>
 private void removetagcontent(string [] files)
 {
 foreach(string file in files)
 {
 string strstart; //vss标签文本开始内容
 string strend; //标签文本结束内容
 int offset;//结束标签文本的偏移量
 fileinfo fi = new fileinfo(file);
 fi.attributes =fileattributes.normal;
 if(fi.extension == ".sln")//如果是解决方案文件
 {
 strstart = "globalsection(sourcecodecontrol)";
 strend = "endglobalsection";
 offset = 19;//包含/r/n和空格
 }
 else//如果是项目文件
 {
 strstart = "sccprojectname";
 strend = ">";
 offset = 0;
 }
 try
 {
 int start;//vss标签文本开始索引
 int end;//vss标签文本结束索引
 string content;//文件内容
 using(filestream fs = new filestream(file,filemode.open,fileaccess.readwrite,fileshare.readwrite))
 {
 streamreader sr = new streamreader(fs);
 content = sr.readtoend();
 sr.close();
 start = content.indexof(strstart);
 }
 if(start!=-1)//文件需要去除标签
 {
 using(filestream fs = new filestream(file,filemode.truncate,fileaccess.write,fileshare.read))
 {
 end = start+content.substring(start).indexof(strend)+offset;
 content = content.substring(0,start)+content.substring(end);
 streamwriter sw = new streamwriter(fs);
 sw.write(content);
 sw.close();
 }
 onoperatenotify(this,new vsseventargs(file+"去除标签完成"));
 }
 }
 catch(exception ex)
 {
 onoperatenotify(this,new vsseventargs(file+"操作错误:"+ex.tostring()));
 }
 } 
 }
当此为止,上面的程序实现了主要的功能,不过上面定义的事件,下面就是关于事件的函数,
 /// <summary>
 /// 操作信息事件通知
 /// </summary>
 /// <param name="sender">vssconverter</param>
 /// <param name="e">参数,</param>
 protected virtual void onoperatenotify(object sender,vsseventargs e)
 {
 if(operatenotify!=null)
 operatenotify(sender,e);
 }
 /// <summary>
 /// 线程结束事件通知
 /// </summary>
 /// <param name="sender">vssconverter</param>
 /// <param name="e">参数</param>
 protected virtual void onthreadcompleted(object sender,eventargs e)
 {
 if(threadcompleted!=null)
 threadcompleted(sender,e);
 }
}
相对于事件中的参数,这里定义了一个类从eventargs继承,里面只包含一个字段用来保存信息,
/// <summary>
 /// 消息通知事件参数类
 /// </summary>
 public class vsseventargs : eventargs
 {
 private string message;
 /// <summary>
 /// 构造函数
 /// </summary>
 /// <param name="message"></param>
 public vsseventargs(string message)
 {
 this.message = message;
 }
 /// <summary>
 /// 消息内容
 /// </summary>
 public string message
 {
 get{return this.message;}
 }
}
}//命名空间