Ejemplo n.º 1
0
        public static async Task <WorkspaceFormatResult> FormatWorkspaceAsync(
            FormatOptions formatOptions,
            ILogger logger,
            CancellationToken cancellationToken,
            bool createBinaryLog = false)
        {
            var logWorkspaceWarnings = formatOptions.LogLevel == LogLevel.Trace;

            logger.LogInformation(string.Format(Resources.Formatting_code_files_in_workspace_0, formatOptions.WorkspaceFilePath));

            logger.LogTrace(Resources.Loading_workspace);

            var workspaceStopwatch = Stopwatch.StartNew();

            using var workspace = formatOptions.WorkspaceType == WorkspaceType.Folder
                ? OpenFolderWorkspace(formatOptions.WorkspaceFilePath, formatOptions.FileMatcher)
                : await OpenMSBuildWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.WorkspaceType, createBinaryLog, logWorkspaceWarnings, logger, cancellationToken).ConfigureAwait(false);

            if (workspace is null)
            {
                return(new WorkspaceFormatResult(filesFormatted: 0, fileCount: 0, exitCode: 1));
            }

            var loadWorkspaceMS = workspaceStopwatch.ElapsedMilliseconds;

            logger.LogTrace(Resources.Complete_in_0_ms, loadWorkspaceMS);

            var projectPath = formatOptions.WorkspaceType == WorkspaceType.Project ? formatOptions.WorkspaceFilePath : string.Empty;
            var solution    = workspace.CurrentSolution;

            logger.LogTrace(Resources.Determining_formattable_files);

            var(fileCount, formatableFiles) = await DetermineFormattableFilesAsync(
                solution, projectPath, formatOptions, logger, cancellationToken).ConfigureAwait(false);

            var determineFilesMS = workspaceStopwatch.ElapsedMilliseconds - loadWorkspaceMS;

            logger.LogTrace(Resources.Complete_in_0_ms, determineFilesMS);

            logger.LogTrace(Resources.Running_formatters);

            var formattedFiles    = new List <FormattedFile>(fileCount);
            var formattedSolution = await RunCodeFormattersAsync(
                solution, formatableFiles, formatOptions, logger, formattedFiles, cancellationToken).ConfigureAwait(false);

            var formatterRanMS = workspaceStopwatch.ElapsedMilliseconds - loadWorkspaceMS - determineFilesMS;

            logger.LogTrace(Resources.Complete_in_0_ms, formatterRanMS);

            var documentIdsWithErrors = formattedFiles.Select(file => file.DocumentId).Distinct().ToImmutableArray();

            foreach (var documentId in documentIdsWithErrors)
            {
                var documentWithError = solution.GetDocument(documentId);

                logger.LogInformation(Resources.Formatted_code_file_0, documentWithError !.FilePath);
            }

            var exitCode = 0;

            if (formatOptions.SaveFormattedFiles && !workspace.TryApplyChanges(formattedSolution))
            {
                logger.LogError(Resources.Failed_to_save_formatting_changes);
                exitCode = 1;
            }

            if (exitCode == 0 && !string.IsNullOrWhiteSpace(formatOptions.ReportPath))
            {
                ReportWriter.Write(formatOptions.ReportPath !, formattedFiles, logger);
            }

            logger.LogDebug(Resources.Formatted_0_of_1_files, documentIdsWithErrors.Length, fileCount);

            logger.LogInformation(Resources.Format_complete_in_0_ms, workspaceStopwatch.ElapsedMilliseconds);

            return(new WorkspaceFormatResult(documentIdsWithErrors.Length, fileCount, exitCode));
        }
