protected override int ExecuteCommand(CommandLineApplication app, IConsole console)
        {
            var directory = ProjectDirectory ?? Directory.GetCurrentDirectory();

            if (Directory.EnumerateFiles(directory, $"*{OeBuilderConstants.OeProjectExtension}", SearchOption.TopDirectoryOnly).Any())
            {
                OeProject.SaveXsd(directory);
            }
            else
            {
                directory = OeBuilderConstants.GetProjectDirectory(directory);
                if (Directory.EnumerateFiles(directory, $"*{OeBuilderConstants.OeProjectExtension}", SearchOption.TopDirectoryOnly).Any())
                {
                    OeProject.SaveXsd(directory);
                }
                else
                {
                    directory = null;
                }
            }

            if (!string.IsNullOrEmpty(directory))
            {
                Log.Info($"The file {Path.Combine(directory, OeProject.XsdName)} has been updated with the latest version.");
            }

            return(0);
        }
        protected override int ExecuteCommand(CommandLineApplication app, IConsole console)
        {
            if (string.IsNullOrEmpty(PathToList))
            {
                PathToList = Directory.GetCurrentDirectory();
            }

            if (Directory.Exists(PathToList))
            {
                var files = Directory.EnumerateFiles(PathToList, $"*{OeBuilderConstants.OeProjectExtension}", SearchOption.TopDirectoryOnly).ToList();
                files.AddRange(Directory.EnumerateFiles(Path.Combine(PathToList, OeBuilderConstants.OeProjectDirectory), $"*{OeBuilderConstants.OeProjectExtension}", SearchOption.TopDirectoryOnly).ToList());
                if (files.Count == 0)
                {
                    Log?.Warn($"No project file {OeBuilderConstants.OeProjectExtension} found.");
                }
                else
                {
                    foreach (var file in files)
                    {
                        Out.WriteResultOnNewLine(file.ToRelativePath(PathToList));
                    }
                }
                return(0);
            }

            var projectFile = GetProjectFilePath(PathToList);

            var project = OeProject.Load(projectFile);

            foreach (var buildConfiguration in project.GetAllBuildConfigurations())
            {
                Out.WriteResultOnNewLine((string.IsNullOrEmpty(buildConfiguration.Name) ? "Unnamed configuration" : "Named configuration").PadRight(30));
                Out.WriteResult(string.IsNullOrEmpty(buildConfiguration.Name) ? buildConfiguration.GetId().ToString() : buildConfiguration.Name);
            }

            return(0);
        }
        protected override int ExecuteCommand(CommandLineApplication app, IConsole console)
        {
            if (string.IsNullOrEmpty(SourceDirectory))
            {
                SourceDirectory = Directory.GetCurrentDirectory();
                Log.Trace?.Write($"Using current directory to initialize the project: {SourceDirectory.PrettyQuote()}.");
            }

            SourceDirectory = SourceDirectory.ToAbsolutePath().ToCleanPath();

            if (string.IsNullOrEmpty(ProjectName))
            {
                ProjectName = Path.GetFileName(SourceDirectory);
                Log.Info($"Using directory name for the project name: {ProjectName.PrettyQuote()}.");
            }

            var projectDirectory = IsLocalProject ? OeBuilderConstants.GetProjectDirectoryLocal(SourceDirectory) : OeBuilderConstants.GetProjectDirectory(SourceDirectory);

            if (Utils.CreateDirectoryIfNeeded(projectDirectory, FileAttributes.Hidden))
            {
                Log.Info($"Created project directory: {projectDirectory.PrettyQuote()}.");
            }

            Log.Trace?.Write("Generating a default project.");
            var project = OeProject.GetStandardProject();

            var projectFilePath = Path.Combine(projectDirectory, $"{ProjectName}{OeBuilderConstants.OeProjectExtension}");

            if (File.Exists(projectFilePath))
            {
                if (Force)
                {
                    File.Delete(projectFilePath);
                }
                else
                {
                    throw new CommandValidationException($"The project file already exists, delete it first: {projectFilePath.PrettyQuote()}.");
                }
            }

            Log.Info($"Creating Openedge project file: {projectFilePath.PrettyQuote()}.");
            project.Save(projectFilePath);

            Log.Info($"Project created: {projectFilePath.PrettyQuote()}.");

            HelpWriter.WriteOnNewLine(null);
            HelpWriter.WriteSectionTitle("IMPORTANT README:");
            HelpWriter.WriteOnNewLine(@"
The project file created (" + OeBuilderConstants.OeProjectExtension + @") is defined in XML format and has a provided XML schema definition file (" + OeProject.XsdName + @").

The project XML schema is fully documented and should be used to enable intellisense in your favorite editor.
Example of xml editors with out-of-the-box intellisense (autocomplete) features for xml:

 - Progress Developer studio (eclipse)
 - Visual studio
 - Most jetbrain IDE

Drag and drop the created " + OeBuilderConstants.OeProjectExtension + @" file into the editor of your choice and start configuring your build.
The file " + Path.Combine(OeBuilderConstants.GetProjectDirectory(""), $"{ProjectName}{OeBuilderConstants.OeProjectExtension}").PrettyQuote() + @" should be versioned in your source repository to allow anyone who clones your application to build it.
The file " + OeProject.XsdName.PrettyQuote() + @", however, should not be versioned with your application because it depends on the version of this tool (sakoe). If this tool is updated, use the command " + typeof(ProjectUpdateCommand).GetFullCommandLine <MainCommand>().PrettyQuote() + @" to update the " + OeProject.XsdName.PrettyQuote() + @" to the latest version.

If you need to have a project file containing build configurations specific to your local machine, you can use the option " + (GetCommandOptionFromPropertyName(nameof(IsLocalProject))?.Template ?? "").PrettyQuote() + @". This will create the project file into the directory " + OeBuilderConstants.GetProjectDirectoryLocal("").PrettyQuote() + @" which should NOT be versioned.
For git repositories, use the command " + typeof(ProjectGitignoreCommand).GetFullCommandLine <MainCommand>().PrettyQuote() + @" to set up your .gitignore file for sakoe projects.");
            HelpWriter.WriteOnNewLine(null);
            return(0);
        }
        /// <inheritdoc />
        protected override int ExecuteCommand(CommandLineApplication app, IConsole console)
        {
            // TODO: show task error and compilation error

            // show help.
            if (ShowBuildPropertyHelp)
            {
                HelpWriter.WriteOnNewLine(null);
                HelpWriter.WriteSectionTitle("BUILD PROPERTIES");

                foreach (var property in GetAvailableBuildProperties().OrderBy(p => p.Key))
                {
                    HelpWriter.WriteOnNewLine(property.Key);
                    HelpWriter.WriteOnNewLine(BuilderHelp.GetPropertyDocumentation(property.Key), padding: 20);
                    HelpWriter.WriteOnNewLine(null);
                }
                return(0);
            }

            if (string.IsNullOrEmpty(ProjectFile))
            {
                ProjectFile = GetCurrentProjectFilePath();
            }
            else
            {
                ProjectFile = GetProjectFilePath(ProjectFile);
            }
            Log?.Debug($"Base project file: {ProjectFile.PrettyQuote()}.");

            // get extra config
            var configQueue = new Queue <Tuple <string, string> >();

            configQueue.Enqueue(new Tuple <string, string>(ProjectFile, ConfigurationName));

            if (ExtraConfigurations != null)
            {
                foreach (var extraConfig in ExtraConfigurations)
                {
                    if (string.IsNullOrEmpty(extraConfig))
                    {
                        throw new CommandValidationException("The extra configuration option can't be empty.");
                    }

                    string file;
                    string name;
                    var    split = extraConfig.Split('=');
                    if (split.Length == 1)
                    {
                        file = ProjectFile;
                        name = split[0];
                    }
                    else if (split.Length == 2)
                    {
                        file = split[0];
                        name = split[1];
                    }
                    else
                    {
                        throw new CommandValidationException("There should be only one character '=' in the extra configuration.");
                    }

                    configQueue.Enqueue(new Tuple <string, string>(file, name));
                    Log?.Debug($"Added an extra configuration: {name.PrettyQuote()} in {file.PrettyQuote()}.");
                }
            }

            // check properties
            var availableBuildProperties = GetAvailableBuildProperties();
            var keyValueProperties       = new Dictionary <string, string>();

            if (BuildProperties != null)
            {
                foreach (var buildProperty in BuildProperties)
                {
                    var split = buildProperty.Split('=');
                    if (split.Length != 2)
                    {
                        throw new CommandValidationException($"There should be exactly one character '=' in the property {buildProperty.PrettyQuote()}.");
                    }
                    if (!availableBuildProperties.ContainsKey(split[0]))
                    {
                        throw new CommandValidationException($"The property {split[0].PrettyQuote()} does not exist, use the option {PropertyHelpLongName} to list the available properties.");
                    }
                    if (!keyValueProperties.ContainsKey(split[0]))
                    {
                        keyValueProperties.Add(split[0], split[1]);
                    }
                    else
                    {
                        Log?.Debug($"The property {split[0]} has been defined several times, we keep only the latest.");
                        keyValueProperties[split[0]] = split[1];
                    }
                }
            }

            // check variables
            List <OeVariable> addedVariables = null;

            if (BuildVariables != null)
            {
                addedVariables = new List <OeVariable>();
                foreach (var kpv in BuildVariables)
                {
                    var split = kpv.Split('=');
                    if (split.Length != 2)
                    {
                        throw new CommandValidationException($"There should be exactly one character '=' in the variable definition {kpv.PrettyQuote()}.");
                    }
                    addedVariables.Add(new OeVariable {
                        Name  = split[0],
                        Value = split[1]
                    });
                }
            }

            var config = OeProject.GetConfiguration(configQueue);

            using (var builder = new BuilderAuto(config)) {
                builder.BuildConfiguration.Properties.SetPropertiesFromKeyValuePairs(keyValueProperties);
                if (addedVariables != null)
                {
                    builder.BuildConfiguration.Variables.AddRange(addedVariables);
                }
                builder.BuildConfiguration.Properties.DlcDirectoryPath = GetDlcPath();
                builder.CancelToken = CancelToken;
                builder.Log         = GetLogger();
                builder.Build();


                // display compilation error.
                var compilationProblems = builder.CompilationProblems;
                if (compilationProblems.Count > 0)
                {
                    Out.WriteErrorOnNewLine(null);
                    Out.WriteErrorOnNewLine("COMPILATION ERRORS", ConsoleColor.Yellow, 1);
                    var groups = compilationProblems.GroupBy(cp => cp.FilePath).ToList();
                    var i      = 0;
                    foreach (var filePathGrouped in groups)
                    {
                        Out.WriteErrorOnNewLine($"{(groups.Count - 1 == i ? "└─ " : "├─ ")}In {filePathGrouped.Key}:", indentation: 1);
                        var j = 0;
                        foreach (var problem in filePathGrouped)
                        {
                            Out.WriteErrorOnNewLine($"{(groups.Count - 1 == i ? "   " : "│  ")}{(filePathGrouped.Count() - 1 == j ? "└─ " : "├─ ")}", indentation: 1);
                            Out.WriteError($"Line {problem.Line}, Column {problem.Column}, error {problem.ErrorNumber} : {(string.IsNullOrEmpty(problem.FilePath) ? problem.Message : problem.Message.Replace(problem.FilePath, Path.GetFileName(problem.FilePath)))}", problem is OeCompilationWarning ? ConsoleColor.Yellow : ConsoleColor.Red, 1);
                            j++;
                        }
                        i++;
                    }
                }

                // display exceptions.
                var taskExceptions = builder.TaskExecutionExceptions;
                if (taskExceptions.Count > 0)
                {
                    Out.WriteErrorOnNewLine(null);
                    Out.WriteErrorOnNewLine("TASK EXCEPTIONS", ConsoleColor.Yellow, 1);
                    var i = 0;
                    foreach (var exception in taskExceptions)
                    {
                        Out.WriteErrorOnNewLine(taskExceptions.Count - 1 == i ? "└─ " : "├─ ", indentation: 1);
                        Out.WriteError(exception.Message, exception.IsWarning ? ConsoleColor.Yellow : ConsoleColor.Red, 3);
                        i++;
                    }
                }
            }
            return(0);
        }