crashanalysercmd/UI/CrashServer/Engine/Inputs/CACmdLineInputParameters.cs
author Jussi Ryoma <ext-jussi.s.ryoma@nokia.com>
Fri, 27 Aug 2010 12:21:46 +0300
changeset 3 045ade241ef5
parent 2 0c91f0baec58
permissions -rw-r--r--
Version 1.0.13. The most important changes are: -detailed defect hash added -panic descriptions updated -release build is working -simple command line usage added

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: 
*
*/
using System;
using System.Text;
using System.IO;
using System.Reflection;
using System.Collections.Generic;
using SymbianUtils.Tracer;
using CrashItemLib.Engine;
using CrashItemLib.Crash;
using CrashItemLib.Crash.Container;
using CrashItemLib.PluginAPI;
using SymbianUtils.FileSystem.Utilities;
using SymbianXmlInputLib.Parser;
using SymbianXmlInputLib.Parser.Nodes;
using SymbianXmlInputLib.Elements;
using SymbianXmlInputLib.Elements.Types.Category;
using SymbianXmlInputLib.Elements.Types.Extension;
using SymbianXmlInputLib.Elements.Types.FileSystem;
using SymbianXmlInputLib.Elements.Types.Command;
using CrashItemLib.Sink;
using System.Text.RegularExpressions;
using System.Globalization;


namespace CrashAnalyserServerExe.Engine
{
	internal class CACmdLineInputParameters
	{
		#region Constructors
        public CACmdLineInputParameters( ITracer aTracer )
		{
            iTracer = aTracer;

            Assembly myAssembly = System.Reflection.Assembly.GetExecutingAssembly();
            iAppPath = Path.GetDirectoryName( myAssembly.Location );

            // CHECKME:
            // Source files are identified from command line current working directory.
            DirectoryInfo sourceDir = new DirectoryInfo( Environment.CurrentDirectory );
            iSources.AddRange( sourceDir.GetFiles( "*.bin", SearchOption.TopDirectoryOnly ) );

            // CHECKME:
            // Read selge.ini from tool directory or CWD
            FindDebugMetaDataFile( KDebugMetaDataFileSelgeIni );

            // CHECKME:
            // Read selge_event.ini from tool directory or CWD
            FindDebugMetaDataFile( KDebugMetaDataFileSelgeEventIni );

            // Sink parameters are fairly simple
            Version version = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
            string commandLine = System.Environment.CommandLine;
            iSinkParams = new CISinkSerializationParameters( version, commandLine );
            iSinkParams.DetailLevel = CISinkSerializationParameters.TDetailLevel.EFull;
            iSinkParams.FileExtensionFailed = ".corrupt_ci";
            iSinkParams.FileExtensionSuccess = ".ci";

            // CHECKME:
            // The output data is written to the same directory as the input file.
            iSinkParams.OutputDirectory = sourceDir;
        }
        #endregion