Ejemplo n.º 2
0
        internal static async Task <(int, ImmutableArray <DocumentId>)> DetermineFormattableFilesAsync(
            Solution solution,
            string projectPath,
            FormatOptions formatOptions,
            ILogger logger,
            CancellationToken cancellationToken)
        {
            var totalFileCount   = solution.Projects.Sum(project => project.DocumentIds.Count);
            var projectFileCount = 0;

            var documentsCoveredByEditorConfig    = ImmutableArray.CreateBuilder <DocumentId>(totalFileCount);
            var documentsNotCoveredByEditorConfig = ImmutableArray.CreateBuilder <DocumentId>(totalFileCount);

            var addedFilePaths = new HashSet <string>(totalFileCount);

            foreach (var project in solution.Projects)
            {
                if (project?.FilePath is null)
                {
                    continue;
                }

                // If a project is used as a workspace, then ignore other referenced projects.
                if (!string.IsNullOrEmpty(projectPath) && !project.FilePath.Equals(projectPath, StringComparison.OrdinalIgnoreCase))
                {
                    logger.LogDebug(Resources.Skipping_referenced_project_0, project.Name);
                    continue;
                }

                // Ignore unsupported project types.
                if (project.Language != LanguageNames.CSharp && project.Language != LanguageNames.VisualBasic)
                {
                    logger.LogWarning(Resources.Could_not_format_0_Format_currently_supports_only_CSharp_and_Visual_Basic_projects, project.FilePath);
                    continue;
                }

                projectFileCount += project.DocumentIds.Count;

                foreach (var document in project.Documents)
                {
                    // If we've already added this document, either via a link or multi-targeted framework, then ignore.
                    if (document?.FilePath is null ||
                        addedFilePaths.Contains(document.FilePath))
                    {
                        continue;
                    }

                    addedFilePaths.Add(document.FilePath);

                    var isFileIncluded = formatOptions.WorkspaceType == WorkspaceType.Folder ||
                                         (formatOptions.FileMatcher.HasMatches(document.FilePath) && File.Exists(document.FilePath));
                    if (!isFileIncluded || !document.SupportsSyntaxTree)
                    {
                        continue;
                    }

                    var syntaxTree = await document.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false);

                    if (syntaxTree is null)
                    {
                        throw new Exception($"Unable to get a syntax tree for '{document.Name}'");
                    }

                    if (!formatOptions.IncludeGeneratedFiles &&
                        await GeneratedCodeUtilities.IsGeneratedCodeAsync(syntaxTree, cancellationToken).ConfigureAwait(false))
                    {
                        continue;
                    }

                    // Track files covered by an editorconfig separately from those not covered.
                    var analyzerConfigOptions = document.Project.AnalyzerOptions.AnalyzerConfigOptionsProvider.GetOptions(syntaxTree);
                    if (analyzerConfigOptions != null)
                    {
                        if (formatOptions.IncludeGeneratedFiles ||
                            GeneratedCodeUtilities.GetIsGeneratedCodeFromOptions(analyzerConfigOptions) != true)
                        {
                            documentsCoveredByEditorConfig.Add(document.Id);
                        }
                    }
                    else
                    {
                        documentsNotCoveredByEditorConfig.Add(document.Id);
                    }
                }
            }

            // Initially we would format all documents in a workspace, even if some files weren't covered by an
            // .editorconfig and would have defaults applied. This behavior was an early requested change since
            // users were surprised to have files not specified by the .editorconfig modified. The assumption is
            // that users without an .editorconfig still wanted formatting (they did run a formatter after all),
            // so we run on all files with defaults.

            // If no files are covered by an editorconfig, then return them all. Otherwise only return
            // files that are covered by an editorconfig.
            return(documentsCoveredByEditorConfig.Count == 0
                ? (projectFileCount, documentsNotCoveredByEditorConfig.ToImmutable())
                : (projectFileCount, documentsCoveredByEditorConfig.ToImmutable()));
        }
