Friday, July 27, 2012

A tool for determining which files have changed

Problem
We integrate with a big product. One of our most complex products is tightly integrated, which means we need to keep track of changes in the software we're integrating with.

The problem is there are hundreds of scripts/forms that integrate with multiple scripts/forms. So checking this by hand would literally take DAYS of work.

Solution
First, i had to go through our source files and map them to the source files that they integrate with. I kept track of this in a table in a Word doc.

Then I made a tool where i could enter the mapping, save it in an XML file, then compare relevant source files in two directories (the previous version, and the new version), then show which files have changed, and which files of ours we need to check for compatibility.

It's rather simple, it checks if the contents of the source file are the exact same. It doesn't do diffing. After this tool is used, I must then load up the changed files in a diffing tool -- such as WinMerge -- and see what changes were made, and then check our files for compatibility. This actual checking for compatibility could be automated, but that would be incredibly complex, and human judgement is needed for this sort of thing i think.

Code


 


using System;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.IO;
using System.Xml;

namespace Development_Utilities.Forms
{
   
    public partial class formOurSoftwareCompatibility : Form
    {
        // Xml tag for node, e.g. 'node' in case of <node></node>
        private const string XmlNodeTag = "node";

        // Xml attributes for node e.g. <node text="Asia" tag=""
        // imageindex="1"></node>
        private const string XmlNodeTextAtt = "text";
        private const string XmlNodeTagAtt = "tag";
        private const string XmlNodeImageIndexAtt = "imageindex";
        Dictionary<string, List<string>> mapping = new Dictionary<string, List<string>>();
        public formOurSoftwareCompatibility()
        {
            InitializeComponent();
        }

        private void button3_Click(object sender, EventArgs e)
        {
            txtOurSoftware.Text = "";
        }

        private void button4_Click(object sender, EventArgs e)
        {
            txtOtherSoftware.Text = "";
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
parseOtherSoftwareString();
        }

        private void button1_Click(object sender, EventArgs e)
        {
           
        }
        public void parseOtherSoftwareString()
        {
            string OtherSoftware = txtOtherSoftware.Text;
            Regex rgx = new Regex(@"\w+", RegexOptions.IgnorePatternWhitespace);
            foreach (Match m in rgx.Matches(OtherSoftware))
            {
                Add(m.Value, txtOurSoftware.Text, tvMapping);
            }
        }
        public void Add(string OtherSoftware, string OurSoftware, TreeView tv)
        {
            if (tv.Nodes.ContainsKey(OtherSoftware))
            {
                if (!tv.Nodes[OtherSoftware].Nodes.ContainsKey(OurSoftware))
                {
                    TreeNode newNode = new TreeNode(OurSoftware);
                    newNode.Name = OurSoftware;
                    tv.Nodes[OtherSoftware].Nodes.Add(newNode);
                }
            }
            else
            {
                TreeNode OtherSoftwareNode = new TreeNode(OtherSoftware);
                OtherSoftwareNode.Name = OtherSoftware;
                TreeNode OurSoftwareNode = new TreeNode(OurSoftware);
                OurSoftwareNode.Name = OurSoftware;
                OtherSoftwareNode.Nodes.Add(OurSoftwareNode);
                tv.Nodes.Add(OtherSoftwareNode);
            }
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            saveFileDialog1.DefaultExt = "xml";
            if (saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                SerializeTreeView(tvMapping, saveFileDialog1.FileName);
            }
        }
        public void DeserializeTreeView(TreeView treeView, string fileName)
        {
            XmlTextReader reader = null;
            try
            {
                // disabling re-drawing of treeview till all nodes are added
                treeView.BeginUpdate();
                reader = new XmlTextReader(fileName);
                TreeNode parentNode = null;
                while (reader.Read())
                {
                    if (reader.NodeType == XmlNodeType.Element)
                    {
                        if (reader.Name == XmlNodeTag)
                        {
                            TreeNode newNode = new TreeNode();
                            bool isEmptyElement = reader.IsEmptyElement;

                            // loading node attributes
                            int attributeCount = reader.AttributeCount;
                            if (attributeCount > 0)
                            {
                                for (int i = 0; i < attributeCount; i++)
                                {
                                    reader.MoveToAttribute(i);
                                    SetAttributeValue(newNode,
                                                 reader.Name, reader.Value);
                                }
                            }
                            // add new node to Parent Node or TreeView
                            if (parentNode != null)
                                parentNode.Nodes.Add(newNode);
                            else
                                treeView.Nodes.Add(newNode);

                            // making current node 'ParentNode' if its not empty
                            if (!isEmptyElement)
                            {
                                parentNode = newNode;
                            }
                        }
                    }
                    // moving up to in TreeView if end tag is encountered
                    else if (reader.NodeType == XmlNodeType.EndElement)
                    {
                        if (reader.Name == XmlNodeTag)
                        {
                            parentNode = parentNode.Parent;
                        }
                    }
                    else if (reader.NodeType == XmlNodeType.XmlDeclaration)
                    {
                        //Ignore Xml Declaration                   
                    }
                    else if (reader.NodeType == XmlNodeType.None)
                    {
                        return;
                    }
                    else if (reader.NodeType == XmlNodeType.Text)
                    {
                        parentNode.Nodes.Add(reader.Value);
                    }

                }
            }
            finally
            {
                // enabling redrawing of treeview after all nodes are added
                treeView.EndUpdate();
                reader.Close();
            }
        }
        /// <summary>
        /// Used by Deserialize method for setting properties of
        /// TreeNode from xml node attributes
        /// </summary>
        private void SetAttributeValue(TreeNode node,
                           string propertyName, string value)
        {
            if (propertyName == XmlNodeTextAtt)
            {
                node.Text = value;
                node.Name = value;
            }
            else if (propertyName == XmlNodeImageIndexAtt)
            {
                node.ImageIndex = int.Parse(value);
            }
            else if (propertyName == XmlNodeTagAtt)
            {
                node.Tag = value;
            }
        }

