A options class for the Command-Line parser library.
        private static int ExecuteMain(string[] arguments)
        {
            if (arguments.Length == 0)
            {
                throw new ArgumentException(Resources.Program_Main_you_must_provide_a_solution_file);
            }
            var solutionFileName = arguments[0];
            var opts = new string[arguments.Length - 1];
            Array.Copy(arguments, 1, opts, 0, arguments.Length - 1);
            var options = new Options();
            Parser.Default.ParseArguments(opts, options);

            return
                TemplateProcessor.ProcessSolution(solutionFileName, options) ? 0 : 1;
        }
        /// <summary>
        /// /
        /// </summary>
        /// <param name="solutionFileName"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static bool ProcessSolution(string solutionFileName, Options options)
        {
            if (string.IsNullOrEmpty(solutionFileName) || !File.Exists(solutionFileName))
            {
                throw new ArgumentException(
                    string.Format(CultureInfo.CurrentUICulture,
                        Resources.Program_Main_the_file_path___0___is_either_invalid_or_doesn_t_exist_, solutionFileName));
            }

            solutionFileName = Path.GetFullPath(solutionFileName);
            Source.TraceEvent(TraceEventType.Information, 0, Resources.Program_Main_Creating_VS_instance___);
            using (new MessageFilter())
            {
                var result = DteHelper.CreateDteInstance();
                var dte = result.Item2;
                var processId = result.Item1;
                try
                {
                    Source.TraceEvent(TraceEventType.Information, 0, Resources.Program_Main_Opening__0_, solutionFileName);
                    dte.Solution.Open(solutionFileName);

                    Source.TraceEvent(TraceEventType.Verbose, 0, Resources.Program_Main_Finding_and_processing___tt_templates___);
                    var firstError =
                        FindTemplates(Path.GetDirectoryName(solutionFileName))
                            .Select(t => Tuple.Create(t, ProcessTemplate(dte, t, options)))
                            .FirstOrDefault(tuple => tuple.Item2.Count > 0);

                    if (firstError != null)
                    {
                        Source.TraceEvent(TraceEventType.Warning, 0, Resources.Program_Main_FAILED_to_process___0__,
                            firstError.Item1);
                        foreach (var error in firstError.Item2)
                        {
                            Source.TraceEvent(TraceEventType.Error, 0, Resources.Program_Main_, error);
                        }
                        return false;
                    }

                    Source.TraceEvent(TraceEventType.Information, 0, Resources.Program_Main_Everything_worked_);
                    return true;
                }
                finally
                {
                    Process process = null;
                    if (processId > 0)
                    {
                        process = Process.GetProcessById(processId);
                    }
                    dte.Quit();

                    // Makes no sense to wait when the process already exited, or when we have no processId to kill.
                    int i = 0;
                    while (i < 10 && process != null && !process.HasExited)
                    {
                        Thread.Sleep(1000);
                        i++;
                    }
                    if (process != null && !process.HasExited)
                    {
                        process.Kill();
                    }
                }
            }
        }
        /// <summary>
        /// /
        /// </summary>
        /// <param name="dte"></param>
        /// <param name="templateFileName"></param>
        /// <param name="options"></param>
        /// <returns></returns>
        public static CompilerErrorCollection ProcessTemplate(DTE2 dte, string templateFileName, Options options)
        {
            if (dte == null)
            {
                throw new ArgumentNullException("dte");
            }
            if (templateFileName == null)
            {
                throw new ArgumentNullException("templateFileName");
            }
            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            var templateDir = Path.GetDirectoryName(templateFileName);
            Debug.Assert(templateDir != null, "templateDir != null, don't expected templateFileName to be a root directory!");
            var defaultResolver = DefaultVariableResolver.CreateFromDte(dte, templateFileName);
            IVariableResolver resolver = defaultResolver;
            Source.TraceEvent(TraceEventType.Information, 1, "Default TargetDir {0} will be used", defaultResolver.TargetDir);
            Source.TraceEvent(TraceEventType.Information, 1, "Default SolutionDir {0} will be used", defaultResolver.SolutionDir);
            Source.TraceEvent(TraceEventType.Information, 1, "Default ProjectDir {0} will be used", defaultResolver.ProjectDir);

            if (!string.IsNullOrEmpty(options.TargetDir))
            {
                if (Directory.Exists(options.TargetDir))
                {
                    Source.TraceEvent(TraceEventType.Information, 1, "TargetDir {0} will be added ", options.TargetDir);
                    resolver = new CombiningVariableResolver(new DefaultVariableResolver(null, null, options.TargetDir), resolver);
                }
                else
                {
                    Source.TraceEvent(TraceEventType.Warning, 1, "TargetDir {0} doesn't exist and will be ignored!", options.TargetDir);
                }
            }

            var result = ProcessTemplateInMemory(dte, templateFileName, resolver);
            var host = result.Item2;
            var output = result.Item1;

            var outFileName = Path.GetFileNameWithoutExtension(templateFileName);
            var outFilePath = Path.Combine(templateDir, outFileName + host.FileExtension);
            // Because with TFS the files could be read-only!
            if (File.Exists(outFilePath))
            {
                var attr = File.GetAttributes(outFilePath);
                File.SetAttributes(outFilePath, attr & ~FileAttributes.ReadOnly);
                File.Delete(outFilePath);
            }
            File.WriteAllText(outFilePath, output, host.FileEncoding);
            return host.Errors;
        }