Ejemplo n.º 3
0
        public static async Task <WorkspaceFormatResult> FormatWorkspaceAsync(
            FormatOptions formatOptions,
            ILogger logger,
            CancellationToken cancellationToken,
            bool createBinaryLog = false)
        {
            var logWorkspaceWarnings = formatOptions.LogLevel == LogLevel.Trace;

            logger.LogInformation(string.Format(Resources.Formatting_code_files_in_workspace_0, formatOptions.WorkspaceFilePath));

            logger.LogTrace(Resources.Loading_workspace);

            var workspaceStopwatch = Stopwatch.StartNew();

            using var workspace = formatOptions.WorkspaceType == WorkspaceType.Folder
                ? await OpenFolderWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.FileMatcher, cancellationToken).ConfigureAwait(false)
                : await OpenMSBuildWorkspaceAsync(formatOptions.WorkspaceFilePath, formatOptions.WorkspaceType, createBinaryLog, logWorkspaceWarnings, logger, cancellationToken).ConfigureAwait(false);

            if (workspace is null)
            {
                return(new WorkspaceFormatResult(filesFormatted: 0, fileCount: 0, exitCode: 1));
            }

            var loadWorkspaceMS = workspaceStopwatch.ElapsedMilliseconds;

            logger.LogTrace(Resources.Complete_in_0_ms, workspaceStopwatch.ElapsedMilliseconds);

            var projectPath = formatOptions.WorkspaceType == WorkspaceType.Project ? formatOptions.WorkspaceFilePath : string.Empty;
            var solution    = workspace.CurrentSolution;

            logger.LogTrace(Resources.Determining_formattable_files);

            var(fileCount, formatableFiles) = await DetermineFormattableFilesAsync(
                solution, projectPath, formatOptions.FileMatcher, formatOptions.IncludeGeneratedFiles, logger, cancellationToken).ConfigureAwait(false);

            var determineFilesMS = workspaceStopwatch.ElapsedMilliseconds - loadWorkspaceMS;

            logger.LogTrace(Resources.Complete_in_0_ms, determineFilesMS);

            logger.LogTrace(Resources.Running_formatters);

            var formattedFiles    = new List <FormattedFile>();
            var formattedSolution = await RunCodeFormattersAsync(
                solution, formatableFiles, formatOptions, logger, formattedFiles, cancellationToken).ConfigureAwait(false);

            var formatterRanMS = workspaceStopwatch.ElapsedMilliseconds - loadWorkspaceMS - determineFilesMS;

            logger.LogTrace(Resources.Complete_in_0_ms, formatterRanMS);

            var solutionChanges = formattedSolution.GetChanges(solution);

            var filesFormatted = 0;

            foreach (var projectChanges in solutionChanges.GetProjectChanges())
            {
                foreach (var changedDocumentId in projectChanges.GetChangedDocuments())
                {
                    var changedDocument = solution.GetDocument(changedDocumentId);
                    if (changedDocument?.FilePath is null)
                    {
                        continue;
                    }

                    logger.LogInformation(Resources.Formatted_code_file_0, changedDocument.FilePath);
                    filesFormatted++;
                }
            }

            var exitCode = 0;

            if (formatOptions.SaveFormattedFiles && !workspace.TryApplyChanges(formattedSolution))
            {
                logger.LogError(Resources.Failed_to_save_formatting_changes);
                exitCode = 1;
            }

            if (exitCode == 0 && !string.IsNullOrWhiteSpace(formatOptions.ReportPath))
            {
                var reportFilePath   = GetReportFilePath(formatOptions.ReportPath !); // IsNullOrEmpty is not annotated on .NET Core 2.1
                var reportFolderPath = Path.GetDirectoryName(reportFilePath);

                if (!Directory.Exists(reportFolderPath))
                {
                    Directory.CreateDirectory(reportFolderPath);
                }

                logger.LogInformation(Resources.Writing_formatting_report_to_0, reportFilePath);
                var seralizerOptions = new JsonSerializerOptions
                {
                    WriteIndented = true
                };
                var formattedFilesJson = JsonSerializer.Serialize(formattedFiles, seralizerOptions);

                File.WriteAllText(reportFilePath, formattedFilesJson);
            }

            logger.LogDebug(Resources.Formatted_0_of_1_files, filesFormatted, fileCount);

            logger.LogInformation(Resources.Format_complete_in_0_ms, workspaceStopwatch.ElapsedMilliseconds);

            return(new WorkspaceFormatResult(filesFormatted, fileCount, exitCode));
        }
