Click here to Skip to main content
15,893,622 members
Articles / Desktop Programming / Windows Forms

GBackupSolution - Visual Studio Extension VSX 2008/2010

Rate me:
Please Sign up or sign in to vote.
4.92/5 (54 votes)
17 Mar 2010CPOL9 min read 85.2K   1.1K   93  
Visual Studio 2008/2010 Extension for backing-up your solution to Gmail.
using System;
using System.Collections.Generic;
using System.IO;
using System.Net.Mail;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using EnvDTE;
using EnvDTE80;
using Ionic.Zip;
using Ionic.Zlib;
using Thread=System.Threading.Thread;

namespace GBackupSolution.Core
{
    class ClsBackup
    {
        string SolutionFile { get; set; }
        string SolutionFileBackup { get
        {
            return SolutionFile + ".bk";
        }}

        string SolutionPath { get; set; }
        string SolutionName { get; set; }
     
        string BackupFile { get; set; }

        int NumberItem { get; set; }
        long TotalLine { get; set; }
        long TotalChar { get; set; }
        long UncompressSize { get; set; }

        bool NeedToReplace { get; set;}
       
        List<ItemFile> ItemList { get; set;}
        List<string> DeleteList { get; set;}

        private DTE2 applicationObject;
        public ClsSetting settings;

        public ClsBackup(DTE2 passedDTE)
        {
            applicationObject = passedDTE;
            SolutionFile = applicationObject.Solution.FileName;
            SolutionPath = Path.GetDirectoryName(SolutionFile);
            SolutionName = Path.GetFileNameWithoutExtension(SolutionFile);

            settings = applicationObject.Globals.get_VariableExists("GBackupSolutionData") ? ClsSetting.LoadFromString(applicationObject.Globals["GBackupSolutionData"] as string) : ClsSetting.LoadDefault();

            // Create new list
            ItemList = new List<ItemFile>();
            DeleteList = new List<string>();

            NumberItem = 0;
            TotalLine = 0;
            TotalChar = 0;
            UncompressSize = 0;
        }

        public void StartToBackup()
        {
            try
            {
                var thrMainThread = new Thread(DoBackUp);
                thrMainThread.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), "ClsBackup contructor error", MessageBoxButtons.OK);                
            }