        public void SerializeTreeView(TreeView treeView, string fileName)
        {
            XmlTextWriter textWriter = new XmlTextWriter(fileName,
                                          System.Text.Encoding.ASCII);
            // writing the xml declaration tag
            textWriter.WriteStartDocument();
            //textWriter.WriteRaw("\r\n");
            // writing the main tag that encloses all node tags
            textWriter.WriteStartElement("TreeView");

            // save the nodes, recursive method
            SaveNodes(treeView.Nodes, textWriter);

            textWriter.WriteEndElement();

            textWriter.Close();
        }
        private void SaveNodes(TreeNodeCollection nodesCollection,
   XmlTextWriter textWriter)
        {
            for (int i = 0; i < nodesCollection.Count; i++)
            {
                TreeNode node = nodesCollection[i];
                textWriter.WriteStartElement(XmlNodeTag);
                textWriter.WriteAttributeString(XmlNodeTextAtt,
                                                           node.Text);
                textWriter.WriteAttributeString(
                    XmlNodeImageIndexAtt, node.ImageIndex.ToString());
                if (node.Tag != null)
                    textWriter.WriteAttributeString(XmlNodeTagAtt,
                                                node.Tag.ToString());
                // add other node properties to serialize here 
                if (node.Nodes.Count > 0)
                {
                    SaveNodes(node.Nodes, textWriter);
                }
                textWriter.WriteEndElement();
            }
        }

        private void btnOpen_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                tvMapping.Nodes.Clear();
                DeserializeTreeView(tvMapping, openFileDialog1.FileName);
            }
          
        }

        private void btnOtherSoftwareOld_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtOtherSoftwareOld.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private void btnOtherSoftwareNew_Click(object sender, EventArgs e)
        {
            if (folderBrowserDialog2.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                txtOtherSoftwareNew.Text = folderBrowserDialog2.SelectedPath;
            }
        }

        private void btnProcess_Click(object sender, EventArgs e)
        {
            tvChanges.Nodes.Clear();
            if (txtOtherSoftwareNew.Text != "" && txtOtherSoftwareOld.Text != "")
            {
                DirectoryInfo OtherSoftwareOld = new DirectoryInfo(txtOtherSoftwareOld.Text);
                DirectoryInfo OtherSoftwareNew = new DirectoryInfo(txtOtherSoftwareNew.Text);

                foreach (FileInfo fileOld in OtherSoftwareOld.GetFiles())
                {
                    string fileName = Path.GetFileNameWithoutExtension(fileOld.FullName);
                    if (tvMapping.Nodes.ContainsKey(fileName))
                    {
                        foreach (FileInfo fileNew in
                            OtherSoftwareNew.GetFiles(fileOld.Name, SearchOption.TopDirectoryOnly))
                        {
                            if (fileNew.Name != fileOld.Name)
                                continue;
                            else
                            {
                                string OtherSoftwareOldTxt = File.ReadAllText(fileOld.FullName);
                                string OtherSoftwareNewTxt = File.ReadAllText(fileNew.FullName);
                                if (OtherSoftwareOldTxt != OtherSoftwareNewTxt)
                                {
                                    TreeNode tn = (TreeNode)tvMapping.Nodes[fileName].Clone();
                                    tvChanges.Nodes.Add(tn);
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
Note
I got the TreeView serialization / deserialization code from here: http://www.codeproject.com/Articles/13099/Loading-and-Saving-a-TreeView-control-to-an-XML-fi  The only thing i changed was I made it set the Node.Name to the same thing as the Node.Text. This was because loading the XML file into the TreeView, and then adding more nodes, Nodes.ContainsKey was not picking up the existing nodes.

Also note: I chose to do TreeView serialization because there was existing open source out there for it. I could have just as easily done it myself, but why reinvent the wheel?

No comments:

Post a Comment

There was an error in this gadget