CvsHistoryParser.cs :  » Build-Systems » CruiseControl.NET » ThoughtWorks » CruiseControl » Core » Sourcecontrol » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » Build Systems » CruiseControl.NET 
CruiseControl.NET » ThoughtWorks » CruiseControl » Core » Sourcecontrol » CvsHistoryParser.cs
using System;
using System.Collections;
using System.Globalization;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using ThoughtWorks.CruiseControl.Core.Util;
using System.Collections.Generic;

namespace ThoughtWorks.CruiseControl.Core.Sourcecontrol{
  public class CvsHistoryParser : IHistoryParser
  {
    /// <summary>
    ///  This line delimits seperate files in the CVS log information.
    ///  </summary>
    private static readonly string CVS_FILE_DELIM =
      "=============================================================================";

    /// <summary>
    /// This line delimits the different revisions of a file in the CVS log information.
    /// </summary>
    private static readonly string CvsModificationDelimiter = "----------------------------";

    /// <summary>
    /// This is the keyword that precedes the name of the RCS filename in the CVS log information.
    /// </summary>
    private static readonly string CVS_RCSFILE_LINE = "RCS file: ";

    /// <summary>
    /// This is the keyword that precedes the timestamp of a file revision in the CVS log information.
    /// </summary>
    private static readonly string CVS_REVISION_DATE = "date:";

    /// <summary>
    /// This is a state keyword which indicates that a revision to a file was not
    /// relevant to the current branch, or the revision consisted of a deletion
    /// of the file (removal from branch..).
    /// </summary>
    private static readonly string CVS_REVISION_DEAD = "dead";

    private string currentLine;

    public Modification[] Parse(TextReader cvsLog, DateTime from, DateTime to)
    {
            var mods = new List<Modification>();

      // Read to the first RCS file name. The first entry in the log
      // information will begin with this line. A CVS_FILE_DELIMITER is NOT
      // present. If no RCS file lines are found then there is nothing to do.      
      while ((currentLine = ReadToNotPast(cvsLog, CVS_RCSFILE_LINE, null)) != null)
      {
        // Parse the single file entry, which may include several modifications.
        var entryList = ParseFileEntry(currentLine, cvsLog);

        //Add all the modifications to the local list.
        mods.AddRange(entryList);
      }
      return mods.ToArray();
    }

        private List<Modification> ParseFileEntry(string rcsFileLine, TextReader cvsLog)
    {
            var mods = new List<Modification>();

      string rcsFile = ParseFileNameAndPath(rcsFileLine);
      string fileName = ParseFileName(rcsFile);
      string folderName = ParseFolderName(rcsFile);

      currentLine = ReadToNotPast(cvsLog, CvsModificationDelimiter, CVS_FILE_DELIM);
      while (currentLine != null && !currentLine.StartsWith(CVS_FILE_DELIM))
      {
        Modification mod = ParseModification(cvsLog, folderName, fileName);
        if (IsFileAddedOnBranch(mod)) continue;
        mods.Add(mod);
      }
      return mods;
    }

    private readonly Regex rcsfileRegex = new Regex(@"^RCS file:\s+(.+),v\s*$");

    private string ParseFileNameAndPath(string rcsFileLine)
    {
      return rcsfileRegex.Match(rcsFileLine).Groups[1].Value;
    }

    private string ReadToNotPast(TextReader reader, string startsWith, string notPast)
    {
      currentLine = reader.ReadLine();
      while (currentLine != null && !currentLine.StartsWith(startsWith))
      {
        if ((notPast != null) && currentLine.StartsWith(notPast))
        {
          return null;
        }
        currentLine = reader.ReadLine();
      }
      return currentLine;
    }