        #region Command line parsing
        public bool ParseCommandLine()
        {
            bool retval = true;
            string commandLine = System.Environment.CommandLine;

            string ppattern = @"\s*(-.\s*[^-]*)";
            MatchCollection matches = Regex.Matches(commandLine, ppattern, RegexOptions.None);
            if (matches.Count < 1)
            {
                PrintCommandHelp();
                System.Console.WriteLine("Error: No valid parameters given");                
                throw new CACmdLineException("Error: No valid parameters given", CACmdLineException.KErrCommandLineError);
            }
            foreach (Match parameter in matches)
            {
                Regex pparser = new Regex(@"(?<id>-.)\s*(?<content>.*)");

                Match m = pparser.Match(parameter.ToString());
                if (m.Success)
                {
                    GroupCollection groups = m.Groups;
                    string paramId = m.Result("${id}").Trim();
                    string paramContent = m.Result("${content}").Trim();

                    if (paramId == "-a")
                    {
                        ArchivePath = paramContent;
                    }
                    if (paramId == "-s")
                    {
                        SkippedPath = paramContent;
                        ErrorPath = paramContent + @"\errors";
                    }
                    if (paramId == "-f")
                    {
                        DecodeWithoutSymbols = true;
                    }
                    if (paramId == "-t")
                    {
                        NotMovingFiles = true;
                    }
                    if (paramId == "-x")
                    {
                        UseXmlSink = true;
                    }

                    if (paramId == "-c")
                    {
                        CITargetPath = paramContent;
                        System.Console.WriteLine("CITargetPath -c is " +CITargetPath);
                    }
                    
                    // Plain text output
                    if (paramId == "-p")
                    {
                        UseXmlSink = true; // XML sink is used for plain text output
                        iSinkParams.PlainTextOutput = true;
                    }
                    
                    // Crash files
                    if (paramId == "-b")
                    {
                        CommandLineUsage = true;
                        FileInfo fi = new FileInfo(paramContent);
                        CACmdLineFSEntityList<CACmdLineFileSource> fileList = new CACmdLineFSEntityList<CACmdLineFileSource>();

                        if (fi.Exists)
                        {
                            fileList.Add(fi);
                        }
                        else
                        {
                            System.Console.WriteLine("Error: Crash file " + fi.FullName + " does not exist");
                            retval = false;
                        }
                        iSources = fileList;
                    }
                    
                    // Symbol/map/dictionary files
                    if (paramId == "-m")
                    {
                        string[] symbolFileTable = paramContent.Split(',');
                        CACmdLineFSEntityList<CACmdLineFSEntity> fileList = new CACmdLineFSEntityList<CACmdLineFSEntity>();
                        foreach (string fileName in symbolFileTable)
                        {
                            FileInfo fi = new FileInfo(fileName);
                            if(fi.Exists)
                            {
                                SymbolsGiven = true;
                                fileList.Add(fi);
                            }
                        }
                        
                        iMetaData = fileList;

                        if (fileList.Count == 0)
                        {
                            System.Console.WriteLine("Error: Invalid symbol/map/dictionary files: " + paramContent);
                            retval = false;
                        }
                    }
                    
                }
                else
                {
                    System.Console.WriteLine("Error: No parameters found");
                    retval = false;
                }          

            }

            //Parameter scanning finished - validate content
            if (CommandLineUsage)
            {
                if (iMetaData.Count == 0 && DecodeWithoutSymbols == false)
                {
                    System.Console.WriteLine("Error: No symbol files given. Give symbol files with parameter -m");
                    retval = false;
                }

                if (!UseXmlSink)
                {
                    // Plain text output as default in command line usage.
                    UseXmlSink = true;
                    iSinkParams.PlainTextOutput = true;
                }
                    
                // When used in command line mode set current directory as default archive, 
                // error and skipped path (just some valid dir as it is not really used).
                if (ArchivePath == String.Empty || SkippedPath == String.Empty)
                {
                    if (ArchivePath != String.Empty || SkippedPath != String.Empty)
                    {
                        System.Console.WriteLine("Please give either both the archive path and the skipped path, or neither of them.");
                        System.Console.WriteLine("Not moving any files.");
                    }
                    NotMovingFiles = true;
                    ArchivePath = Directory.GetCurrentDirectory();
                    SkippedPath = ArchivePath;
                    ErrorPath = SkippedPath + @"\errors";
                }
            }            
                
            if (ArchivePath == string.Empty)
            {
                System.Console.WriteLine("Error: No archive path given");
                retval = false;
            }
            else if (!Directory.Exists(ArchivePath))
            {
                System.Console.WriteLine("Error: Archive path " + ArchivePath +" cannot be found");
                retval = false;
          
            }
            if (SkippedPath == string.Empty)
            {
                System.Console.WriteLine("Error: No skipped file path given");
                retval = false;
            }
            else if (!Directory.Exists(SkippedPath))
            {
                System.Console.WriteLine("Error: Skipped path " + SkippedPath + " cannot be found");
                retval = false;
            }
            else //skipped path exists, create error path if not there
            {
                if (!Directory.Exists(ErrorPath) && !NotMovingFiles)
                {
                    Directory.CreateDirectory(ErrorPath);
                }
                
            }

            if (CITargetPath != string.Empty)
            {
                CITargetPath = Path.GetFullPath(CITargetPath);
                System.Console.WriteLine("CITargetPath used! Resulting files will be created to " +CITargetPath);
                
                if (!Directory.Exists(CITargetPath))
                {
                    Directory.CreateDirectory(CITargetPath);
                }
                iSinkParams.OutputDirectory = new DirectoryInfo(CITargetPath);
            }

            //make sure paths are absolute
            iArchivePath = Path.GetFullPath(iArchivePath);
            iSkippedPath = Path.GetFullPath(iSkippedPath);
            iErrorPath = Path.GetFullPath(iErrorPath);

            //add weekly division        
            DateTime today = DateTime.Now;
            CultureInfo culInfo = CultureInfo.CurrentCulture;
            int weekNum = culInfo.Calendar.GetWeekOfYear(today, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday);
            int year = culInfo.Calendar.GetYear(today);

            iArchivePath = iArchivePath + @"\" + year + "_" + weekNum.ToString().PadLeft(2, '0');
            iSkippedPath = iSkippedPath + @"\" + year + "_" + weekNum.ToString().PadLeft(2, '0');
            iErrorPath = iErrorPath + @"\" + year + "_" + weekNum.ToString().PadLeft(2, '0');


            if (NotMovingFiles)
            {
                System.Console.WriteLine("Not moving any files!" );
            }
            else if (retval) //Archive & skipped directories exsits, clean up paths and add week numbers
            {
                
                if (!Directory.Exists(iArchivePath))
                {
                    Directory.CreateDirectory(iArchivePath);
                }
                if (!Directory.Exists(iSkippedPath))
                {
                    Directory.CreateDirectory(iSkippedPath);
                }
                if (!Directory.Exists(iErrorPath))
                {
                    Directory.CreateDirectory(iErrorPath);
                }                    
            }
            else
            {
                PrintCommandHelp();
            }
            
            if (!NotMovingFiles)
            {
                System.Console.WriteLine("Using archive path " + ArchivePath + ", skipped path " + SkippedPath + " and error path " + ErrorPath);
            }

            return retval;
        }