Ejemplo n.º 4
0
        public static async Task <int> Run(string folder, string workspace, string verbosity, bool dryRun, bool check, string files, string report, IConsole console = null)
        {
            // Setup logging.
            var serviceCollection = new ServiceCollection();
            var logLevel          = GetLogLevel(verbosity);

            ConfigureServices(serviceCollection, console, logLevel);

            var serviceProvider = serviceCollection.BuildServiceProvider();
            var logger          = serviceProvider.GetService <ILogger <Program> >();

            // Hook so we can cancel and exit when ctrl+c is pressed.
            var cancellationTokenSource = new CancellationTokenSource();

            Console.CancelKeyPress += (sender, e) =>
            {
                e.Cancel = true;
                cancellationTokenSource.Cancel();
            };

            var currentDirectory = string.Empty;

            try
            {
                currentDirectory = Environment.CurrentDirectory;

                string        workspaceDirectory;
                string        workspacePath;
                WorkspaceType workspaceType;

                if (!string.IsNullOrEmpty(folder) && !string.IsNullOrEmpty(workspace))
                {
                    logger.LogWarning(Resources.Cannot_specify_both_folder_and_workspace_options);
                    return(1);
                }

                if (!string.IsNullOrEmpty(folder))
                {
                    folder             = Path.GetFullPath(folder, Environment.CurrentDirectory);
                    workspacePath      = folder;
                    workspaceDirectory = workspacePath;
                    workspaceType      = WorkspaceType.Folder;
                }
                else
                {
                    var(isSolution, workspaceFilePath) = MSBuildWorkspaceFinder.FindWorkspace(currentDirectory, workspace);

                    workspacePath = workspaceFilePath;
                    workspaceType = isSolution
                        ? WorkspaceType.Solution
                        : WorkspaceType.Project;

                    // To ensure we get the version of MSBuild packaged with the dotnet SDK used by the
                    // workspace, use its directory as our working directory which will take into account
                    // a global.json if present.
                    workspaceDirectory = Path.GetDirectoryName(workspacePath);
                }

                Environment.CurrentDirectory = workspaceDirectory;

                var filesToFormat = GetFilesToFormat(files, folder);

                // Since we are running as a dotnet tool we should be able to find an instance of
                // MSBuild in a .NET Core SDK.
                var msBuildInstance = Build.Locator.MSBuildLocator.QueryVisualStudioInstances().First();

                // Since we do not inherit msbuild.deps.json when referencing the SDK copy
                // of MSBuild and because the SDK no longer ships with version matched assemblies, we
                // register an assembly loader that will load assemblies from the msbuild path with
                // equal or higher version numbers than requested.
                LooseVersionAssemblyLoader.Register(msBuildInstance.MSBuildPath);

                Build.Locator.MSBuildLocator.RegisterInstance(msBuildInstance);

                var formatOptions = new FormatOptions(
                    workspacePath,
                    workspaceType,
                    logLevel,
                    saveFormattedFiles: !dryRun,
                    changesAreErrors: check,
                    filesToFormat,
                    reportPath: report);

                var formatResult = await CodeFormatter.FormatWorkspaceAsync(
                    formatOptions,
                    logger,
                    cancellationTokenSource.Token).ConfigureAwait(false);

                return(GetExitCode(formatResult, check));
            }
            catch (FileNotFoundException fex)
            {
                logger.LogError(fex.Message);
                return(1);
            }
            catch (OperationCanceledException)
            {
                return(1);
            }
            finally
            {
                if (!string.IsNullOrEmpty(currentDirectory))
                {
                    Environment.CurrentDirectory = currentDirectory;
                }
            }
        }