    private Modification ParseModification(TextReader reader, string folderName, string fileName)
    {
      currentLine = reader.ReadLine();
      Modification modification = new Modification();
      if (currentLine.StartsWith("revision"))
      {
        modification.Version = currentLine.Substring("revision".Length).Trim();
        currentLine = reader.ReadLine();
      }
      if (currentLine.StartsWith(CVS_REVISION_DATE))
      {
        ParseDateLine(modification, currentLine);
        modification.FileName = fileName;
        modification.FolderName = folderName;

        currentLine = reader.ReadLine();
        modification.Comment = ParseComment(reader);
      }
      return modification;
    }

    private string ParseComment(TextReader cvsLog)
    {
      // All the text from now to the next revision delimiter or working
      // file delimiter constitutes the comment.
      StringBuilder message = new StringBuilder();
      while (currentLine != null && !currentLine.StartsWith(CVS_FILE_DELIM)
        && !currentLine.StartsWith(CvsModificationDelimiter))
      {
        if (message.Length > 0)
        {
          message.Append(Environment.NewLine);
        }
        message.Append(currentLine);

        //Go to the next line.
        currentLine = cvsLog.ReadLine();
      }
      return message.ToString();
    }

    private string ParseFileName(string rcsFilePath)
    {
      int lastSlashIndex = rcsFilePath.LastIndexOf("/");
      return rcsFilePath.Substring(lastSlashIndex + 1);
    }

    /// <summary>
    /// Strip the filename, Attic folder (if the file has been deleted) and repository folder prefix to get folder name.
    /// </summary>
    private string ParseFolderName(string rcsFilePath)
    {
      return StripAtticFolder(StripFilename(rcsFilePath));
    }

    private static string StripFilename(string rcsFilePath)
    {
      int lastSlashIndex = rcsFilePath.LastIndexOf("/");
      if (lastSlashIndex != -1)
      {
        return rcsFilePath.Substring(0, lastSlashIndex);
      }
      return string.Empty;
    }

    private static string StripAtticFolder(string rcsFilePath)
    {
      if (rcsFilePath.EndsWith("Attic"))
        rcsFilePath = rcsFilePath.Substring(0, rcsFilePath.LastIndexOf("/"));
      return rcsFilePath;
    }

    private readonly Regex dateLineRegex = new Regex(@"date:\s+(?<date>\S+)\s+(?<time>\S+)\s*(?<timezone>\S*);\s+author:\s+(?<author>.*);\s+state:\s+(?<state>\S*);(\s+lines:\s+\+(?<line1>\d+)\s+-(?<line2>\d+))?");

    private void ParseDateLine(Modification modification, string dateLine)
    {
      Match match = dateLineRegex.Match(dateLine);
      try
      {
        modification.ModifiedTime = ParseModifiedTime(match.Groups["date"].Value, match.Groups["time"].Value, match.Groups["timezone"].Value);
        modification.UserName = match.Groups["author"].Value;
        modification.Type = ParseType(match.Groups["state"].Value, match.Groups["line1"].Value);
      }
      catch (Exception ex)
      {
        throw new CruiseControlException("Unable to parse CVS date line: " + dateLine, ex);
      }
    }

    private DateTime ParseModifiedTime(string dateStamp, string timeStamp, string timezone)
    {
            if(String.IsNullOrEmpty(timezone))
                timezone = "+0";
      string dateTimeString = string.Format("{0} {1} {2}", dateStamp, timeStamp, timezone);
      return DateTime.Parse(dateTimeString, DateTimeFormatInfo.GetInstance(CultureInfo.InvariantCulture));
    }

    private string ParseType(string stateKeyword, string line1)
    {
      if (StringUtil.EqualsIgnoreCase(stateKeyword, CVS_REVISION_DEAD))
      {
        return "deleted";
      }
            else if (string.IsNullOrEmpty(line1) || Convert.ToInt32(line1) == 0)
      {
        return "added";
      }
      else
      {
        return "modified";
      }
    }

    private static bool IsFileAddedOnBranch(Modification mod)
    {
      return mod.Type == "deleted" && mod.Version == "1.1";
    }
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.