        private void PrintCommandHelp()
        {
            System.Console.WriteLine("Usage example:");
            System.Console.WriteLine("CrashAnalyserServerExe.exe -b crashfile.bin -m mapfiles.zip,rom.symbol");
            System.Console.WriteLine();
            System.Console.WriteLine("Command line parameters:");
            System.Console.WriteLine("-b crashfile.bin            Crash file to be decoded.");
            System.Console.WriteLine("-m crash.symbol,crash.map   Symbol/map/dictionary files.");
            System.Console.WriteLine("-f                          Force decoding even if files are without symbols.");
            System.Console.WriteLine("-x                          Prints output in Xml format");
            System.Console.WriteLine("-p                          Prints output in plain text format (default)");
            System.Console.WriteLine();
            System.Console.WriteLine("For server usage:");
            System.Console.WriteLine("-a C:\\folderarchive\\        Location where to move files to permanent archive.");
            System.Console.WriteLine("-s C:\\folder\\skipped\\       Location where to put skipped");
            System.Console.WriteLine("                            files to wait reprocessing.");
            System.Console.WriteLine("-c C:\\folder\\output\\        Location where to put output files.");
            System.Console.WriteLine("                            Defaults to current working dir.");
            System.Console.WriteLine("-t                          Will not move any files,");
            System.Console.WriteLine("                            ignores -a and -s.");
            System.Console.WriteLine();
        }

        #endregion

        #region API
        #endregion

        #region Properties
        public CISinkSerializationParameters SinkParameters
        {
            get { return iSinkParams; }
        }

        public CACmdLineFSEntityList<CACmdLineFileSource> SourceFiles
        {
            get { return iSources; }
            set { iSources = value; }
        }

        public CACmdLineFSEntityList<CACmdLineFSEntity> MetaDataFiles
        {
            get { return iMetaData; }
        }

        public string ArchivePath
        {
            get { return iArchivePath; }
            set { iArchivePath = value; }
        }
        public string SkippedPath
        {
            get { return iSkippedPath; }
            set { iSkippedPath = value; }
        }
        public string ErrorPath
        {
            get { return iErrorPath; }
            set { iErrorPath = value; }
        }
        public string CITargetPath
        {
            get { return iCITargetPath; }
            set { iCITargetPath = value; }
        }  
        public bool DecodeWithoutSymbols
        {
            get { return iDecodeWithoutSymbols; }
            set { iDecodeWithoutSymbols = value; }
        }
        public bool NotMovingFiles
        {
            get { return iNotMovingFiles; }
            set { iNotMovingFiles = value; }
        }
        public bool SymbolsGiven
        {
            get { return iSymbolsGiven; }
            set { iSymbolsGiven = value; }
        }
        public bool UseXmlSink
        {
            get { return iUseXmlSink; }
            set { iUseXmlSink = value; }
        }
        public bool CommandLineUsage
        {
            get { return iCommandLineUsage; }
            set { iCommandLineUsage = value; }
        }
        #endregion

        #region Internal constants
        private const string KDebugMetaDataFileSelgeIni = "selge.ini";
        private const string KDebugMetaDataFileSelgeEventIni = "selge_event.ini";
        #endregion

        #region Internal methods
        private void FindDebugMetaDataFile( string aFileName )
        {
            // First try current working directory, and if not, then try application path.
            DirectoryInfo sourceDir = new DirectoryInfo( Environment.CurrentDirectory );

            string fileName = Path.Combine( sourceDir.FullName, aFileName );
            FileInfo file = new FileInfo( fileName );
            if ( file.Exists )
            {
                iMetaData.Add( file );
            }
            else
            {
                // Try app path
                fileName = Path.Combine(iAppPath, aFileName);
                file = new FileInfo( fileName );
                if ( file.Exists )
                {
                    iMetaData.Add( file );
                }
                else
                {
                    iTracer.Trace( "WARNING: Could not find debug meta data file: " + aFileName );
                }
            }
        }
        #endregion


        #region Data members
        private readonly ITracer iTracer;
        private readonly string iAppPath;
        private readonly CISinkSerializationParameters iSinkParams;
        private CACmdLineFSEntityList<CACmdLineFSEntity> iMetaData = new CACmdLineFSEntityList<CACmdLineFSEntity>();
        private CACmdLineFSEntityList<CACmdLineFileSource> iSources = new CACmdLineFSEntityList<CACmdLineFileSource>();

        private string iCITargetPath = string.Empty;  
        private string iArchivePath = string.Empty;       
        private string iSkippedPath = string.Empty;      
        private string iErrorPath = string.Empty;    
        private bool iNotMovingFiles = false;
        private bool iSymbolsGiven = false;
        private bool iUseXmlSink = false;
        private bool iDecodeWithoutSymbols = false;
        private bool iCommandLineUsage = false;



  

        #endregion
	}
}