Ejemplo n.º 5
0
        public static async Task <int> Run(
            string?workspace,
            bool folder,
            bool fixWhitespace,
            string?fixStyle,
            string?fixAnalyzers,
            string?verbosity,
            bool check,
            string[] include,
            string[] exclude,
            string?report,
            bool includeGenerated,
            IConsole console = null !)
        {
            if (s_parseResult == null)
            {
                return(1);
            }

            // Setup logging.
            var logLevel = GetLogLevel(verbosity);
            var logger   = SetupLogging(console, logLevel);

            // Hook so we can cancel and exit when ctrl+c is pressed.
            var cancellationTokenSource = new CancellationTokenSource();

            Console.CancelKeyPress += (sender, e) =>
            {
                e.Cancel = true;
                cancellationTokenSource.Cancel();
            };

            var currentDirectory = string.Empty;

            try
            {
                currentDirectory = Environment.CurrentDirectory;

                var formatVersion = GetVersion();
                logger.LogDebug(Resources.The_dotnet_format_version_is_0, formatVersion);

                string?       workspaceDirectory;
                string        workspacePath;
                WorkspaceType workspaceType;

                // The folder option means we should treat the project path as a folder path.
                if (folder)
                {
                    // If folder isn't populated, then use the current directory
                    workspacePath      = Path.GetFullPath(workspace ?? ".", Environment.CurrentDirectory);
                    workspaceDirectory = workspacePath;
                    workspaceType      = WorkspaceType.Folder;
                }
                else
                {
                    var(isSolution, workspaceFilePath) = MSBuildWorkspaceFinder.FindWorkspace(currentDirectory, workspace);

                    workspacePath = workspaceFilePath;
                    workspaceType = isSolution
                        ? WorkspaceType.Solution
                        : WorkspaceType.Project;

                    // To ensure we get the version of MSBuild packaged with the dotnet SDK used by the
                    // workspace, use its directory as our working directory which will take into account
                    // a global.json if present.
                    workspaceDirectory = Path.GetDirectoryName(workspacePath);
                    if (workspaceDirectory is null)
                    {
                        throw new Exception($"Unable to find folder at '{workspacePath}'");
                    }
                }

                if (workspaceType != WorkspaceType.Folder)
                {
                    var runtimeVersion = GetRuntimeVersion();
                    logger.LogDebug(Resources.The_dotnet_runtime_version_is_0, runtimeVersion);

                    // Load MSBuild
                    Environment.CurrentDirectory = workspaceDirectory;

                    if (!TryGetDotNetCliVersion(out var dotnetVersion))
                    {
                        logger.LogError(Resources.Unable_to_locate_dotnet_CLI_Ensure_that_it_is_on_the_PATH);
                        return(UnableToLocateDotNetCliExitCode);
                    }

                    logger.LogTrace(Resources.The_dotnet_CLI_version_is_0, dotnetVersion);

                    if (!TryLoadMSBuild(out var msBuildPath))
                    {
                        logger.LogError(Resources.Unable_to_locate_MSBuild_Ensure_the_NET_SDK_was_installed_with_the_official_installer);
                        return(UnableToLocateMSBuildExitCode);
                    }

                    logger.LogTrace(Resources.Using_msbuildexe_located_in_0, msBuildPath);
                }

                var fixType = FixCategory.None;
                if (s_parseResult.WasOptionUsed("--fix-style", "-s"))
                {
                    fixType |= FixCategory.CodeStyle;
                }

                if (s_parseResult.WasOptionUsed("--fix-analyzers", "-a"))
                {
                    fixType |= FixCategory.Analyzers;
                }

                if (fixType == FixCategory.None || fixWhitespace)
                {
                    fixType |= FixCategory.Whitespace;
                }

                HandleStandardInput(logger, ref include, ref exclude);

                var fileMatcher = SourceFileMatcher.CreateMatcher(include, exclude);

                var formatOptions = new FormatOptions(
                    workspacePath,
                    workspaceType,
                    logLevel,
                    fixType,
                    codeStyleSeverity: GetSeverity(fixStyle ?? FixSeverity.Error),
                    analyzerSeverity: GetSeverity(fixAnalyzers ?? FixSeverity.Error),
                    saveFormattedFiles: !check,
                    changesAreErrors: check,
                    fileMatcher,
                    reportPath: report,
                    includeGenerated);

                var formatResult = await CodeFormatter.FormatWorkspaceAsync(
                    formatOptions,
                    logger,
                    cancellationTokenSource.Token,
                    createBinaryLog : logLevel == LogLevel.Trace).ConfigureAwait(false);

                return(GetExitCode(formatResult, check));
            }
            catch (FileNotFoundException fex)
            {
                logger.LogError(fex.Message);
                return(UnhandledExceptionExitCode);
            }
            catch (OperationCanceledException)
            {
                return(UnhandledExceptionExitCode);
            }
            finally
            {
                if (!string.IsNullOrEmpty(currentDirectory))
                {
                    Environment.CurrentDirectory = currentDirectory;
                }
            }
        }