            // NOTE: for testing
            // DoBackUp();
        }

        private void DoBackUp()
        {
            // Step1 : Get all items.
            if (GetAllItems())
            {
                // Step2 : Zip all items.
                if (DoZip())
                {
                    // Step3 : Send to Gmail.
                    if (!settings.OtherBackupLocally)
                        SendToGmail();
                    else if (settings.OtherPromptDone)
                    {
                        applicationObject.StatusBar.Text = "Backup solution to file successfully!";
                        MessageBox.Show("Backup solution to file successfully!", "Successfully!", MessageBoxButtons.OK,
                                        MessageBoxIcon.Information);
                    }
                }
                else
                {
                    applicationObject.StatusBar.Text = "FAILED to backup solution to file!";
                    MessageBox.Show("FAILED to backup solution to file!", "FAILED!", MessageBoxButtons.OK,
                                    MessageBoxIcon.Information);
                }
            }
            // Do something here
        }

        private bool GetAllItems()
        {
            try
            {
                applicationObject.StatusBar.Text = "Getting all project files...";

                foreach (Project project in applicationObject.Solution.Projects)
                {
                    bool bIsExternal = false;
                    bool bIsBackup = false;

                    var strProjectPath = "";
                    var strProjectFolder = "";

                    if (project.Name.Contains("Miscellaneous"))
                        continue;

                    // Detect if this project is external.
                    if (project.FileName == project.UniqueName || project.FullName == project.UniqueName)
                    {
                        bIsExternal = true;
                        strProjectPath = project.UniqueName;
                    }
                    else
                        strProjectPath = Path.Combine(SolutionPath, project.UniqueName);

                    // Exit if a project file does not exist
                    if (!File.Exists(strProjectPath))
                        continue;

                    #region Modify Solution file with external project
                    // If a project is external and the *.sln file is not modified yet
                    if (bIsExternal && !NeedToReplace)
                    {
                        // Make a new copy of Solution file
                        if (!File.Exists(SolutionFileBackup))
                            File.Copy(SolutionFile, SolutionFileBackup);
                        
                        // Change to project path to new one
                        var rd = new StreamReader(SolutionFileBackup);
                        var slnContent = rd.ReadToEnd();
                        rd.Close();
                        rd.Dispose();

                        File.Delete(SolutionFileBackup);

                        slnContent = slnContent.Replace(strProjectPath.Substring(0,
                            Directory.GetParent(strProjectPath).Parent.FullName.Length + 1), "");

                        var writer = new StreamWriter(SolutionFileBackup);
                        writer.Write(slnContent);
                        writer.Close();
                        writer.Dispose();

                        // Mark this solution file need to be replaced
                        NeedToReplace = true;
                    }
                    #endregion

                    strProjectFolder = Directory.GetParent(strProjectPath).Name;

                    // Read all content of project file. 
                    var reader = new StreamReader(strProjectPath);
                    var projContent = reader.ReadToEnd();

                    #region Add all source code files

                    // For source code files
                    var r = new Regex("<Compile Include=\"(.*?)\"", RegexOptions.Singleline);
                    var ms = r.Matches(projContent);
                    foreach (Match ma in ms)
                        AddItemWithHierarchialStructure(ma.Groups[1].Value, strProjectPath, strProjectFolder, false);

                    #endregion

                    #region Add all resources

                    r = new Regex("<Content Include=\"(.*?)\"", RegexOptions.Singleline);
                    ms = r.Matches(projContent);
                    foreach (Match ma in ms)
                        AddItemWithHierarchialStructure(ma.Groups[1].Value, strProjectPath, strProjectFolder, false);

                    #endregion

                    #region Add *.resx files and all included resources in it

                    r = new Regex("<EmbeddedResource Include=\"(.*?)\"", RegexOptions.Singleline);
                    ms = r.Matches(projContent);
                    foreach (Match ma in ms)
                    {
                        AddItemWithHierarchialStructure(ma.Groups[1].Value, strProjectPath, strProjectFolder, true);

                        // add included content
                        var rd = new StreamReader(ItemList[ItemList.Count-1].Path);
                        var resxContent = rd.ReadToEnd();

                        // We get all resource path
                        r = new Regex(@"<data name="".*?"">\r?\n?[ \t]*<value>..\\(.*?);.*?>\r?\n?[ \t]*</data>");
                        ms = r.Matches(resxContent);

                        foreach (Match match in ms)
                            AddItemWithHierarchialStructure(match.Groups[1].Value, strProjectPath, strProjectFolder, true);
                        
                        rd.Close();
                        rd.Dispose();
                    }
                    #endregion

                    #region Add all references
                    // Change project file to map with new reference
                    // We don't get details info of refs files.
                    if (settings.BackupIncludeRef)
                    {
                        r = new Regex("<HintPath>(.*?)</HintPath>", RegexOptions.Singleline);
                        ms = r.Matches(projContent);

                        if (ms.Count > 0)
                        {
                            var newContent = projContent;

                        foreach (Match ma in ms)
                        {
                                AddItemWithHierarchialStructure(ma.Groups[1].Value, strProjectPath, strProjectFolder, true);
                                ItemList[ItemList.Count - 1].HieraryPath = "References";

                                newContent = newContent.Replace(ma.Groups[1].Value, Path.Combine("References", Path.GetFileName(ma.Groups[1].Value)));

                        }

                            if (!File.Exists(strProjectPath + ".bk"))
                                File.Delete(strProjectPath + ".bk");

                            var writer = new StreamWriter(strProjectPath + ".bk");
                            writer.Write(newContent);
                            writer.Close();
                            writer.Dispose();

                            bIsBackup = true;
                            DeleteList.Add(strProjectPath + ".bk");
                        }

                    }
                    #endregion

                    // Add *.csproj to Item list.
                    AddItemWithHierarchialStructure(strProjectPath, strProjectPath, strProjectFolder, false);
                    ItemList[ItemList.Count - 1].IsBackup = bIsBackup;
                    
                    reader.Close();
                    reader.Dispose();
                }

                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
                return false;
            }
        }

        private bool DoZip()
        {
            try
            {
                applicationObject.StatusBar.Text = "Compressing to backup file...";

                var zip = new ZipFile(Encoding.UTF8) { CompressionLevel = (CompressionLevel)settings.BackupCompresionLvl };
                if (!string.IsNullOrEmpty(settings.BackupPass))
                {
                    zip.Password = settings.BackupPass;
                    zip.Encryption = EncryptionAlgorithm.PkzipWeak;
                }

                foreach (var itemFile in ItemList)
                {
                    // TO: We need to build a hierarchial structure
                    var path = Path.Combine(Path.Combine(SolutionName, itemFile.ProjectName), itemFile.HieraryPath);

                    if (itemFile.IsBackup)
                    {
                        zip.AddFile(itemFile.Path + ".bk", path).FileName = Path.Combine(path, Path.GetFileName(itemFile.Path));
                    }
                    else
                    zip.AddFile(itemFile.Path, path);

                    TotalLine += itemFile.LineCount;
                    TotalChar += itemFile.CharCount;
                    UncompressSize += itemFile.Size;
                }

                if(settings.BackupIncludeUserStt)
                {
                    var suoFile = Path.Combine(SolutionPath, SolutionName + ".suo");
                    if(Directory.Exists(suoFile))
                         zip.AddFile(suoFile, SolutionName); // *.suo file

                    var userFile = Path.Combine(SolutionPath, SolutionName + ".user");
                    if (Directory.Exists(userFile))
                        zip.AddFile(userFile, SolutionName); // *.user file
                }
               
                
                // Replace the solution file to orginal
                if (NeedToReplace)
                    zip.AddFile(SolutionFileBackup, SolutionName).FileName = Path.Combine(SolutionName,SolutionName) + ".sln"; // *.sln file
                else
                    zip.AddFile(SolutionFile, SolutionName); // *.sln file
                
                NumberItem = zip.Count;

                var pathToSave = GetFormatString(settings.BackupPath);
                if (!Directory.Exists(pathToSave))
                    Directory.CreateDirectory(pathToSave);

                var nameToSave = GetFormatString(settings.BackupName);
                BackupFile = Path.Combine(pathToSave, nameToSave);
                
                // TODO: Make progress bar to show percent
                //zip.SaveProgress += ZipSaveProgress;
                zip.Save(BackupFile);
                
                if (NeedToReplace)
                {
                    File.Delete(SolutionFileBackup);
                    NeedToReplace = false;
                }

                foreach (var list in DeleteList)
                    File.Delete(list);

                return true;
            }
            catch (Exception exception)
            {
                // TODO: handle exception here
                MessageBox.Show(exception.ToString());
                return false;
            }
        }

        private bool SendToGmail()
        {
            try
            {
                applicationObject.StatusBar.Text = "Sending backuped files to Gmail...";

                var gUser = settings.GmailUsername.Contains("@gmail.com")
                                ? settings.GmailUsername
                                : settings.GmailUsername + "@gmail.com";

                var toAddress = !settings.GmailToOther ? new MailAddress(settings.GmailUsername) : new MailAddress(settings.Gmail2OtherEmail);
                var fromAddress = new MailAddress(gUser);

                var mailMessage = new MailMessage(fromAddress, toAddress)
                                      {
                                          Subject = GetFormatString(settings.GmailSubject),
                                          IsBodyHtml = true,
                                          BodyEncoding = Encoding.UTF8
                                          
                                      };
                if (settings.GmailToOther)
                    mailMessage.CC.Add(fromAddress);

                var sb = new StringBuilder();

                sb.Append(
                    string.Format(
                            @"<html>
                        <body>
                        <table width=`100%`>
                        <tr><td>
                        <table style=`width: 800px; font-family: Tahoma; font-size: 80%;` align=`left`>							
	                        <tr style=`font-weight: 700;`>
		                        <td colspan=`2` align=`center` style=`font-weight: 700;  font-size: medium`>
                                        <a href='http://www.codeproject.com' target=_blank >GBackupSolution Add-in</a> 
                                </td>
	                        </tr>
							<tr style=`font-weight: 700;`>
								<td><br></td>
							</tr>
	                        <tr style=`font-weight: 700;`>
		                        <td style=`width: 150px`>Backup Solution</td>
		                        <td style=`width: 650px; font-weight: 200`>{0}</td>
	                        </tr>
	                        <tr style=`font-weight: 700;`>
		                        <td style=`width: 150px`>Backup Date/Time</td>
		                        <td style=`width: 650px; font-weight: 200`>{1}</td>
	                        </tr>
	                        <tr style=`font-weight: 700;`>
		                        <td style=`width: 150px`>Files in Backup</td>
		                        <td style=`width: 650px; font-weight: 200`><b>{2}</b> files.</td>
	                        </tr>
							<tr style=`font-weight: 700;`>
		                        <td style=`width: 150px`>Statictis</td>
		                        <td style=`width: 650px; font-weight: 200`><b>{3}</b> lines and <b>{4}</b> characters.</td>
	                        </tr>
							<tr style=`font-weight: 700;`>
		                        <td style=`width: 150px`>Solution Size</td>
		                        <td style=`width: 650px; font-weight: 200`><b>{5}</b> / <b>{6}</b> (compress/uncompress).</td>
	                        </tr>
                        </table>
                      </td>
                    </tr>
                    <tr>
                        <td style=`font-family: Tahoma; font-size: 80%; font-weight: 700;`> Item list details:</td>
                    </tr>
                    <tr>
                        <td>".Replace("`", "\""),
                                     SolutionPath,
                                     DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss"),
                                     NumberItem,
                                     TotalLine,
                                     TotalChar,
                                     ByteFormatter.ToString(new FileInfo(BackupFile).Length),
                                     ByteFormatter.ToString(UncompressSize)
                                     ));

                sb.Append(
                        @"<table style=`width: 800px; font-size: xx-small; font-family: Tahoma; border: 1px solid #663300; background-color: #FFFFCC` align=`left`>
                        <tr style=`font-weight: 700; font-size: 120%; border-style: solid; border-width: 1px; background: #CCCFFF`>
	                        <td style=`width: 150px`>File Name</td>
	                        <td style=`width: 400px`>Folder</td>
	                        <td style=`width: 90px`>Modified Date</td>
	                        <td style=`width: 50px` nowrap>Lines</td>
	                        <td style=`width: 60px` nowrap>Chars</td>
                        </tr>".Replace("`", "\""));

                // TODO : make it better
                foreach (var itemFile in ItemList)
                {
                    sb.Append(
                    string.Format(
                            @"<tr>
		                        <td>{0}</td>
		                        <td>{1}</td>
		                        <td>{2}</td>
		                        <td>{3}</td>
		                        <td>{4}</td>
                        </tr>", Path.GetFileName(itemFile.Path),
                                    Path.GetDirectoryName(itemFile.Path),
                                    itemFile.Time.ToString("yyyy-MM-dd hh:mm:ss"),
                                    itemFile.LineCount,
                                    itemFile.CharCount));
                }

                sb.Append(
                        @"</table></td>
                    </tr>
                    <tr>
                        <td align=`center` stype=`width: 80px; font-size: x-small; font-family: Tahoma;`>                         
                           Copyright &#169; 2010 by <a href='http://www.thekok.net' target=_blank >Tiệp Lê</a>.  Contact to me via email:<a href=`mailto:lktiep@gmail.com`> lktiep@gmail.com</a>   
                         </td>
                    </tr>   
                    </body></html>");

                mailMessage.Body = sb.ToString();

                // TODO: Just for testing
                //using(var writer = new StreamWriter(Path.Combine(SolutionPath, "message.html")))
                //{
                //    writer.Write(sb);
                //}
                //return true;


                var mailAttachment = new Attachment(BackupFile);
                mailMessage.Attachments.Add(mailAttachment);

                // Sending email
                var mailClient = new SmtpClient
                                  {
                                      Port = 587,
                                      EnableSsl = true,
                                      UseDefaultCredentials = false,
                                      Credentials =
                                          new System.Net.NetworkCredential(gUser, settings.GmailPassword),
                                      Host = "smtp.gmail.com",
                                      DeliveryMethod = SmtpDeliveryMethod.Network,
                                      Timeout = int.MaxValue
                                  };

                //NOTE: Who want to use SendAsync then uncomment below lines
                //mailClient.SendCompleted += MClientSendCompleted;
                //mailClient.SendAsync(mailMessage, mailAttachment.Name);
                mailClient.Send(mailMessage);

                applicationObject.StatusBar.Text = "Backup solution successfully to " + BackupFile;
                if (settings.OtherPromptDone)
                    MessageBox.Show("Send backup file to Gmail successfully!", "Successfully!", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return true;
            }
            catch (Exception ex)
            {
                //MessageBox.Show(ex.ToString());
                applicationObject.StatusBar.Text = "Send backup file to Gmail unsuccessfully";
                MessageBox.Show(ex.ToString(), "Unsuccessfully!", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return false;
            }
        }

        void MClientSendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            var subject = e.UserState as string;

            if (e.Cancelled)
            {
                // Never mind it.
                Console.WriteLine("[{0}] Send canceled.", subject);
            }
            if (e.Error != null)
            {
                applicationObject.StatusBar.Text = "Send backup file to Gmail unsuccessfully";
                MessageBox.Show("FAILED to send backup file to Gmail.", "Unsuccessfully!", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            else
            {
                applicationObject.StatusBar.Text = "Backup solution successfully to " + BackupFile;
                if (settings.OtherPromptDone)
                    MessageBox.Show("Send backup file to Gmail successfully!", "Successfully!", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

        private void AddItemWithHierarchialStructure(string itemPath, string projPath, string projName, bool bIsResource)
        {
            var item = File.Exists(itemPath) ? new ItemFile(itemPath) : new ItemFile(Path.Combine(Path.GetDirectoryName(projPath), itemPath));

            if (!File.Exists(item.Path))
               return;

            item.ProjectName = projName;
            item.HieraryPath = item.Path.Substring(Directory.GetParent(projPath).FullName.Length + 1).Replace(Path.GetFileName(itemPath), "");

            if (bIsResource)
                item.LineCount = item.CharCount = 0;

            ItemList.Add(item);
        }

        public string GetFormatString(string strOrignal)
        {
            var now = DateTime.Now;

            return strOrignal.
                Replace("$N", SolutionName).
                Replace("$P", SolutionPath).
                Replace("$Date", now.ToString("yyyyMMdd_HHmm")).
                Replace("$Y", now.Year.ToString()).
                Replace("$M", now.Month.ToString("D2")).
                Replace("$D", now.Day.ToString("D2")).
                Replace("$h", now.Hour.ToString("D2")).
                Replace("$m", now.Minute.ToString("D2")).
                Replace("$s", now.Second.ToString("D2"));
        }

        internal class ItemFile
        {
            public string Name { get; set; }
            public string Path { get; set; }
            public string HieraryPath { get; set; }

            public long Size { get; set; }
            public long LineCount { get; set; }
            public long CharCount { get; set; }
            public DateTime Time { get; set; }

            public string ProjectName { get; set; }
            public bool IsBackup { get; set; }

            public ItemFile(string path)
            {
                Path = path;
                HieraryPath = "";
                Name = System.IO.Path.GetFileNameWithoutExtension(path);

                if (File.Exists(path))
                    GetDetailInfo();
            }

            private void GetDetailInfo()
            {
                // Step1: Count lines & chars
                using(var reader = File.OpenText(Path))
                {
                    LineCount = 0;
                    CharCount = 0;
                    string line = reader.ReadLine();
                    while (line != null)
                    {
                        LineCount++;
                        CharCount += line.Length;
                        line = reader.ReadLine();
                    }
                    reader.Close();
                }
                
                // Step2: Get Size & time modified
                var fileInfo = new FileInfo(Path);
                Size = fileInfo.Length;
                Time = fileInfo.LastWriteTime;
            }
        }

        public static class ByteFormatter
        {
            private const long KB = 1024;
            private const long MB = KB * 1024;
            private const long GB = MB * 1024;

            private const string BFormatPattern = "{0} b";
            private const string KBFormatPattern = "{0:0} KB";
            private const string MBFormatPattern = "{0:0,###} MB";
            private const string GBFormatPattern = "{0:0,###.###} GB";

            public static string ToString(long size)
            {
                if (size < KB)
                {
                    return String.Format(BFormatPattern, size);
                }
                if (size >= KB && size < MB)
                {
                    return String.Format(KBFormatPattern, size / 1024.0f);
                }
                return size >= MB && size < GB
                           ? String.Format(MBFormatPattern, size / 1024.0f)
                           : String.Format(GBFormatPattern, size / 1024.0f);
            }
        }
    }
}

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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer TMA Solutions
Vietnam Vietnam
Impossible = I'm possible!

Comments and Discussions