SourceSafe management with C # removal code
Author: Zheng Zuo 2004-06-15
Other procedures, some solutions have multiple projects, because the code is more, multi-person development, so many projects under VS.NET are controlled with Source Safe. The Source Safe is used to control the local area network path sharing. Therefore, many projects have changed some problems, such as "Solutions seem to be subject to source code, but cannot find its binding information ..." The prompt information is much. Sometimes I have already modified the code, I can't save it, so I want to remove him. The following is some contrast to the project management.
I. Comparison of project projects
Compared with the project management of Source Safe code:
1. Many.scc, .vssscc and .vspscc files;
2. C # project files (.csproj) have added a few lines of labels:
Sccprojectname = "SAK"
SccLocalPath = "SAK"
Sccauxpath = "SAK"
SccProvider = "SAK"
3. In the solution file (.sln), the following node is added:
GlobalSection (SourceCodecontrol) = PRESolution
Sccnumberofprojects = 4
ScclocalPath0 =.
......
SccLocalPath3 = SUBSCRIBE_TOOLS
Cancheckoutshared = false
Endglobalsection
Second, write the implementation
Since the file is increased, some files have been modified, so they want to modify him back by programming, so that I can remove those prompt information, so I wrote the following code.
// ******************************************************** **********
// zhengzuo 2004/06/10 http://blog.9cbs.net/zhzuo
// ******************************************************** **********
Using system;
Using system.io;
Using system.text;
Using system.threading;
Namespace ZZ
{
///
/// Operating information event agent
/// summary>
Public Delegate Void OperateNotifyHandler (Object Sender, VSSEventArgs E);
///
/// VssConverter process solution or project's SourceSafe association.
/// summary>
Public Class VssConverter
{
// Synchronous count private int syncpoint = 0;
// Operate the root directory
PRIVATE STRING OPERATEPATH;
///
/// Operating information event
/// summary>
Public Event OperatenotifyHandler OperationNotify;
///
/// thread end notification event
/// summary>
Public Event EventHandler ThreadCompleted;
///
/// summary>
/// Project path param>
Public vssconverter (String OperatePath)
{
THIS.OPERATEPATH = OPERATEPATH;
}
The OperatePath property is used to set or get the project path that currently needs, but it is best not to set him at runtime.
///
/// Set the solution engineering path
/// summary>
Public String OperatePath
{
Get {returnid.operatepath;}
Set {this.operatepath = value;
}
Below is a function of a public modifier, as well as the unique external public method of class instance, with two threads to delete files and modify files separately.
///
/// Remove Source Safe Code Management
/// summary>
Public void transovevss ()
{
Thread deletethread = new thread (New ThreadStart (deletevssfile);
Thread Removevssidentifythread = New Thread (New ThreadStart (RemovevssIdentify);
deletethread.start ();
REMOVEVSSIDENTIFYTHREAD.START ();
}
Later, I was tested that DELETETHREAD was faster than RemovevssiDentifythread. Of course, I can also open a thread to share the modification of the file, but here I need to pay attention is that a lot of files are read-only attributes, so I have to set the file attribute to Normal. The operation can be successfully completed, otherwise it will throw an exception.
Here, recursive deletion related files, consisting of three functions:
///
/// Thread delegate function, complete the deletion "* .scc", "*. Vsscc", and * .vspscc file function.
/// summary>
Private void deletevssfile ()
{
Deletevssfile (this.operatepath);
// Notice Delete File End Interlocked.Increment (Ref SyncPoint); IF (Interlocked.comPareExchange (Ref SyncPoint, 0, 2) == 2) {ONTHREADCOMPLETED (this, new evenetargs ());}
}
///
/// Recresence function, delete "* .scc", "*. Vsscc", and * .vspscc files.
/// summary>
/// Current processing path param>
Private void deletevssfile (String Path)
{
DELETEFILE (Directory.GetFiles));
Deletefile (Directory.Getfiles (path, "*. Vsscc")); deletefile (Directory.GetFiles));
FOREACH (String Dir in Directory.GetDirectories (PATH))
Deletevssfile (DIR);
}
///
/// Remove the file, really delete the file
/// summary>
/// 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);
}
}
Recursive implementation for the ".sln" solution file and ".csproj '" C # project files are also used:
///
/// Thread Principal, remove the "* .sln" solution file and "* .csproj" C # project file. VSS associated tag.
/// summary>
Private void transovevssidentify ()
{
Removevsstag (this.operatePath);
/ / Notification Removal Label End Interlocked.Increment (Ref SyncPoint); IF (Interlocked.comPareExchange (Ref SyncPoint, 0, 2) == 2) {ONTHREADCOMPLETED (this, new evenetargs ());}
}
///
/// Remove the "* .sln" solution file and "* .csproj" C # project file .vss associated tag.
/// summary>
/// Current processing path param>
Private void transovevsstag (String Path)
{
REMOVETAGCONTENT (Directory.Getfiles));
RemoveTagContent (Directory.GetFiles (PATH, "*. Csproj");
FOREACH (String Dir in Directory.GetDirectories (PATH))
Removevsstag (DIR);
}
The following functions are used to analyze the modification of the file, because they are doing the work of deleting some file content, so write the processing function into one,
///
/// Remove the "* .sln" solution file and "* .csproj" C # project file .vss associated tag.
/// summary>
/// Current processing file param>
Private void removetagcontent (string [] files) {
FOREACH (String File In Files)
{
String strs; // vss label text start content
String strand; // Label text ends
INT OFFSET; / / End the offset of the label text
FileInfo Fi = New FileInfo (file);
Fi.attributes = fileAttributes.Normal;
IF (FI.EXTension == ".SLN") // If it is a solution file
{
strStart = "GlobalSection (Sourcecodecontrol)";
Strend = "EndglobalSection";
OFFSET = 19; // contain / r / n and spaces
}
Else // If it is a project file
{
Strstart = "sccprojectname";
STREND = ">";
OFFSET = 0;
}
Try
{
Int start; // vss label text begins index
INT end; // vss tag text end index
String content; // file 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) // The file needs to remove the label
{
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 "removal tag"))
}
}
Catch (Exception EX)
{
ONOPERATENOTIFY (this, New vsseventargs): " EX.TOSTRING ()));
}
}
}
That do this, the above program implements the main function, but the event defined above, the following is the function of the event,
///
/// Operating information event notification
/// summary>
/// VssConverter param>
/// parameter, param>
Protected Virtual Void OnoperationNotify (Object Sender, vssAndargs E) {
OperatingNotifyHandler Eventop = OperateNotify; if (Eventop! = NULL) Eventop (Sender, E);
}
///
/// thread end event notification
/// summary>
/// VssConverter param>
/// parameter param>
Protected Virtual Void ONTHREADCOMPLETED (Object Sender, Eventargs E)
{
EventHandler Eventop = ThreadCompleted; if (Eventop! = NULL) Eventop (Sender, E);
}
}
Relative to the parameters in the event, define a class from Eventargs inherit, only one field is used to save information,
///
/// Message Notification Event Parameter Class
/// summary>
Public Class vssEventArgs: Eventargs
{
PRIVATE STRING MESSAGE;
///
/// Constructor
/// summary>
/// param>
Public vsseventargs (String Message)
{
THIS.MESSAGE = Message;
}
///
/// Message content
/// summary>
Public String Message
{
Get {return this.Message;}
}
}
}//Namespaces
Third, test use
Program test run interface,
Most of the interface part of the interface is generated by the designer, and the main added code is listed below.
// Delegate, update text box
Private delegate void appendtexthandler (String content);
Private system.windows.Forms.TextBox textboxfolder; // Path text box
Private system.windows.Forms.Button ButtonFolder; // Browse button
Private system.windows.forms.textbox textboxinfo; // information display box
Private system.windows.Forms.Button buttonock; // run button
Private system.windows.Forms.Button ButtonCancel; // Exit button
Button processing function is used to open a path selection box,
Private void ButtonFolder_Click (Object Sender, System.Eventargs E)
{
Folderbrowserdialog mydialog = new folderbrowserdialog ();
MyDialog.ShowneWFolderButton = false;
MyDialog.description = "Select the solution you need to handle or project directory"; if (MyDialog.Showdialog () == DialogResult.ok)
This .TextBoxFolder.Text = mydialog.selectedpath;
MyDialog.dispose ();
}
Run the function, instantiate the VssConverter class here, and call the REMOVEVSS method. If you run a few buttons, you have registered two events, and the information is transmitted, but for entering the illegal path directly in the address bar. Specifically,
Private Void Buttonok_Click (Object Sender, System.EventArgs E)
{
IF (this .textboxfolder.text.length> 1)
{
This .TextBoxInfo.clear ();
This.buttonok.enabled = false;
This .Buttonfolder.enabled = false;
This .Buttoncancel.enabled = false;
this .TextBoxFolder.enabled = false;
VssConverter vssconverter = new vssconverter (this .textboxfolder.text);
VssConverter.operatenotify = new operationenotifyhandler (vssconverter_operatenotify);
vssconverter.threadcompleted = new eventhandler (vssconverter_threadcompleted);
vssconverter.removevss ();
}
Else
Messagebox.show ("Please enter the solution or project path!");
}
Below is the two event handlers, the first is used to instantly display the currently processed file information in the front desk, and the second function is used to notify the thread execution result. The function is as follows.
// information notification
Private void vssconverter_operatenotify (Object Sender, vsseventargs e)
{
AppendTextHandler Ath = new appendtextHandler (THISTEXTBOXINFO.APPpendText); this.textBoxInfo.beginInvoke (Ath, New Object [] {E.MESSAGE Environment.newline});
}
// thread end notification
Private void vssconverter_threadcompleted (Object Sender, Eventargs E)
{
AppendTextHandler Ath = new appendtexthandler (completedwork); this.beginInvoke (Ath, new object [] {"#### conversion completed ####"});
}
private void CompletedWork (string info) {this.buttonOK.Enabled = true; this.buttonFolder.Enabled = true; this.buttonCancel.Enabled = true; this.textBoxFolder.Enabled = true; this.textBoxInfo.AppendText (info);} Summary, the program performs processing according to the file based on the file in the specified directory, which is processed according to the extension, where the thread is increased in order to speed up the running speed. Welcome everyone to communicate.