Ejemplo n.º 6
0
        public static async Task <int> Run(
            string?project,
            string?folder,
            string?workspace,
            string?verbosity,
            bool check,
            string[] include,
            string[] exclude,
            string?report,
            bool includeGenerated,
            IConsole console = null !)
        {
            if (s_parseResult == null)
            {
                return(1);
            }

            // Setup logging.
            var logLevel = GetLogLevel(verbosity);
            var logger   = SetupLogging(console, logLevel);

            // Hook so we can cancel and exit when ctrl+c is pressed.
            var cancellationTokenSource = new CancellationTokenSource();

            Console.CancelKeyPress += (sender, e) =>
            {
                e.Cancel = true;
                cancellationTokenSource.Cancel();
            };

            var currentDirectory = string.Empty;

            try
            {
                currentDirectory = Environment.CurrentDirectory;

                // Check for deprecated options and assign package if specified via `-w | -f` options.
                if (!string.IsNullOrEmpty(workspace) && string.IsNullOrEmpty(project))
                {
                    logger.LogWarning(Resources.The_workspace_option_is_deprecated_Use_the_project_argument_instead);
                    project = workspace;
                }
                else if (!string.IsNullOrEmpty(folder) && string.IsNullOrEmpty(project))
                {
                    logger.LogWarning(Resources.The_folder_option_is_deprecated_for_specifying_the_path_Pass_the_folder_option_but_specify_the_path_with_the_project_argument_instead);
                    project = folder;
                }

                if (s_parseResult.WasOptionUsed("--files"))
                {
                    logger.LogWarning(Resources.The_files_option_is_deprecated_Use_the_include_option_instead);
                }

                if (s_parseResult.WasOptionUsed("--dry-run"))
                {
                    logger.LogWarning(Resources.The_dry_run_option_is_deprecated_Use_the_check_option_instead);
                }

                string        workspaceDirectory;
                string        workspacePath;
                WorkspaceType workspaceType;

                // The presence of the folder token means we should treat the project path as a folder path.
                // This will change in the following version so that the folder option is a bool flag.
                if (s_parseResult.WasOptionUsed("-f", "--folder"))
                {
                    // If folder isn't populated, then use the current directory
                    workspacePath      = Path.GetFullPath(project ?? ".", Environment.CurrentDirectory);
                    workspaceDirectory = workspacePath;
                    workspaceType      = WorkspaceType.Folder;
                }
                else
                {
                    var(isSolution, workspaceFilePath) = MSBuildWorkspaceFinder.FindWorkspace(currentDirectory, project);

                    workspacePath = workspaceFilePath;
                    workspaceType = isSolution
                        ? WorkspaceType.Solution
                        : WorkspaceType.Project;

                    // To ensure we get the version of MSBuild packaged with the dotnet SDK used by the
                    // workspace, use its directory as our working directory which will take into account
                    // a global.json if present.
                    workspaceDirectory = Path.GetDirectoryName(workspacePath);
                    if (workspaceDirectory is null)
                    {
                        throw new Exception($"Unable to find folder at '{workspacePath}'");
                    }
                }

                // Load MSBuild
                Environment.CurrentDirectory = workspaceDirectory;

                if (!TryGetDotNetCliVersion(out var dotnetVersion))
                {
                    logger.LogError(Resources.Unable_to_locate_dotnet_CLI_Ensure_that_it_is_on_the_PATH);
                    return(UnableToLocateDotNetCliExitCode);
                }

                logger.LogTrace(Resources.The_dotnet_CLI_version_is_0, dotnetVersion);

                if (!TryLoadMSBuild(out var msBuildPath))
                {
                    logger.LogError(Resources.Unable_to_locate_MSBuild_Ensure_the_NET_SDK_was_installed_with_the_official_installer);
                    return(UnableToLocateMSBuildExitCode);
                }

                logger.LogTrace(Resources.Using_msbuildexe_located_in_0, msBuildPath);

                var fileMatcher = SourceFileMatcher.CreateMatcher(include, exclude);

                var formatOptions = new FormatOptions(
                    workspacePath,
                    workspaceType,
                    logLevel,
                    saveFormattedFiles: !check,
                    changesAreErrors: check,
                    fileMatcher,
                    reportPath: report,
                    includeGenerated);

                var formatResult = await CodeFormatter.FormatWorkspaceAsync(
                    formatOptions,
                    logger,
                    cancellationTokenSource.Token,
                    createBinaryLog : logLevel == LogLevel.Trace).ConfigureAwait(false);

                return(GetExitCode(formatResult, check));
            }
            catch (FileNotFoundException fex)
            {
                logger.LogError(fex.Message);
                return(UnhandledExceptionExitCode);
            }
            catch (OperationCanceledException)
            {
                return(UnhandledExceptionExitCode);
            }
            finally
            {
                if (!string.IsNullOrEmpty(currentDirectory))
                {
                    Environment.CurrentDirectory = currentDirectory;
                }
            }
        }