/// <summary>
        ///     Process a T4 template using Visual Studio's text templating service, given a path that could contain macros (i.e. "$(DevEnvDir)\...").
        ///     NOTE: Template paths that are not files or are UNC paths are not allowed
        /// </summary>
        /// <param name="templatePath">Template's file path which may contain project-based macros</param>
        /// <returns>The output of processing the template.</returns>
        protected string ProcessTemplate(string templatePath)
        {
            // Attempt to resolve the full template path if it contains any macros, using
            // the edmx path to get the project and using the project's defined macros.
            Project project = null;

            if (!String.IsNullOrEmpty(_edmxPath))
            {
                project = VSHelpers.GetProjectForDocument(_edmxPath);
            }

            // Resolve and validate the template file path
            var errorMessages = new DatabaseGenerationEngine.PathValidationErrorMessages
            {
                NullFile = String.Format(
                    CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNotSet, DisplayName),
                NonValid = String.Format(
                    CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNotValid, DisplayName),
                ParseError = String.Format(
                    CultureInfo.CurrentCulture, Resources.DatabaseCreation_ExceptionParsingTemplateFilePath, DisplayName),
                NonFile = String.Format(
                    CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNonFile, DisplayName),
                NotInProject = String.Format(
                    CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplateFileNotInProject, DisplayName),
                NonExistant = String.Format(
                    CultureInfo.CurrentCulture, Resources.DatabaseCreation_TemplateFileNotExists, DisplayName)
            };

            var templateFileInfo = DatabaseGenerationEngine.ResolveAndValidatePath(
                project,
                templatePath,
                errorMessages);

            var resolvedTemplatePath = templateFileInfo.FullName;

            // The workflow will catch any IO exceptions and wrap them in a friendly message
            var templateContents = File.ReadAllText(resolvedTemplatePath);

            // Since we are leveraging the VS T4 Host, we will have to ask the environment how to resolve any other assemblies.
            // The VS T4 Host only resolves: (a) rooted paths (b) GAC'd dlls and (c) Referenced dlls in the project, if a hierarchy is provided
            // This is a little risky here, but we will use a strict regular expression to replace the assembly references with resolved paths
            templateContents = Regex.Replace(
                templateContents, _assemblyDirectiveRegex.ToString(), match =>
            {
                Debug.Assert(
                    match.Groups.Count == 2,
                    "If we have a match, we should only ever have two groups, the last of which is the assembly path");
                if (match.Groups.Count == 2)
                {
                    var resolvedAssemblyPath = match.Groups[1].Value;

                    // project can be null if we are running via tests. In this case, the custom macros will
                    // be used
                    resolvedAssemblyPath = VsUtils.ResolvePathWithMacro(
                        project, resolvedAssemblyPath,
                        new Dictionary <string, string>
                    {
                        { VsUtils.DevEnvDirMacroName, VsUtils.GetVisualStudioInstallDir() },
                        { ExtensibleFileManager.EFTOOLS_USER_MACRONAME, ExtensibleFileManager.UserEFToolsDir.FullName },
                        { ExtensibleFileManager.EFTOOLS_VS_MACRONAME, ExtensibleFileManager.VSEFToolsDir.FullName }
                    });
                    return(String.Format(CultureInfo.InvariantCulture, AssemblyDirectiveFormat, resolvedAssemblyPath));
                }
                return(match.Value);
            });

            var textTemplatingService = Package.GetGlobalService(typeof(STextTemplating)) as ITextTemplating;

            Debug.Assert(textTemplatingService != null, "ITextTemplating could not be found from the IServiceProvider");
            if (textTemplatingService == null)
            {
                throw new InvalidOperationException(
                          String.Format(
                              CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTextTemplatingServiceNotFound, resolvedTemplatePath));
            }
            // Process the template, keeping track of errors
            var templateCallback = new TemplateCallback();
            var templateOutput   = String.Empty;

            textTemplatingService.BeginErrorSession();
            templateOutput = textTemplatingService.ProcessTemplate(resolvedTemplatePath, templateContents, templateCallback, null);
            if (textTemplatingService.EndErrorSession())
            {
                throw new InvalidOperationException(
                          String.Format(
                              CultureInfo.CurrentCulture, Resources.TemplateErrorsEncountered, resolvedTemplatePath,
                              templateCallback.ErrorStringBuilder));
            }
            return(templateOutput);
        }
        /// <summary>
        ///     Process a T4 template using Visual Studio's text templating service, given a path that could contain macros (i.e. "$(DevEnvDir)\...").
        ///     NOTE: Template paths that are not files or are UNC paths are not allowed
        /// </summary>
        /// <param name="templatePath">Template's file path which may contain project-based macros</param>
        /// <returns>The output of processing the template.</returns>
        protected string ProcessTemplate(string templatePath)
        {
            // Attempt to resolve the full template path if it contains any macros, using
            // the edmx path to get the project and using the project's defined macros.
            Project project = null;
            if (!String.IsNullOrEmpty(_edmxPath))
            {
                project = VSHelpers.GetProjectForDocument(_edmxPath);
            }

            // Resolve and validate the template file path
            var errorMessages = new DatabaseGenerationEngine.PathValidationErrorMessages
                {
                    NullFile = String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNotSet, DisplayName),
                    NonValid = String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNotValid, DisplayName),
                    ParseError = String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_ExceptionParsingTemplateFilePath, DisplayName),
                    NonFile = String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplatePathNonFile, DisplayName),
                    NotInProject = String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTemplateFileNotInProject, DisplayName),
                    NonExistant = String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_TemplateFileNotExists, DisplayName)
                };

            var templateFileInfo = DatabaseGenerationEngine.ResolveAndValidatePath(
                project,
                templatePath,
                errorMessages);

            var resolvedTemplatePath = templateFileInfo.FullName;

            // The workflow will catch any IO exceptions and wrap them in a friendly message
            var templateContents = File.ReadAllText(resolvedTemplatePath);

            // Since we are leveraging the VS T4 Host, we will have to ask the environment how to resolve any other assemblies.
            // The VS T4 Host only resolves: (a) rooted paths (b) GAC'd dlls and (c) Referenced dlls in the project, if a hierarchy is provided
            // This is a little risky here, but we will use a strict regular expression to replace the assembly references with resolved paths
            templateContents = Regex.Replace(
                templateContents, _assemblyDirectiveRegex.ToString(), match =>
                    {
                        Debug.Assert(
                            match.Groups.Count == 2,
                            "If we have a match, we should only ever have two groups, the last of which is the assembly path");
                        if (match.Groups.Count == 2)
                        {
                            var resolvedAssemblyPath = match.Groups[1].Value;

                            // project can be null if we are running via tests. In this case, the custom macros will
                            // be used
                            resolvedAssemblyPath = VsUtils.ResolvePathWithMacro(
                                project, resolvedAssemblyPath,
                                new Dictionary<string, string>
                                    {
                                        { VsUtils.DevEnvDirMacroName, VsUtils.GetVisualStudioInstallDir() },
                                        { ExtensibleFileManager.EFTOOLS_USER_MACRONAME, ExtensibleFileManager.UserEFToolsDir.FullName },
                                        { ExtensibleFileManager.EFTOOLS_VS_MACRONAME, ExtensibleFileManager.VSEFToolsDir.FullName }
                                    });
                            return String.Format(CultureInfo.InvariantCulture, AssemblyDirectiveFormat, resolvedAssemblyPath);
                        }
                        return match.Value;
                    });

            var textTemplatingService = Package.GetGlobalService(typeof(STextTemplating)) as ITextTemplating;
            Debug.Assert(textTemplatingService != null, "ITextTemplating could not be found from the IServiceProvider");
            if (textTemplatingService == null)
            {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentCulture, Resources.DatabaseCreation_ErrorTextTemplatingServiceNotFound, resolvedTemplatePath));
            }
            // Process the template, keeping track of errors
            var templateCallback = new TemplateCallback();
            var templateOutput = String.Empty;

            textTemplatingService.BeginErrorSession();
            templateOutput = textTemplatingService.ProcessTemplate(resolvedTemplatePath, templateContents, templateCallback, null);
            if (textTemplatingService.EndErrorSession())
            {
                throw new InvalidOperationException(
                    String.Format(
                        CultureInfo.CurrentCulture, Resources.TemplateErrorsEncountered, resolvedTemplatePath,
                        templateCallback.ErrorStringBuilder));
            }
            return templateOutput;
        }