From 020389a764837a32dc3348d7a8b72bd277d1e0b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Thu, 5 Aug 2021 21:15:39 +0200 Subject: [PATCH 01/14] Add solution structure and a test command. --- .gitignore | 3 +- Utility-Scripts.sln | 39 ++++++++++++++++ src/Orchard-Core/Orchard-Core.csproj | 14 ++++++ src/Orchard-Core/TestSampleCmdletCommand.cs | 51 +++++++++++++++++++++ 4 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 Utility-Scripts.sln create mode 100644 src/Orchard-Core/Orchard-Core.csproj create mode 100644 src/Orchard-Core/TestSampleCmdletCommand.cs diff --git a/.gitignore b/.gitignore index 0df25f4..5171f91 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,5 @@ buildtasks artifacts robots.txt syntax: regexp -(?i)src/.*bin/.* \ No newline at end of file +(?i)src/.*bin/.* +.idea diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln new file mode 100644 index 0000000..ad54ac1 --- /dev/null +++ b/Utility-Scripts.sln @@ -0,0 +1,39 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30114.105 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard-Core", "src\Orchard-Core\Orchard-Core.csproj", "{D3BA3D61-C374-4881-905C-43819676D5B2}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x64.ActiveCfg = Debug|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x64.Build.0 = Debug|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x86.ActiveCfg = Debug|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x86.Build.0 = Debug|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|Any CPU.Build.0 = Release|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x64.ActiveCfg = Release|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x64.Build.0 = Release|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x86.ActiveCfg = Release|Any CPU + {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {D3BA3D61-C374-4881-905C-43819676D5B2} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} + EndGlobalSection +EndGlobal diff --git a/src/Orchard-Core/Orchard-Core.csproj b/src/Orchard-Core/Orchard-Core.csproj new file mode 100644 index 0000000..dd2731d --- /dev/null +++ b/src/Orchard-Core/Orchard-Core.csproj @@ -0,0 +1,14 @@ + + + + netstandard2.0 + Orchard_Core + + + + + All + + + + diff --git a/src/Orchard-Core/TestSampleCmdletCommand.cs b/src/Orchard-Core/TestSampleCmdletCommand.cs new file mode 100644 index 0000000..73ef872 --- /dev/null +++ b/src/Orchard-Core/TestSampleCmdletCommand.cs @@ -0,0 +1,51 @@ +using System; +using System.Management.Automation; +using System.Management.Automation.Runspaces; + +namespace Orchard_Core +{ + [Cmdlet(VerbsDiagnostic.Test,"SampleCmdlet")] + [OutputType(typeof(FavoriteStuff))] + public class TestSampleCmdletCommand : PSCmdlet + { + [Parameter( + Mandatory = true, + Position = 0, + ValueFromPipeline = true, + ValueFromPipelineByPropertyName = true)] + public int FavoriteNumber { get; set; } + + [Parameter( + Position = 1, + ValueFromPipelineByPropertyName = true)] + [ValidateSet("Cat", "Dog", "Horse")] + public string FavoritePet { get; set; } = "Dog"; + + // This method gets called once for each cmdlet in the pipeline when the pipeline starts executing + protected override void BeginProcessing() + { + WriteVerbose("Begin!"); + } + + // This method will be called for each input received from the pipeline to this cmdlet; if no input is received, this method is not called + protected override void ProcessRecord() + { + WriteObject(new FavoriteStuff { + FavoriteNumber = FavoriteNumber, + FavoritePet = FavoritePet + }); + } + + // This method will be called once at the end of pipeline execution; if no input is received, this method is not called + protected override void EndProcessing() + { + WriteVerbose("End!"); + } + } + + public class FavoriteStuff + { + public int FavoriteNumber { get; set; } + public string FavoritePet { get; set; } + } +} From f1581936d7bf0cfa2e99cdddda4819ecafdf2125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Thu, 5 Aug 2021 22:40:00 +0200 Subject: [PATCH 02/14] Ported Init-OrchardCoreSolution. --- .gitignore | 1 + ...tializeOrchardCoreSolutionCmdletCommand.cs | 91 +++++++++ .../{ => Cmdlets}/TestSampleCmdletCommand.cs | 6 +- src/Orchard-Core/Constants/NounNames.cs | 9 + .../Helpers/FormerlyScriptHelper.cs | 30 +++ src/Orchard-Core/Orchard-Core.csproj | 11 +- src/Orchard-Core/gitignore.template | 189 ++++++++++++++++++ 7 files changed, 332 insertions(+), 5 deletions(-) create mode 100644 src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs rename src/Orchard-Core/{ => Cmdlets}/TestSampleCmdletCommand.cs (92%) create mode 100644 src/Orchard-Core/Constants/NounNames.cs create mode 100644 src/Orchard-Core/Helpers/FormerlyScriptHelper.cs create mode 100644 src/Orchard-Core/gitignore.template diff --git a/.gitignore b/.gitignore index 5171f91..2c4994f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ robots.txt syntax: regexp (?i)src/.*bin/.* .idea +/src/Orchard-Core/bin diff --git a/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs b/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs new file mode 100644 index 0000000..f680041 --- /dev/null +++ b/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections.Generic; +using System.Management.Automation; +using CliWrap; +using Lombiq.UtilityScripts.OrchardCore.Constants; +using static Lombiq.UtilityScripts.OrchardCore.Helpers.FormerlyScriptHelper; + +namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets +{ + // TODO: How to turn this into help docs? Maybe this? https://docs.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-help-using-platyps?view=powershell-7.1 + + /// + /// Initializes an Orchard Core solution for a git repository. + /// + /// + /// + /// Initializes an Orchard Core solution using the latest released Orchard Core NuGet packages at the current + /// location or under the given path, and adds a suitable .gitignore file. Optionally creates an initial module + /// and/or theme, and optionally uses a given NuGet source. + /// + /// + /// + /// + /// Init-OrchardCoreSolution + /// -Name "FancyWebsite" + /// -Path "D:\Work\FancyWebsite" + /// -ModuleName "FancyWebsite.Core" + /// -ThemeName "FancyWebsite.Theme" + /// -NuGetSource "https://nuget.cloudsmith.io/orchardcore/preview/v3/index.json" + /// + /// + [Cmdlet(VerbsData.Initialize, NounNames.OrchardCoreSolution)] + [Alias(VerbsData.Initialize + "-" + NounNames.OrchardCore)] + [OutputType(typeof(FavoriteStuff))] + public class InitializeOrchardCoreSolutionCmdletCommand : PSCmdlet + { + [Parameter(Position = 0)] + public string Path { get; set; } + + [Parameter(Mandatory = true, Position = 1)] + public string Name { get; set; } + + [Parameter(Position = 2)] + public string ModuleName { get; set; } + + [Parameter(Position = 3)] + public string ThemeName { get; set; } + + [Parameter(Position = 4)] + public string NuGetSource { get; set; } + + private string _dotnetPath = null; + + protected override void ProcessRecord() + { + if (string.IsNullOrWhiteSpace(Path)) Path = Environment.CurrentDirectory; + + _dotnetPath = "dotnet"; + + var installArguments = new List { "new", "-i", "OrchardCore.ProjectTemplates::1.0.0-*" }; + if (!string.IsNullOrWhiteSpace(NuGetSource)) installArguments.Add(NuGetSource); + Dotnet(installArguments.ToArray()); + + Dotnet("occms", "-o", $"{Path}/src/$Name.Web"); + Dotnet("new", "sln", "-o", Path, "-n", Name); + + if (!string.IsNullOrWhiteSpace(ModuleName)) + { + Dotnet("new", "ocmodulecms", "-n", ModuleName, "-o", $"{Path}/src/Modules/{ModuleName}"); + Dotnet("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); + Dotnet("sln", $"{Path}/{Name}.sln", "add", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); + } + + if (!string.IsNullOrWhiteSpace(ThemeName)) + { + Dotnet("new", "octheme", "-n", ThemeName, "-o", $"{Path}/src/Themes/{ThemeName}"); + Dotnet("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); + Dotnet("sln", $"{Path}/{Name}.sln", "add", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); + } + + System.IO.File.Copy( + System.IO.Path.Combine(PSScriptRoot, "gitignore.template"), + System.IO.Path.Combine(Path, ".gitignore")); + } + + private void Dotnet(params string[] arguments) => + Cli + .Wrap(_dotnetPath) + .WithArguments(arguments); + } +} \ No newline at end of file diff --git a/src/Orchard-Core/TestSampleCmdletCommand.cs b/src/Orchard-Core/Cmdlets/TestSampleCmdletCommand.cs similarity index 92% rename from src/Orchard-Core/TestSampleCmdletCommand.cs rename to src/Orchard-Core/Cmdlets/TestSampleCmdletCommand.cs index 73ef872..de54816 100644 --- a/src/Orchard-Core/TestSampleCmdletCommand.cs +++ b/src/Orchard-Core/Cmdlets/TestSampleCmdletCommand.cs @@ -1,8 +1,6 @@ -using System; -using System.Management.Automation; -using System.Management.Automation.Runspaces; +using System.Management.Automation; -namespace Orchard_Core +namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets { [Cmdlet(VerbsDiagnostic.Test,"SampleCmdlet")] [OutputType(typeof(FavoriteStuff))] diff --git a/src/Orchard-Core/Constants/NounNames.cs b/src/Orchard-Core/Constants/NounNames.cs new file mode 100644 index 0000000..29edabe --- /dev/null +++ b/src/Orchard-Core/Constants/NounNames.cs @@ -0,0 +1,9 @@ +namespace Lombiq.UtilityScripts.OrchardCore.Constants +{ + public static class NounNames + { + public const string OrchardCore = nameof(OrchardCore); + public const string OrchardCoreSolution = nameof(OrchardCoreSolution); + public const string OrchardCoreApp = nameof(OrchardCoreApp); + } +} \ No newline at end of file diff --git a/src/Orchard-Core/Helpers/FormerlyScriptHelper.cs b/src/Orchard-Core/Helpers/FormerlyScriptHelper.cs new file mode 100644 index 0000000..e86a86c --- /dev/null +++ b/src/Orchard-Core/Helpers/FormerlyScriptHelper.cs @@ -0,0 +1,30 @@ +using System.IO; +using Lombiq.UtilityScripts.OrchardCore.Cmdlets; + +namespace Lombiq.UtilityScripts.OrchardCore.Helpers +{ + /// + /// Helper to ease transition from the scripts. + /// + public static class FormerlyScriptHelper + { + private static string _psScriptRoot = null; + + /// + /// Gets the string that behaves like the Powershell builtin $PSScriptRoot. + /// + public static string PSScriptRoot + { + get + { + if (_psScriptRoot == null) + { + var assemblyLocation = typeof(InitializeOrchardCoreSolutionCmdletCommand).Assembly.Location; + _psScriptRoot = Path.GetDirectoryName(assemblyLocation); + } + + return _psScriptRoot; + } + } + } +} \ No newline at end of file diff --git a/src/Orchard-Core/Orchard-Core.csproj b/src/Orchard-Core/Orchard-Core.csproj index dd2731d..606c8f2 100644 --- a/src/Orchard-Core/Orchard-Core.csproj +++ b/src/Orchard-Core/Orchard-Core.csproj @@ -2,13 +2,22 @@ netstandard2.0 - Orchard_Core + Lombiq.UtilityScripts.OrchardCore + Lombiq.UtilityScripts.OrchardCore + All + + + + PreserveNewest + + + diff --git a/src/Orchard-Core/gitignore.template b/src/Orchard-Core/gitignore.template new file mode 100644 index 0000000..2305c85 --- /dev/null +++ b/src/Orchard-Core/gitignore.template @@ -0,0 +1,189 @@ +## Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.sln.docstates +*.sln.ide/ + +# Build results + +[Dd]ebug/ +[Rr]elease/ +x64/ +build/ +app.publish/ +[Bb]in/ +[Oo]bj/ + +# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets +!packages/*/build/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +*_i.c +*_p.c +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.log +*.scc +project.lock.json + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +*.ncrunch* +.*crunch*.local.xml + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.Publish.xml +*.pubxml + +# NuGet Packages Directory +packages/ + +# Windows Azure Build Output +csx +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Others +*.Cache +!OrchardCore.Environment.Cache +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.[Pp]ublish.xml +*.pfx +*.publishsettings + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file to a newer +# Visual Studio version. Backup files are not needed, because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + + +## Windows and MAC detritus + +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Mac +.DS_Store + + +## ASP.NET Core and Orchard Core specifics + +App_Data/ +*.user +*.patch +*.hg +build/ +/buildazure +/buildtasks +/artifacts +site/ +*.sln.cache +log.xml +profiling/ +*.orig +.vs/ +#.vscode/ +.build/ +.testPublish/ + +nuget.exe +.nuget/ + +# Enable all /lib artifacts +!lib/*/*.* + +# Exclude node modules +node_modules/ + +# Exclude wwwroot and add exceptions +**/wwwroot/* +!**/wwwroot/favicon.ico +!**/wwwroot/.placeholder + +src/*.Web/Localization From edf30b3db2b87e6af9703dcf93c18f93ae60b208 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Fri, 6 Aug 2021 08:14:45 +0200 Subject: [PATCH 03/14] Added ResetOrchardCoreAppCmdletCommand --- ...tializeOrchardCoreSolutionCmdletCommand.cs | 17 +- .../ResetOrchardCoreAppCmdletCommand.cs | 387 ++++++++++++++++++ .../Constants/ParameterSetNames.cs | 7 + 3 files changed, 405 insertions(+), 6 deletions(-) create mode 100644 src/Orchard-Core/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs create mode 100644 src/Orchard-Core/Constants/ParameterSetNames.cs diff --git a/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs b/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs index f680041..cc504fb 100644 --- a/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs +++ b/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs @@ -1,8 +1,10 @@ using System; using System.Collections.Generic; +using System.IO; using System.Management.Automation; using CliWrap; using Lombiq.UtilityScripts.OrchardCore.Constants; +using IoPath = System.IO.Path; using static Lombiq.UtilityScripts.OrchardCore.Helpers.FormerlyScriptHelper; namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets @@ -31,7 +33,7 @@ namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets /// [Cmdlet(VerbsData.Initialize, NounNames.OrchardCoreSolution)] [Alias(VerbsData.Initialize + "-" + NounNames.OrchardCore)] - [OutputType(typeof(FavoriteStuff))] + [OutputType(typeof(FileInfo))] public class InitializeOrchardCoreSolutionCmdletCommand : PSCmdlet { [Parameter(Position = 0)] @@ -56,6 +58,7 @@ protected override void ProcessRecord() if (string.IsNullOrWhiteSpace(Path)) Path = Environment.CurrentDirectory; _dotnetPath = "dotnet"; + var solutionFilePath = $"{Path}/{Name}.sln"; var installArguments = new List { "new", "-i", "OrchardCore.ProjectTemplates::1.0.0-*" }; if (!string.IsNullOrWhiteSpace(NuGetSource)) installArguments.Add(NuGetSource); @@ -68,19 +71,21 @@ protected override void ProcessRecord() { Dotnet("new", "ocmodulecms", "-n", ModuleName, "-o", $"{Path}/src/Modules/{ModuleName}"); Dotnet("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); - Dotnet("sln", $"{Path}/{Name}.sln", "add", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); + Dotnet("sln", solutionFilePath, "add", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); } if (!string.IsNullOrWhiteSpace(ThemeName)) { Dotnet("new", "octheme", "-n", ThemeName, "-o", $"{Path}/src/Themes/{ThemeName}"); Dotnet("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); - Dotnet("sln", $"{Path}/{Name}.sln", "add", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); + Dotnet("sln", solutionFilePath, "add", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); } - System.IO.File.Copy( - System.IO.Path.Combine(PSScriptRoot, "gitignore.template"), - System.IO.Path.Combine(Path, ".gitignore")); + File.Copy( + IoPath.Combine(PSScriptRoot, "gitignore.template"), + IoPath.Combine(Path, ".gitignore")); + + WriteObject(new FileInfo(solutionFilePath)); } private void Dotnet(params string[] arguments) => diff --git a/src/Orchard-Core/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs b/src/Orchard-Core/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs new file mode 100644 index 0000000..2e33bde --- /dev/null +++ b/src/Orchard-Core/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs @@ -0,0 +1,387 @@ +using System; +using System.Diagnostics; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Management.Automation; +using System.Threading; +using Lombiq.UtilityScripts.OrchardCore.Constants; +using static Lombiq.UtilityScripts.OrchardCore.Constants.ParameterSetNames; + +namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets +{ + + [Cmdlet(VerbsCommon.Reset, NounNames.OrchardCoreApp)] + [Alias(VerbsCommon.Reset + "-" + NounNames.OrchardCore)] + [OutputType(typeof(FileInfo))] + public class ResetOrchardCoreAppCmdletCommand : PSCmdlet + { + private const string Name = VerbsCommon.Reset + "-" + NounNames.OrchardCoreApp; + + [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)] + public string WebProjectPath { get; set; } + + [Parameter] + public string SetupSiteName { get; set; } = "Orchard Core"; + + [Parameter] + public string SetupTenantName { get; set; } = "Default"; + + [Parameter] + public string SetupRecipeName { get; set; } = "Blog"; + + [Parameter] + public string SetupUserName { get; set; } = "admin"; + + [Parameter] + public string SetupPassword { get; set; } = "Password1!"; + + [Parameter] + public string SetupEmail { get; set; } = "admin@localhost"; + + public int Port { get; set; } = 5000; + + [Parameter(ParameterSetName = ServerDB, Mandatory = true)] + [ValidateSet("SqlConnection")] + public string SetupDatabaseProvider { get; set; } = "Sqlite"; + + [Parameter(ParameterSetName = ServerDB)] + public string SetupDatabaseTablePrefix { get; set; } = ""; + + [Parameter(ParameterSetName = ServerDB)] + public string SetupDatabaseServerName { get; set; } = "-"; + + [Parameter(ParameterSetName = ServerDB)] + public string SetupDatabaseName { get; set; } = "OrchardCore"; + + [Parameter(ParameterSetName = ServerDB)] + public string SetupDatabaseSqlUser { get; set; } = "sa"; + + [Parameter(ParameterSetName = ServerDB)] + public string SetupDatabaseSqlPassword { get; set; } = null; + + [Parameter(ParameterSetName = ServerDB)] + public SwitchParameter Force { get; set; } + + [Parameter(ParameterSetName = ServerDB)] + public SwitchParameter SuffixDatabaseNameWithFolderName { get; set; } + + [Parameter] + public SwitchParameter Rebuild { get; set; } + + [Parameter] + public SwitchParameter KeepAlive { get; set; } + + [Parameter] + public SwitchParameter Pause { get; set; } + + protected override void ProcessRecord() + { + string webProjectDllPath; + string siteName; + + // Checking if the Web Project Path is valid and extracting the name of the Web Project. + if (File.Exists(WebProjectPath)) + { + if (!WebProjectPath.EndsWith(".DLL", StringComparison.OrdinalIgnoreCase)) + { + throw new InvalidOperationException( + $"The {nameof(WebProjectPath)} must be a dll file or a directory path."); + } + + webProjectDllPath = WebProjectPath; + var fileInfo = new FileInfo(WebProjectPath); + siteName = fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf('.')); + WebProjectPath = Path.GetDirectoryName(WebProjectPath); + } + else if (!Directory.Exists(WebProjectPath)) + { + throw new InvalidOperationException( + $"The {nameof(WebProjectPath)} is not found or not accessible! ({WebProjectPath})"); + } + else + { + webProjectDllPath = GetWebProjectDllPath(WebProjectPath); + siteName = Path.GetFileName(WebProjectPath); + } + + // Trying to find IIS Express and .NET host processes that run a Web Project with a matching name and + // terminate them. + var siteHostProcesses = Process.GetProcessesByName("iisexpress.exe") + .Concat(Process.GetProcessesByName("dotnet.exe")) + .Where(process => process.StartInfo?.Arguments?.Contains("$siteName", StringComparer.OrdinalIgnoreCase) == true) + .ToList(); + + if (siteHostProcesses.Any()) + { + foreach (var process in siteHostProcesses) + { + var commandLine = $"{process.StartInfo.FileName} {process.StartInfo.Arguments}"; + Info($"Terminating application host process running \"{commandLine}\"."); + + process.Kill(); + } + + Thread.Sleep(1000); + } + + //Delete App_Data if exists. + var appData = new DirectoryInfo($"{WebProjectPath}\\App_Data"); + if (appData.Exists) + { + Info($"Deleting App_Data folder found in \"{appData.FullName}\"."); + appData.Delete(recursive: true); + } + + /* + # Rebuilding the application if the "Rebuild" switch is present or the Web Project DLL is not found. + + $buildRequired = $false; + if ($Rebuild.IsPresent) + { + "Rebuild switch active!`n" + + $buildRequired = $true + } + elseif ([string]::IsNullOrEmpty($webProjectDllPath) -or -not (Test-Path $webProjectDllPath -PathType Leaf)) + { + "Web Project DLL not found, build is required!`n" + + $buildRequired = $true + } + + if ($buildRequired) + { + dotnet build "$WebProjectPath" --configuration Debug + + if ($LASTEXITCODE -ne 0) + { + pause + + exit $LASTEXITCODE + } + else + { + $webProjectDllPath = GetWebProjectDllPath($WebProjectPath) + + if ([string]::IsNullOrEmpty($webProjectDllPath)) + { + throw "Project was successfully built at `"$WebProjectPath`", but the compiled Web Project DLL was not found!" + } + } + } + + "Compiled Web Project DLL found at `"$webProjectDllPath`"!`n" + + + + # Validating and setting up database server connection. + + $SetupDatabaseConnectionString = "" + if ($PSCmdlet.ParameterSetName -eq "ServerDB") + { + if ($SuffixDatabaseNameWithFolderName.IsPresent) + { + $solutionPath = (Get-Location).Path + + while (-not [string]::IsNullOrEmpty($solutionPath) -and -not (Test-Path (Join-Path $solutionPath "*.sln"))) + { + $solutionPath = Split-Path $solutionPath -Parent; + } + + if ([string]::IsNullOrEmpty($solutionPath)) + { + throw ("No solution folder was found to create the database name suffix. Put this script into a folder where there or in a parent folder there is the app's .sln file.") + } + + $solutionFolder = Split-Path $solutionPath -Leaf + + $SetupDatabaseName = $SetupDatabaseName + "_" + $solutionFolder + } + + "Using the following database name: `"$SetupDatabaseName`"." + + if (New-SqlServerDatabase -SqlServerName $SetupDatabaseServerName -DatabaseName $SetupDatabaseName -Force:$Force.IsPresent -ErrorAction Stop -UserName $SetupDatabaseSqlUser -Password $SetupDatabaseSqlPassword) + { + "Database `"$SetupDatabaseServerName\$SetupDatabaseName`" created!" + } + else + { + if ([string]::IsNullOrEmpty($SetupDatabaseTablePrefix)) + { + throw ("Database `"$SetupDatabaseServerName\$SetupDatabaseName`" could not be created!") + } + else + { + "The specified database already exists! Attempting to run setup using the `"$SetupDatabaseTablePrefix`" table prefix." + } + } + + $Security = if (-not $SetupDatabaseSqlPassword) + { + "Integrated Security=True" + } + else + { + "User Id=$SetupDatabaseSqlUser;Password=$SetupDatabaseSqlPassword" + } + + # MARS is necessary for Orchard. + $SetupDatabaseConnectionString = "Server=$SetupDatabaseServerName;Database=$SetupDatabaseName;$Security;MultipleActiveResultSets=True;" + } + + + + # Try to find the Launch Settings file to get the launch URL of the application. + # If not found (or the URL is not found in the settings), and the $Port parameter is set to <=0 then using a random one on localhost instead. + + $launchSettingsFilePath = $("$WebProjectPath\Properties\launchSettings.json") + $environmentSetting = "Development" + + if ($Port -le 0) + { + $Port = Get-Random -Minimum 2000 -Maximum 64000 + } + + $applicationUrl = "http://localhost:$Port" + + if (Test-Path $launchSettingsFilePath -PathType Leaf) + { + $launchSettings = Get-Content $launchSettingsFilePath | ConvertFrom-Json + + $applicationUrlSetting = $launchSettings.profiles."$SiteName".applicationUrl + + if (-not [string]::IsNullOrEmpty($applicationUrlSetting)) + { + $applicationUrlsFromSetting = $applicationUrlSetting -split ";" + + $applicationUrlFromSetting = $applicationUrlsFromSetting | Where-Object { $_.StartsWith("http://") } + + if (-not [string]::IsNullOrEmpty($applicationUrlFromSetting)) + { + $applicationUrl = $applicationUrlFromSetting.Trim() + } + } + + $environmentSetting = $launchSettings.profiles."$SiteName".environmentVariables.ASPNETCORE_ENVIRONMENT + + if ([string]::IsNullOrEmpty($environmentSetting)) + { + $environmentSetting = "Development" + } + } + + + + # Launching the .NET application host process. + + $webProjectDllFile = Get-Item -Path $webProjectDllPath + + "Starting .NET application host at `"$applicationUrl`"!`n" + + $applicationProcess = Start-Process ` + -WorkingDirectory $WebProjectPath ` + dotnet ` + -ArgumentList "$($webProjectDllFile.FullName) --urls $applicationUrl --environment $environmentSetting --webroot wwwroot --AuthorizeOrchardApiRequests true" ` + -PassThru + + + + # Confirming that the host process has started the application successfully. + + Start-Sleep 2 + + $applicationRunning = $false + do + { + Start-Sleep 1 + + if ($applicationProcess.HasExited) + { + throw "Application host process exited with exit code $($applicationProcess.ExitCode)!`nCheck if another application host process (IIS Express or dotnet) is running under a different user account using the same port and terminate it!" + } + + $setupScreenResponse = Invoke-WebRequest -Uri $applicationUrl -UseBasicParsing -ErrorAction Stop + + if ($setupScreenResponse.StatusCode -ne 200) + { + throw "Application host process started, but the setup screen returned status code $($setupScreenResponse.StatusCode)!" + } + + $applicationRunning = $true + } + until ($applicationRunning) + + + + # Running setup. + + "Application started, attempting to run setup!`n" + + $tenantSetupSettings = @{ + SiteName = $SetupSiteName + DatabaseProvider = $SetupDatabaseProvider + TablePrefix = $SetupDatabaseTablePrefix + ConnectionString = $SetupDatabaseConnectionString + RecipeName = $SetupRecipeName + UserName = $SetupUserName + Password = $SetupPassword + Email = $SetupEmail + Name = $SetupTenantName + } + + $setupRequest = Invoke-WebRequest -Method Post -Uri "$applicationUrl/api/tenants/setup" -Body (ConvertTo-Json($tenantSetupSettings)) -ContentType "application/json" -UseBasicParsing + + if ($setupRequest.StatusCode -ne 200) + { + Stop-Process $applicationProcess + + throw "Setup failed with status code $($setupRequest.StatusCode)!" + } + + "Setup successful!`n" + + + + # Terminating the .NET application host process if Keep Alive is not requested. + + if (-not $KeepAlive.IsPresent) + { + "Keep Alive not requested, shutting down application host process!" + + Stop-Process $applicationProcess + } + + + + if ($Pause.IsPresent) + { + pause + } + + exit 0 + } + */ + } + + /// + /// Looking for the Web Project DLL and selecting the latest ASP.NET Core variant if more than one found. + /// + private string GetWebProjectDllPath(string WebProjectPath) + { + var siteName = Path.GetFileName(WebProjectPath); + var netCoreAppDirectoryPath = Directory + .GetDirectories(Path.Combine(WebProjectPath, "bin", "Debug")) + .FirstOrDefault(); + + if (netCoreAppDirectoryPath == null) return string.Empty; + var webProjectDllPath = Path.Combine(netCoreAppDirectoryPath, siteName + ".dll"); + + return File.Exists(webProjectDllPath) + ? webProjectDllPath + : string.Empty; + } + + private void Info(string message) => WriteInformation(new InformationRecord(message, Name)); + } +} \ No newline at end of file diff --git a/src/Orchard-Core/Constants/ParameterSetNames.cs b/src/Orchard-Core/Constants/ParameterSetNames.cs new file mode 100644 index 0000000..ad9bd5a --- /dev/null +++ b/src/Orchard-Core/Constants/ParameterSetNames.cs @@ -0,0 +1,7 @@ +namespace Lombiq.UtilityScripts.OrchardCore.Constants +{ + public class ParameterSetNames + { + public const string ServerDB = nameof(ServerDB); + } +} \ No newline at end of file From 7b48fee28b7fdc75bb76e13619342c61f575a0c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Fri, 6 Aug 2021 08:17:27 +0200 Subject: [PATCH 04/14] Rename project file. --- .gitignore | 1 + Utility-Scripts.sln | 28 +++++++++---------- ...tializeOrchardCoreSolutionCmdletCommand.cs | 0 .../ResetOrchardCoreAppCmdletCommand.cs | 0 .../Cmdlets/TestSampleCmdletCommand.cs | 0 .../Constants/NounNames.cs | 0 .../Constants/ParameterSetNames.cs | 0 .../Helpers/FormerlyScriptHelper.cs | 0 .../Lombiq.UtilityScripts.OrchardCore.csproj} | 0 .../gitignore.template | 0 10 files changed, 15 insertions(+), 14 deletions(-) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs (100%) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs (100%) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/Cmdlets/TestSampleCmdletCommand.cs (100%) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/Constants/NounNames.cs (100%) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/Constants/ParameterSetNames.cs (100%) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/Helpers/FormerlyScriptHelper.cs (100%) rename src/{Orchard-Core/Orchard-Core.csproj => Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj} (100%) rename src/{Orchard-Core => Lombiq.UtilityScripts.OrchardCore}/gitignore.template (100%) diff --git a/.gitignore b/.gitignore index 2c4994f..df53ff5 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ syntax: regexp (?i)src/.*bin/.* .idea /src/Orchard-Core/bin +/src/*/bin diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln index ad54ac1..f34e54a 100644 --- a/Utility-Scripts.sln +++ b/Utility-Scripts.sln @@ -5,7 +5,7 @@ VisualStudioVersion = 16.0.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Orchard-Core", "src\Orchard-Core\Orchard-Core.csproj", "{D3BA3D61-C374-4881-905C-43819676D5B2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.OrchardCore", "src\Lombiq.UtilityScripts.OrchardCore\Lombiq.UtilityScripts.OrchardCore.csproj", "{9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -20,20 +20,20 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x64.ActiveCfg = Debug|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x64.Build.0 = Debug|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x86.ActiveCfg = Debug|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Debug|x86.Build.0 = Debug|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|Any CPU.Build.0 = Release|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x64.ActiveCfg = Release|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x64.Build.0 = Release|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x86.ActiveCfg = Release|Any CPU - {D3BA3D61-C374-4881-905C-43819676D5B2}.Release|x86.Build.0 = Release|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x64.ActiveCfg = Debug|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x64.Build.0 = Debug|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x86.ActiveCfg = Debug|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x86.Build.0 = Debug|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|Any CPU.Build.0 = Release|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x64.ActiveCfg = Release|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x64.Build.0 = Release|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x86.ActiveCfg = Release|Any CPU + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution - {D3BA3D61-C374-4881-905C-43819676D5B2} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} + {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} EndGlobalSection EndGlobal diff --git a/src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs similarity index 100% rename from src/Orchard-Core/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs rename to src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs diff --git a/src/Orchard-Core/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs similarity index 100% rename from src/Orchard-Core/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs rename to src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs diff --git a/src/Orchard-Core/Cmdlets/TestSampleCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/TestSampleCmdletCommand.cs similarity index 100% rename from src/Orchard-Core/Cmdlets/TestSampleCmdletCommand.cs rename to src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/TestSampleCmdletCommand.cs diff --git a/src/Orchard-Core/Constants/NounNames.cs b/src/Lombiq.UtilityScripts.OrchardCore/Constants/NounNames.cs similarity index 100% rename from src/Orchard-Core/Constants/NounNames.cs rename to src/Lombiq.UtilityScripts.OrchardCore/Constants/NounNames.cs diff --git a/src/Orchard-Core/Constants/ParameterSetNames.cs b/src/Lombiq.UtilityScripts.OrchardCore/Constants/ParameterSetNames.cs similarity index 100% rename from src/Orchard-Core/Constants/ParameterSetNames.cs rename to src/Lombiq.UtilityScripts.OrchardCore/Constants/ParameterSetNames.cs diff --git a/src/Orchard-Core/Helpers/FormerlyScriptHelper.cs b/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs similarity index 100% rename from src/Orchard-Core/Helpers/FormerlyScriptHelper.cs rename to src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs diff --git a/src/Orchard-Core/Orchard-Core.csproj b/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj similarity index 100% rename from src/Orchard-Core/Orchard-Core.csproj rename to src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj diff --git a/src/Orchard-Core/gitignore.template b/src/Lombiq.UtilityScripts.OrchardCore/gitignore.template similarity index 100% rename from src/Orchard-Core/gitignore.template rename to src/Lombiq.UtilityScripts.OrchardCore/gitignore.template From 758a04021f6ba79b862f910fda86280aa82a60cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Fri, 6 Aug 2021 09:00:27 +0200 Subject: [PATCH 05/14] More work on ResetOrchardCoreAppCmdletCommand. --- .../Cmdlets/AsyncCmdletBase.cs | 29 ++++ ...tializeOrchardCoreSolutionCmdletCommand.cs | 34 +++-- .../ResetOrchardCoreAppCmdletCommand.cs | 125 ++++++++++++------ .../Helpers/FormerlyScriptHelper.cs | 9 ++ 4 files changed, 139 insertions(+), 58 deletions(-) create mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs new file mode 100644 index 0000000..471c02c --- /dev/null +++ b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs @@ -0,0 +1,29 @@ +using System; +using System.Management.Automation; +using System.Threading.Tasks; + +namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets +{ + public abstract class AsyncCmdletBase : PSCmdlet + { + protected abstract string CmdletName { get; } + + protected override void ProcessRecord() + { + try + { + ProcessRecordAsync().Wait(); + } + catch (Exception exception) + { + Error(exception, ErrorCategory.NotSpecified); + } + } + + protected abstract Task ProcessRecordAsync(); + + protected void Info(string message) => WriteInformation(new InformationRecord(message, CmdletName)); + protected void Error(Exception exception, ErrorCategory errorCategory) => + WriteError(new ErrorRecord(exception, exception.GetType().Name, errorCategory, CmdletName)); + } +} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs index cc504fb..cebe314 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs @@ -2,7 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Management.Automation; -using CliWrap; +using System.Threading.Tasks; using Lombiq.UtilityScripts.OrchardCore.Constants; using IoPath = System.IO.Path; using static Lombiq.UtilityScripts.OrchardCore.Helpers.FormerlyScriptHelper; @@ -34,8 +34,11 @@ namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets [Cmdlet(VerbsData.Initialize, NounNames.OrchardCoreSolution)] [Alias(VerbsData.Initialize + "-" + NounNames.OrchardCore)] [OutputType(typeof(FileInfo))] - public class InitializeOrchardCoreSolutionCmdletCommand : PSCmdlet + public class InitializeOrchardCoreSolutionCmdletCommand : AsyncCmdletBase { + private const string _cmdletName = VerbsData.Initialize + "-" + NounNames.OrchardCore; + protected override string CmdletName => _cmdletName; + [Parameter(Position = 0)] public string Path { get; set; } @@ -51,34 +54,32 @@ public class InitializeOrchardCoreSolutionCmdletCommand : PSCmdlet [Parameter(Position = 4)] public string NuGetSource { get; set; } - private string _dotnetPath = null; - protected override void ProcessRecord() + protected override async Task ProcessRecordAsync() { if (string.IsNullOrWhiteSpace(Path)) Path = Environment.CurrentDirectory; - _dotnetPath = "dotnet"; var solutionFilePath = $"{Path}/{Name}.sln"; var installArguments = new List { "new", "-i", "OrchardCore.ProjectTemplates::1.0.0-*" }; if (!string.IsNullOrWhiteSpace(NuGetSource)) installArguments.Add(NuGetSource); - Dotnet(installArguments.ToArray()); + await DotnetAsync(installArguments.ToArray()); - Dotnet("occms", "-o", $"{Path}/src/$Name.Web"); - Dotnet("new", "sln", "-o", Path, "-n", Name); + await DotnetAsync("occms", "-o", $"{Path}/src/$Name.Web"); + await DotnetAsync("new", "sln", "-o", Path, "-n", Name); if (!string.IsNullOrWhiteSpace(ModuleName)) { - Dotnet("new", "ocmodulecms", "-n", ModuleName, "-o", $"{Path}/src/Modules/{ModuleName}"); - Dotnet("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); - Dotnet("sln", solutionFilePath, "add", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); + await DotnetAsync("new", "ocmodulecms", "-n", ModuleName, "-o", $"{Path}/src/Modules/{ModuleName}"); + await DotnetAsync("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); + await DotnetAsync("sln", solutionFilePath, "add", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); } if (!string.IsNullOrWhiteSpace(ThemeName)) { - Dotnet("new", "octheme", "-n", ThemeName, "-o", $"{Path}/src/Themes/{ThemeName}"); - Dotnet("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); - Dotnet("sln", solutionFilePath, "add", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); + await DotnetAsync("new", "octheme", "-n", ThemeName, "-o", $"{Path}/src/Themes/{ThemeName}"); + await DotnetAsync("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); + await DotnetAsync("sln", solutionFilePath, "add", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); } File.Copy( @@ -87,10 +88,5 @@ protected override void ProcessRecord() WriteObject(new FileInfo(solutionFilePath)); } - - private void Dotnet(params string[] arguments) => - Cli - .Wrap(_dotnetPath) - .WithArguments(arguments); } } \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs index 2e33bde..dcd62c0 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs @@ -1,12 +1,13 @@ using System; using System.Diagnostics; -using System.Globalization; using System.IO; using System.Linq; using System.Management.Automation; using System.Threading; +using System.Threading.Tasks; using Lombiq.UtilityScripts.OrchardCore.Constants; using static Lombiq.UtilityScripts.OrchardCore.Constants.ParameterSetNames; +using static Lombiq.UtilityScripts.OrchardCore.Helpers.FormerlyScriptHelper; namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets { @@ -14,9 +15,11 @@ namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets [Cmdlet(VerbsCommon.Reset, NounNames.OrchardCoreApp)] [Alias(VerbsCommon.Reset + "-" + NounNames.OrchardCore)] [OutputType(typeof(FileInfo))] - public class ResetOrchardCoreAppCmdletCommand : PSCmdlet + public class ResetOrchardCoreAppCmdletCommand : AsyncCmdletBase { - private const string Name = VerbsCommon.Reset + "-" + NounNames.OrchardCoreApp; + private const string _cmdletName = VerbsCommon.Reset + "-" + NounNames.OrchardCoreApp; + + protected override string CmdletName => _cmdletName; [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)] public string WebProjectPath { get; set; } @@ -75,7 +78,7 @@ public class ResetOrchardCoreAppCmdletCommand : PSCmdlet [Parameter] public SwitchParameter Pause { get; set; } - protected override void ProcessRecord() + private async Task ProcessRecordAsync() { string webProjectDllPath; string siteName; @@ -109,7 +112,7 @@ protected override void ProcessRecord() // terminate them. var siteHostProcesses = Process.GetProcessesByName("iisexpress.exe") .Concat(Process.GetProcessesByName("dotnet.exe")) - .Where(process => process.StartInfo?.Arguments?.Contains("$siteName", StringComparer.OrdinalIgnoreCase) == true) + .Where(process => process.StartInfo?.Arguments?.Contains("$siteName") == true) .ToList(); if (siteHostProcesses.Any()) @@ -133,48 +136,94 @@ protected override void ProcessRecord() appData.Delete(recursive: true); } - /* - # Rebuilding the application if the "Rebuild" switch is present or the Web Project DLL is not found. - - $buildRequired = $false; - if ($Rebuild.IsPresent) - { - "Rebuild switch active!`n" - - $buildRequired = $true - } - elseif ([string]::IsNullOrEmpty($webProjectDllPath) -or -not (Test-Path $webProjectDllPath -PathType Leaf)) - { - "Web Project DLL not found, build is required!`n" - - $buildRequired = $true - } - - if ($buildRequired) - { - dotnet build "$WebProjectPath" --configuration Debug - - if ($LASTEXITCODE -ne 0) + // Rebuilding the application if the "Rebuild" switch is present or the Web Project DLL is not found. + var buildRequired = false; + if (Rebuild.IsPresent) { - pause - - exit $LASTEXITCODE + Info("Rebuild switch active!"); + buildRequired = true; } - else + else if (string.IsNullOrEmpty(webProjectDllPath) || !File.Exists(webProjectDllPath)) + { + Info("Web Project DLL not found, build is required!"); + buildRequired = true; + } + + if (buildRequired) { - $webProjectDllPath = GetWebProjectDllPath($WebProjectPath) + await DotnetAsync("build", WebProjectPath, "--configuration", "Debug"); + + // The `if ($LASTEXITCODE -ne 0)` is not needed because CliWrap does that on its own and it should + // happen everywhere anyway, not just here. - if ([string]::IsNullOrEmpty($webProjectDllPath)) + webProjectDllPath = GetWebProjectDllPath(WebProjectPath); + + if (string.IsNullOrEmpty(webProjectDllPath)) { - throw "Project was successfully built at `"$WebProjectPath`", but the compiled Web Project DLL was not found!" + throw new InvalidOperationException( + $"Project was successfully built at \"{WebProjectPath}\", but the compiled Web Project DLL was not found!"); } } - } - - "Compiled Web Project DLL found at `"$webProjectDllPath`"!`n" + + Info($"Compiled Web Project DLL found at \"{webProjectDllPath}\"!"); + + // Validating and setting up database server connection. + var SetupDatabaseConnectionString = ""; + if (ParameterSetName == ServerDB) + { + if (SuffixDatabaseNameWithFolderName.IsPresent) + { + var solutionPath = Environment.CurrentDirectory; + + while (!string.IsNullOrEmpty(solutionPath) && !Directory.GetFiles(solutionPath, "*.sln").Any()) + { + solutionPath = Path.GetDirectoryName(solutionPath); + } + + if (string.IsNullOrEmpty(solutionPath)) + { + throw new DirectoryNotFoundException( + "No solution folder was found to create the database name suffix. Put this script into a " + + "folder where there or in a parent folder there is the app's .sln file."); + } + + var solutionFolder = Path.GetFileName(solutionPath); + SetupDatabaseName = $"{SetupDatabaseName}_{solutionFolder}"; + } + + Info($"Using the following database name: \"{SetupDatabaseName}\"."); + + if (New-SqlServerDatabase -SqlServerName SetupDatabaseServerName -DatabaseName SetupDatabaseName -Force:Force.IsPresent -ErrorAction Stop -UserName SetupDatabaseSqlUser -Password SetupDatabaseSqlPassword) + { + "Database `"SetupDatabaseServerName\SetupDatabaseName`" created!" + } + else + { + if ([string]::IsNullOrEmpty(SetupDatabaseTablePrefix)) + { + throw ("Database `"SetupDatabaseServerName\SetupDatabaseName`" could not be created!") + } + else + { + "The specified database already exists! Attempting to run setup using the `"SetupDatabaseTablePrefix`" table prefix." + } + } + Security = if (-not SetupDatabaseSqlPassword) + { + "Integrated Security=True" + } + else + { + "User Id=SetupDatabaseSqlUser;Password=SetupDatabaseSqlPassword" + } + # MARS is necessary for Orchard. + SetupDatabaseConnectionString = "Server=SetupDatabaseServerName;Database=SetupDatabaseName;Security;MultipleActiveResultSets=True;" + } + + /* # Validating and setting up database server connection. $SetupDatabaseConnectionString = "" @@ -381,7 +430,5 @@ private string GetWebProjectDllPath(string WebProjectPath) ? webProjectDllPath : string.Empty; } - - private void Info(string message) => WriteInformation(new InformationRecord(message, Name)); } } \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs b/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs index e86a86c..b3776a5 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs +++ b/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs @@ -1,4 +1,5 @@ using System.IO; +using CliWrap; using Lombiq.UtilityScripts.OrchardCore.Cmdlets; namespace Lombiq.UtilityScripts.OrchardCore.Helpers @@ -10,6 +11,8 @@ public static class FormerlyScriptHelper { private static string _psScriptRoot = null; + public static string DotnetPath { get; set; } = "dotnet"; + /// /// Gets the string that behaves like the Powershell builtin $PSScriptRoot. /// @@ -26,5 +29,11 @@ public static string PSScriptRoot return _psScriptRoot; } } + + public static CommandTask DotnetAsync(params string[] arguments) => + Cli + .Wrap(DotnetPath) + .WithArguments(arguments) + .ExecuteAsync(); } } \ No newline at end of file From ebcd1dc64443991a69301947b4735c204470b79f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Sat, 7 Aug 2021 19:11:13 +0200 Subject: [PATCH 06/14] Create a common project. --- Utility-Scripts.sln | 15 ++++++ .../Cmdlets/AsyncCmdletBase.cs | 2 +- .../Helpers/FormerlyScriptHelper.cs | 13 ++--- .../Lombiq.UtilityScripts.Common.csproj | 15 ++++++ ...tializeOrchardCoreSolutionCmdletCommand.cs | 3 +- .../ResetOrchardCoreAppCmdletCommand.cs | 5 +- .../Cmdlets/TestSampleCmdletCommand.cs | 49 ------------------- .../Lombiq.UtilityScripts.OrchardCore.csproj | 7 ++- 8 files changed, 49 insertions(+), 60 deletions(-) rename src/{Lombiq.UtilityScripts.OrchardCore => Lombiq.UtilityScripts.Common}/Cmdlets/AsyncCmdletBase.cs (94%) rename src/{Lombiq.UtilityScripts.OrchardCore => Lombiq.UtilityScripts.Common}/Helpers/FormerlyScriptHelper.cs (73%) create mode 100644 src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/TestSampleCmdletCommand.cs diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln index f34e54a..782fdeb 100644 --- a/Utility-Scripts.sln +++ b/Utility-Scripts.sln @@ -7,6 +7,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EA34D28-4D2 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.OrchardCore", "src\Lombiq.UtilityScripts.OrchardCore\Lombiq.UtilityScripts.OrchardCore.csproj", "{9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Common", "src\Lombiq.UtilityScripts.Common\Lombiq.UtilityScripts.Common.csproj", "{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -32,8 +34,21 @@ Global {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x64.Build.0 = Release|Any CPU {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x86.ActiveCfg = Release|Any CPU {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x86.Build.0 = Release|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x64.ActiveCfg = Debug|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x64.Build.0 = Debug|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x86.ActiveCfg = Debug|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x86.Build.0 = Debug|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|Any CPU.Build.0 = Release|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x64.ActiveCfg = Release|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x64.Build.0 = Release|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x86.ActiveCfg = Release|Any CPU + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} + {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} EndGlobalSection EndGlobal diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs b/src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs similarity index 94% rename from src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs rename to src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs index 471c02c..e4a0c55 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/AsyncCmdletBase.cs +++ b/src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs @@ -2,7 +2,7 @@ using System.Management.Automation; using System.Threading.Tasks; -namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets +namespace Lombiq.UtilityScripts.Common.Cmdlets { public abstract class AsyncCmdletBase : PSCmdlet { diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs b/src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs similarity index 73% rename from src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs rename to src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs index b3776a5..b5edf9c 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Helpers/FormerlyScriptHelper.cs +++ b/src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs @@ -1,15 +1,16 @@ -using System.IO; +using System; +using System.IO; using CliWrap; -using Lombiq.UtilityScripts.OrchardCore.Cmdlets; +using Lombiq.UtilityScripts.Common.Cmdlets; -namespace Lombiq.UtilityScripts.OrchardCore.Helpers +namespace Lombiq.UtilityScripts.Common.Helpers { /// /// Helper to ease transition from the scripts. /// public static class FormerlyScriptHelper { - private static string _psScriptRoot = null; + private static string? _psScriptRoot = null; public static string DotnetPath { get; set; } = "dotnet"; @@ -22,8 +23,8 @@ public static string PSScriptRoot { if (_psScriptRoot == null) { - var assemblyLocation = typeof(InitializeOrchardCoreSolutionCmdletCommand).Assembly.Location; - _psScriptRoot = Path.GetDirectoryName(assemblyLocation); + var assemblyLocation = typeof(AsyncCmdletBase).Assembly.Location; + _psScriptRoot = Path.GetDirectoryName(assemblyLocation) ?? Environment.CurrentDirectory; } return _psScriptRoot; diff --git a/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj b/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj new file mode 100644 index 0000000..b1f9d57 --- /dev/null +++ b/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.1 + enable + + + + + + All + + + + diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs index cebe314..1e683e5 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs @@ -3,9 +3,10 @@ using System.IO; using System.Management.Automation; using System.Threading.Tasks; +using Lombiq.UtilityScripts.Common.Cmdlets; using Lombiq.UtilityScripts.OrchardCore.Constants; using IoPath = System.IO.Path; -using static Lombiq.UtilityScripts.OrchardCore.Helpers.FormerlyScriptHelper; +using static Lombiq.UtilityScripts.Common.Helpers.FormerlyScriptHelper; namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets { diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs index dcd62c0..9802448 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs @@ -5,9 +5,10 @@ using System.Management.Automation; using System.Threading; using System.Threading.Tasks; +using Lombiq.UtilityScripts.Common.Cmdlets; using Lombiq.UtilityScripts.OrchardCore.Constants; using static Lombiq.UtilityScripts.OrchardCore.Constants.ParameterSetNames; -using static Lombiq.UtilityScripts.OrchardCore.Helpers.FormerlyScriptHelper; +using static Lombiq.UtilityScripts.Common.Helpers.FormerlyScriptHelper; namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets { @@ -78,7 +79,7 @@ public class ResetOrchardCoreAppCmdletCommand : AsyncCmdletBase [Parameter] public SwitchParameter Pause { get; set; } - private async Task ProcessRecordAsync() + protected override async Task ProcessRecordAsync() { string webProjectDllPath; string siteName; diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/TestSampleCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/TestSampleCmdletCommand.cs deleted file mode 100644 index de54816..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/TestSampleCmdletCommand.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System.Management.Automation; - -namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets -{ - [Cmdlet(VerbsDiagnostic.Test,"SampleCmdlet")] - [OutputType(typeof(FavoriteStuff))] - public class TestSampleCmdletCommand : PSCmdlet - { - [Parameter( - Mandatory = true, - Position = 0, - ValueFromPipeline = true, - ValueFromPipelineByPropertyName = true)] - public int FavoriteNumber { get; set; } - - [Parameter( - Position = 1, - ValueFromPipelineByPropertyName = true)] - [ValidateSet("Cat", "Dog", "Horse")] - public string FavoritePet { get; set; } = "Dog"; - - // This method gets called once for each cmdlet in the pipeline when the pipeline starts executing - protected override void BeginProcessing() - { - WriteVerbose("Begin!"); - } - - // This method will be called for each input received from the pipeline to this cmdlet; if no input is received, this method is not called - protected override void ProcessRecord() - { - WriteObject(new FavoriteStuff { - FavoriteNumber = FavoriteNumber, - FavoritePet = FavoritePet - }); - } - - // This method will be called once at the end of pipeline execution; if no input is received, this method is not called - protected override void EndProcessing() - { - WriteVerbose("End!"); - } - } - - public class FavoriteStuff - { - public int FavoriteNumber { get; set; } - public string FavoritePet { get; set; } - } -} diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj b/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj index 606c8f2..8406e84 100644 --- a/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj +++ b/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj @@ -1,9 +1,10 @@ - netstandard2.0 + netstandard2.1 Lombiq.UtilityScripts.OrchardCore Lombiq.UtilityScripts.OrchardCore + enable @@ -20,4 +21,8 @@ + + + + From bd9dddb919b917aef47e5f68e613f047fd178144 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Sat, 7 Aug 2021 21:44:16 +0200 Subject: [PATCH 07/14] Added IServiceProvider to AsnycCmdletBase and SqlServerManager (cmdlet to follow). --- Utility-Scripts.sln | 15 ++ .../Cmdlets/AsyncCmdletBase.cs | 33 +++++ .../Lombiq.UtilityScripts.Common.csproj | 2 + .../Cmdlets/SqlConnectionExtensions.cs | 36 +++++ .../Lombiq.UtilityScripts.SqlServer.csproj | 17 +++ .../Services/SqlServerManager.cs | 139 ++++++++++++++++++ 6 files changed, 242 insertions(+) create mode 100644 src/Lombiq.UtilityScripts.SqlServer/Cmdlets/SqlConnectionExtensions.cs create mode 100644 src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj create mode 100644 src/Lombiq.UtilityScripts.SqlServer/Services/SqlServerManager.cs diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln index 782fdeb..bf3a508 100644 --- a/Utility-Scripts.sln +++ b/Utility-Scripts.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Orcha EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Common", "src\Lombiq.UtilityScripts.Common\Lombiq.UtilityScripts.Common.csproj", "{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.SqlServer", "src\Lombiq.UtilityScripts.SqlServer\Lombiq.UtilityScripts.SqlServer.csproj", "{79B8C1DD-ADBD-4266-B89A-D938D0614D50}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,9 +48,22 @@ Global {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x64.Build.0 = Release|Any CPU {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x86.ActiveCfg = Release|Any CPU {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Release|x86.Build.0 = Release|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|Any CPU.Build.0 = Debug|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x64.ActiveCfg = Debug|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x64.Build.0 = Debug|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x86.ActiveCfg = Debug|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Debug|x86.Build.0 = Debug|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|Any CPU.ActiveCfg = Release|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|Any CPU.Build.0 = Release|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x64.ActiveCfg = Release|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x64.Build.0 = Release|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.ActiveCfg = Release|Any CPU + {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} + {79B8C1DD-ADBD-4266-B89A-D938D0614D50} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} EndGlobalSection EndGlobal diff --git a/src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs b/src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs index e4a0c55..661a1ba 100644 --- a/src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs +++ b/src/Lombiq.UtilityScripts.Common/Cmdlets/AsyncCmdletBase.cs @@ -1,6 +1,8 @@ using System; using System.Management.Automation; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; namespace Lombiq.UtilityScripts.Common.Cmdlets { @@ -8,11 +10,38 @@ public abstract class AsyncCmdletBase : PSCmdlet { protected abstract string CmdletName { get; } + private ServiceProvider? _provider; + private IServiceProvider? _scopeProvider; + + protected IServiceProvider ServiceProvider => + _scopeProvider ?? _provider ?? throw new InvalidOperationException($"{nameof(BeginProcessing)} was not called!"); + + protected override void BeginProcessing() + { + var services = new ServiceCollection(); + services.AddLogging(options => options.AddConsole()); + services.AddSingleton(this); + services.AddSingleton(this); + + Configure(services); + _provider = services.BuildServiceProvider(); + } + protected override void ProcessRecord() { try { + if (_scopeProvider != null) + { + throw new InvalidOperationException("Overlapping scopes! This should not be possible."); + } + + using var scope = ServiceProvider.CreateScope(); + _scopeProvider = scope.ServiceProvider; + ProcessRecordAsync().Wait(); + + _scopeProvider = null; } catch (Exception exception) { @@ -20,6 +49,10 @@ protected override void ProcessRecord() } } + protected override void EndProcessing() => _provider?.Dispose(); + + protected virtual void Configure(IServiceCollection services) { } + protected abstract Task ProcessRecordAsync(); protected void Info(string message) => WriteInformation(new InformationRecord(message, CmdletName)); diff --git a/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj b/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj index b1f9d57..6946b89 100644 --- a/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj +++ b/src/Lombiq.UtilityScripts.Common/Lombiq.UtilityScripts.Common.csproj @@ -7,9 +7,11 @@ + All + diff --git a/src/Lombiq.UtilityScripts.SqlServer/Cmdlets/SqlConnectionExtensions.cs b/src/Lombiq.UtilityScripts.SqlServer/Cmdlets/SqlConnectionExtensions.cs new file mode 100644 index 0000000..e4755da --- /dev/null +++ b/src/Lombiq.UtilityScripts.SqlServer/Cmdlets/SqlConnectionExtensions.cs @@ -0,0 +1,36 @@ +using System.Collections.Generic; +using System.Data.SqlClient; + +namespace Lombiq.UtilityScripts.SqlServer.Cmdlets +{ + public static class SqlConnectionExtensions + { + public static SqlCommand GetCommand( + this SqlConnection connection, + string commandText, + IDictionary? parameters = null) + { + var command = connection.CreateCommand(); + command.CommandText = commandText; + + if (parameters != null) + { + foreach (var (name, value) in parameters) + { + command.Parameters.AddWithValue(name, value); + } + } + + return command; + } + + public static async IAsyncEnumerable YieldStringColumnAsync(this SqlCommand command, int columnId = 0) + { + await using var reader = await command.ExecuteReaderAsync(); + while (await reader.ReadAsync()) + { + yield return reader.GetString(columnId); + } + } + } +} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj b/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj new file mode 100644 index 0000000..bf2048d --- /dev/null +++ b/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj @@ -0,0 +1,17 @@ + + + + netstandard2.1 + enable + + + + + + + + + + + + diff --git a/src/Lombiq.UtilityScripts.SqlServer/Services/SqlServerManager.cs b/src/Lombiq.UtilityScripts.SqlServer/Services/SqlServerManager.cs new file mode 100644 index 0000000..01c8920 --- /dev/null +++ b/src/Lombiq.UtilityScripts.SqlServer/Services/SqlServerManager.cs @@ -0,0 +1,139 @@ +using System; +using System.Collections.Generic; +using System.Data; +using System.Data.SqlClient; +using System.Threading.Tasks; +using Lombiq.UtilityScripts.SqlServer.Cmdlets; +using Microsoft.Extensions.Logging; + +namespace Lombiq.UtilityScripts.SqlServer.Services +{ + public class SqlServerManager + { + private readonly ILogger _logger; + + public SqlServerManager(ILogger logger) + { + _logger = logger; + } + + public async Task CreateNewDatabase( + string sqlServerName, + string databaseName, + bool force = false, + string? userName = null, + string? password = null) + { + var connection = CreateNewConnection(sqlServerName, userName, password); + await connection.OpenAsync(); + + if (await TestDatabaseAsync(connection, databaseName)) + { + if (force) + { + _logger.LogWarning("Dropping database \"{0}\\{1}\"!", sqlServerName, databaseName); + await KillAllProcessesAsync(connection, databaseName); + await connection.GetCommand("DROP " + databaseName).ExecuteNonQueryAsync(); + } + else + { + _logger.LogWarning( + "A database with the name \"{0}\" already exists on the SQL Server at \"{1}\". Use the " + + "\"-Force\" switch to drop it and create a new database with that name.", + databaseName, + sqlServerName); + + return false; + } + } + + try + { + await connection.GetCommand($"CREATE DATABASE [{databaseName}];").ExecuteNonQueryAsync(); + } + catch (Exception exception) + { + throw new InvalidOperationException( + $"Could not create \"{sqlServerName}\\{databaseName}\"! ({exception.Message})", + exception); + } + + return true; + } + + public SqlConnection CreateNewConnection(string sqlServerName, string? userName = null, string? password = null) + { + var builder = new SqlConnectionStringBuilder("Server=" + sqlServerName); + + if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password)) + { + builder.Password = userName; + builder.UserID = password; + } + + return new SqlConnection(builder.ConnectionString); + } + + public async Task TestServerAsync(SqlConnection connection) + { + try + { + if (connection.State != ConnectionState.Open) + { + await connection.CloseAsync(); + await connection.OpenAsync(); + } + + var command = connection.CreateCommand(); + command.CommandText = "SELECT 1"; + return await command.ExecuteScalarAsync() is int response && response == 1; + } + catch + { + return false; + } + } + + public async Task TestDatabaseAsync(SqlConnection connection, string databaseName) + { + // If success it also ensures that the connection is open. + if (!await TestServerAsync(connection)) + { + throw new InvalidOperationException($"Could not find SQL Server for \"{nameof(connection.ConnectionString)}\"!"); + } + + await foreach (var name in connection.GetCommand("SELECT name FROM sys.databases").YieldStringColumnAsync()) + { + if (name?.Equals(databaseName, StringComparison.OrdinalIgnoreCase) == true) + { + return true; + } + } + + return false; + } + + private async Task KillAllProcessesAsync(SqlConnection connection, string databaseName) + { + if (databaseName == null) + { + throw new ArgumentNullException(nameof(databaseName)); + } + + const string columnName = "columnName"; + var commandText = connection.ServerVersion is { } serverVersion && new Version(serverVersion).Major == 8 + ? @$"SELECT DISTINCT req_spid as {columnName} + FROM master.dbo.syslockinfo + WHERE rsc_type = 2 AND rsc_dbid = db_id(@{nameof(databaseName)}) AND req_spid > 50" + : @$"SELECT DISTINCT request_session_id as {columnName} + FROM master.sys.dm_tran_locks + WHERE resource_type = 'DATABASE' AND resource_database_id = db_id(@{nameof(databaseName)})"; + + var targets = connection + .GetCommand(commandText, new Dictionary { [nameof(databaseName)] = databaseName }) + .YieldStringColumnAsync(); + + await foreach (var target in targets) await connection.GetCommand("KILL " + target).ExecuteNonQueryAsync(); + } + } +} \ No newline at end of file From ed844cdccb4daf5cfbc85a48a723a2607937ef5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Sun, 5 Sep 2021 23:01:15 +0200 Subject: [PATCH 08/14] Remvoe unnecessary stuff. --- Utility-Scripts.sln | 15 - ...tializeOrchardCoreSolutionCmdletCommand.cs | 93 ---- .../ResetOrchardCoreAppCmdletCommand.cs | 435 ------------------ .../Constants/NounNames.cs | 9 - .../Constants/ParameterSetNames.cs | 7 - .../Lombiq.UtilityScripts.OrchardCore.csproj | 28 -- .../gitignore.template | 189 -------- 7 files changed, 776 deletions(-) delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Constants/NounNames.cs delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Constants/ParameterSetNames.cs delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj delete mode 100644 src/Lombiq.UtilityScripts.OrchardCore/gitignore.template diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln index bf3a508..74feeb1 100644 --- a/Utility-Scripts.sln +++ b/Utility-Scripts.sln @@ -5,8 +5,6 @@ VisualStudioVersion = 16.0.30114.105 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.OrchardCore", "src\Lombiq.UtilityScripts.OrchardCore\Lombiq.UtilityScripts.OrchardCore.csproj", "{9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}" -EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Common", "src\Lombiq.UtilityScripts.Common\Lombiq.UtilityScripts.Common.csproj", "{CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.SqlServer", "src\Lombiq.UtilityScripts.SqlServer\Lombiq.UtilityScripts.SqlServer.csproj", "{79B8C1DD-ADBD-4266-B89A-D938D0614D50}" @@ -24,18 +22,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|Any CPU.Build.0 = Debug|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x64.ActiveCfg = Debug|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x64.Build.0 = Debug|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x86.ActiveCfg = Debug|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Debug|x86.Build.0 = Debug|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|Any CPU.ActiveCfg = Release|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|Any CPU.Build.0 = Release|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x64.ActiveCfg = Release|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x64.Build.0 = Release|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x86.ActiveCfg = Release|Any CPU - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37}.Release|x86.Build.0 = Release|Any CPU {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|Any CPU.Build.0 = Debug|Any CPU {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -62,7 +48,6 @@ Global {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution - {9A0D4EAC-EFCE-4BDA-A698-A179898C1C37} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} {79B8C1DD-ADBD-4266-B89A-D938D0614D50} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} EndGlobalSection diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs deleted file mode 100644 index 1e683e5..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/InitializeOrchardCoreSolutionCmdletCommand.cs +++ /dev/null @@ -1,93 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Management.Automation; -using System.Threading.Tasks; -using Lombiq.UtilityScripts.Common.Cmdlets; -using Lombiq.UtilityScripts.OrchardCore.Constants; -using IoPath = System.IO.Path; -using static Lombiq.UtilityScripts.Common.Helpers.FormerlyScriptHelper; - -namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets -{ - // TODO: How to turn this into help docs? Maybe this? https://docs.microsoft.com/en-us/powershell/scripting/dev-cross-plat/create-help-using-platyps?view=powershell-7.1 - - /// - /// Initializes an Orchard Core solution for a git repository. - /// - /// - /// - /// Initializes an Orchard Core solution using the latest released Orchard Core NuGet packages at the current - /// location or under the given path, and adds a suitable .gitignore file. Optionally creates an initial module - /// and/or theme, and optionally uses a given NuGet source. - /// - /// - /// - /// - /// Init-OrchardCoreSolution - /// -Name "FancyWebsite" - /// -Path "D:\Work\FancyWebsite" - /// -ModuleName "FancyWebsite.Core" - /// -ThemeName "FancyWebsite.Theme" - /// -NuGetSource "https://nuget.cloudsmith.io/orchardcore/preview/v3/index.json" - /// - /// - [Cmdlet(VerbsData.Initialize, NounNames.OrchardCoreSolution)] - [Alias(VerbsData.Initialize + "-" + NounNames.OrchardCore)] - [OutputType(typeof(FileInfo))] - public class InitializeOrchardCoreSolutionCmdletCommand : AsyncCmdletBase - { - private const string _cmdletName = VerbsData.Initialize + "-" + NounNames.OrchardCore; - protected override string CmdletName => _cmdletName; - - [Parameter(Position = 0)] - public string Path { get; set; } - - [Parameter(Mandatory = true, Position = 1)] - public string Name { get; set; } - - [Parameter(Position = 2)] - public string ModuleName { get; set; } - - [Parameter(Position = 3)] - public string ThemeName { get; set; } - - [Parameter(Position = 4)] - public string NuGetSource { get; set; } - - - protected override async Task ProcessRecordAsync() - { - if (string.IsNullOrWhiteSpace(Path)) Path = Environment.CurrentDirectory; - - var solutionFilePath = $"{Path}/{Name}.sln"; - - var installArguments = new List { "new", "-i", "OrchardCore.ProjectTemplates::1.0.0-*" }; - if (!string.IsNullOrWhiteSpace(NuGetSource)) installArguments.Add(NuGetSource); - await DotnetAsync(installArguments.ToArray()); - - await DotnetAsync("occms", "-o", $"{Path}/src/$Name.Web"); - await DotnetAsync("new", "sln", "-o", Path, "-n", Name); - - if (!string.IsNullOrWhiteSpace(ModuleName)) - { - await DotnetAsync("new", "ocmodulecms", "-n", ModuleName, "-o", $"{Path}/src/Modules/{ModuleName}"); - await DotnetAsync("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); - await DotnetAsync("sln", solutionFilePath, "add", $"{Path}/src/Modules/{ModuleName}/{ModuleName}.csproj"); - } - - if (!string.IsNullOrWhiteSpace(ThemeName)) - { - await DotnetAsync("new", "octheme", "-n", ThemeName, "-o", $"{Path}/src/Themes/{ThemeName}"); - await DotnetAsync("add", $"{Path}/src/{Name}.Web/{Name}.Web.csproj", "reference", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); - await DotnetAsync("sln", solutionFilePath, "add", $"{Path}/src/Themes/{ThemeName}/{ThemeName}.csproj"); - } - - File.Copy( - IoPath.Combine(PSScriptRoot, "gitignore.template"), - IoPath.Combine(Path, ".gitignore")); - - WriteObject(new FileInfo(solutionFilePath)); - } - } -} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs b/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs deleted file mode 100644 index 9802448..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/Cmdlets/ResetOrchardCoreAppCmdletCommand.cs +++ /dev/null @@ -1,435 +0,0 @@ -using System; -using System.Diagnostics; -using System.IO; -using System.Linq; -using System.Management.Automation; -using System.Threading; -using System.Threading.Tasks; -using Lombiq.UtilityScripts.Common.Cmdlets; -using Lombiq.UtilityScripts.OrchardCore.Constants; -using static Lombiq.UtilityScripts.OrchardCore.Constants.ParameterSetNames; -using static Lombiq.UtilityScripts.Common.Helpers.FormerlyScriptHelper; - -namespace Lombiq.UtilityScripts.OrchardCore.Cmdlets -{ - - [Cmdlet(VerbsCommon.Reset, NounNames.OrchardCoreApp)] - [Alias(VerbsCommon.Reset + "-" + NounNames.OrchardCore)] - [OutputType(typeof(FileInfo))] - public class ResetOrchardCoreAppCmdletCommand : AsyncCmdletBase - { - private const string _cmdletName = VerbsCommon.Reset + "-" + NounNames.OrchardCoreApp; - - protected override string CmdletName => _cmdletName; - - [Parameter(Mandatory = true, ValueFromPipelineByPropertyName = true, Position = 0)] - public string WebProjectPath { get; set; } - - [Parameter] - public string SetupSiteName { get; set; } = "Orchard Core"; - - [Parameter] - public string SetupTenantName { get; set; } = "Default"; - - [Parameter] - public string SetupRecipeName { get; set; } = "Blog"; - - [Parameter] - public string SetupUserName { get; set; } = "admin"; - - [Parameter] - public string SetupPassword { get; set; } = "Password1!"; - - [Parameter] - public string SetupEmail { get; set; } = "admin@localhost"; - - public int Port { get; set; } = 5000; - - [Parameter(ParameterSetName = ServerDB, Mandatory = true)] - [ValidateSet("SqlConnection")] - public string SetupDatabaseProvider { get; set; } = "Sqlite"; - - [Parameter(ParameterSetName = ServerDB)] - public string SetupDatabaseTablePrefix { get; set; } = ""; - - [Parameter(ParameterSetName = ServerDB)] - public string SetupDatabaseServerName { get; set; } = "-"; - - [Parameter(ParameterSetName = ServerDB)] - public string SetupDatabaseName { get; set; } = "OrchardCore"; - - [Parameter(ParameterSetName = ServerDB)] - public string SetupDatabaseSqlUser { get; set; } = "sa"; - - [Parameter(ParameterSetName = ServerDB)] - public string SetupDatabaseSqlPassword { get; set; } = null; - - [Parameter(ParameterSetName = ServerDB)] - public SwitchParameter Force { get; set; } - - [Parameter(ParameterSetName = ServerDB)] - public SwitchParameter SuffixDatabaseNameWithFolderName { get; set; } - - [Parameter] - public SwitchParameter Rebuild { get; set; } - - [Parameter] - public SwitchParameter KeepAlive { get; set; } - - [Parameter] - public SwitchParameter Pause { get; set; } - - protected override async Task ProcessRecordAsync() - { - string webProjectDllPath; - string siteName; - - // Checking if the Web Project Path is valid and extracting the name of the Web Project. - if (File.Exists(WebProjectPath)) - { - if (!WebProjectPath.EndsWith(".DLL", StringComparison.OrdinalIgnoreCase)) - { - throw new InvalidOperationException( - $"The {nameof(WebProjectPath)} must be a dll file or a directory path."); - } - - webProjectDllPath = WebProjectPath; - var fileInfo = new FileInfo(WebProjectPath); - siteName = fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf('.')); - WebProjectPath = Path.GetDirectoryName(WebProjectPath); - } - else if (!Directory.Exists(WebProjectPath)) - { - throw new InvalidOperationException( - $"The {nameof(WebProjectPath)} is not found or not accessible! ({WebProjectPath})"); - } - else - { - webProjectDllPath = GetWebProjectDllPath(WebProjectPath); - siteName = Path.GetFileName(WebProjectPath); - } - - // Trying to find IIS Express and .NET host processes that run a Web Project with a matching name and - // terminate them. - var siteHostProcesses = Process.GetProcessesByName("iisexpress.exe") - .Concat(Process.GetProcessesByName("dotnet.exe")) - .Where(process => process.StartInfo?.Arguments?.Contains("$siteName") == true) - .ToList(); - - if (siteHostProcesses.Any()) - { - foreach (var process in siteHostProcesses) - { - var commandLine = $"{process.StartInfo.FileName} {process.StartInfo.Arguments}"; - Info($"Terminating application host process running \"{commandLine}\"."); - - process.Kill(); - } - - Thread.Sleep(1000); - } - - //Delete App_Data if exists. - var appData = new DirectoryInfo($"{WebProjectPath}\\App_Data"); - if (appData.Exists) - { - Info($"Deleting App_Data folder found in \"{appData.FullName}\"."); - appData.Delete(recursive: true); - } - - // Rebuilding the application if the "Rebuild" switch is present or the Web Project DLL is not found. - var buildRequired = false; - if (Rebuild.IsPresent) - { - Info("Rebuild switch active!"); - buildRequired = true; - } - else if (string.IsNullOrEmpty(webProjectDllPath) || !File.Exists(webProjectDllPath)) - { - Info("Web Project DLL not found, build is required!"); - buildRequired = true; - } - - if (buildRequired) - { - await DotnetAsync("build", WebProjectPath, "--configuration", "Debug"); - - // The `if ($LASTEXITCODE -ne 0)` is not needed because CliWrap does that on its own and it should - // happen everywhere anyway, not just here. - - webProjectDllPath = GetWebProjectDllPath(WebProjectPath); - - if (string.IsNullOrEmpty(webProjectDllPath)) - { - throw new InvalidOperationException( - $"Project was successfully built at \"{WebProjectPath}\", but the compiled Web Project DLL was not found!"); - } - } - - Info($"Compiled Web Project DLL found at \"{webProjectDllPath}\"!"); - - // Validating and setting up database server connection. - - var SetupDatabaseConnectionString = ""; - if (ParameterSetName == ServerDB) - { - if (SuffixDatabaseNameWithFolderName.IsPresent) - { - var solutionPath = Environment.CurrentDirectory; - - while (!string.IsNullOrEmpty(solutionPath) && !Directory.GetFiles(solutionPath, "*.sln").Any()) - { - solutionPath = Path.GetDirectoryName(solutionPath); - } - - if (string.IsNullOrEmpty(solutionPath)) - { - throw new DirectoryNotFoundException( - "No solution folder was found to create the database name suffix. Put this script into a " + - "folder where there or in a parent folder there is the app's .sln file."); - } - - var solutionFolder = Path.GetFileName(solutionPath); - SetupDatabaseName = $"{SetupDatabaseName}_{solutionFolder}"; - } - - Info($"Using the following database name: \"{SetupDatabaseName}\"."); - - if (New-SqlServerDatabase -SqlServerName SetupDatabaseServerName -DatabaseName SetupDatabaseName -Force:Force.IsPresent -ErrorAction Stop -UserName SetupDatabaseSqlUser -Password SetupDatabaseSqlPassword) - { - "Database `"SetupDatabaseServerName\SetupDatabaseName`" created!" - } - else - { - if ([string]::IsNullOrEmpty(SetupDatabaseTablePrefix)) - { - throw ("Database `"SetupDatabaseServerName\SetupDatabaseName`" could not be created!") - } - else - { - "The specified database already exists! Attempting to run setup using the `"SetupDatabaseTablePrefix`" table prefix." - } - } - - Security = if (-not SetupDatabaseSqlPassword) - { - "Integrated Security=True" - } - else - { - "User Id=SetupDatabaseSqlUser;Password=SetupDatabaseSqlPassword" - } - - # MARS is necessary for Orchard. - SetupDatabaseConnectionString = "Server=SetupDatabaseServerName;Database=SetupDatabaseName;Security;MultipleActiveResultSets=True;" - } - - /* - # Validating and setting up database server connection. - - $SetupDatabaseConnectionString = "" - if ($PSCmdlet.ParameterSetName -eq "ServerDB") - { - if ($SuffixDatabaseNameWithFolderName.IsPresent) - { - $solutionPath = (Get-Location).Path - - while (-not [string]::IsNullOrEmpty($solutionPath) -and -not (Test-Path (Join-Path $solutionPath "*.sln"))) - { - $solutionPath = Split-Path $solutionPath -Parent; - } - - if ([string]::IsNullOrEmpty($solutionPath)) - { - throw ("No solution folder was found to create the database name suffix. Put this script into a folder where there or in a parent folder there is the app's .sln file.") - } - - $solutionFolder = Split-Path $solutionPath -Leaf - - $SetupDatabaseName = $SetupDatabaseName + "_" + $solutionFolder - } - - "Using the following database name: `"$SetupDatabaseName`"." - - if (New-SqlServerDatabase -SqlServerName $SetupDatabaseServerName -DatabaseName $SetupDatabaseName -Force:$Force.IsPresent -ErrorAction Stop -UserName $SetupDatabaseSqlUser -Password $SetupDatabaseSqlPassword) - { - "Database `"$SetupDatabaseServerName\$SetupDatabaseName`" created!" - } - else - { - if ([string]::IsNullOrEmpty($SetupDatabaseTablePrefix)) - { - throw ("Database `"$SetupDatabaseServerName\$SetupDatabaseName`" could not be created!") - } - else - { - "The specified database already exists! Attempting to run setup using the `"$SetupDatabaseTablePrefix`" table prefix." - } - } - - $Security = if (-not $SetupDatabaseSqlPassword) - { - "Integrated Security=True" - } - else - { - "User Id=$SetupDatabaseSqlUser;Password=$SetupDatabaseSqlPassword" - } - - # MARS is necessary for Orchard. - $SetupDatabaseConnectionString = "Server=$SetupDatabaseServerName;Database=$SetupDatabaseName;$Security;MultipleActiveResultSets=True;" - } - - - - # Try to find the Launch Settings file to get the launch URL of the application. - # If not found (or the URL is not found in the settings), and the $Port parameter is set to <=0 then using a random one on localhost instead. - - $launchSettingsFilePath = $("$WebProjectPath\Properties\launchSettings.json") - $environmentSetting = "Development" - - if ($Port -le 0) - { - $Port = Get-Random -Minimum 2000 -Maximum 64000 - } - - $applicationUrl = "http://localhost:$Port" - - if (Test-Path $launchSettingsFilePath -PathType Leaf) - { - $launchSettings = Get-Content $launchSettingsFilePath | ConvertFrom-Json - - $applicationUrlSetting = $launchSettings.profiles."$SiteName".applicationUrl - - if (-not [string]::IsNullOrEmpty($applicationUrlSetting)) - { - $applicationUrlsFromSetting = $applicationUrlSetting -split ";" - - $applicationUrlFromSetting = $applicationUrlsFromSetting | Where-Object { $_.StartsWith("http://") } - - if (-not [string]::IsNullOrEmpty($applicationUrlFromSetting)) - { - $applicationUrl = $applicationUrlFromSetting.Trim() - } - } - - $environmentSetting = $launchSettings.profiles."$SiteName".environmentVariables.ASPNETCORE_ENVIRONMENT - - if ([string]::IsNullOrEmpty($environmentSetting)) - { - $environmentSetting = "Development" - } - } - - - - # Launching the .NET application host process. - - $webProjectDllFile = Get-Item -Path $webProjectDllPath - - "Starting .NET application host at `"$applicationUrl`"!`n" - - $applicationProcess = Start-Process ` - -WorkingDirectory $WebProjectPath ` - dotnet ` - -ArgumentList "$($webProjectDllFile.FullName) --urls $applicationUrl --environment $environmentSetting --webroot wwwroot --AuthorizeOrchardApiRequests true" ` - -PassThru - - - - # Confirming that the host process has started the application successfully. - - Start-Sleep 2 - - $applicationRunning = $false - do - { - Start-Sleep 1 - - if ($applicationProcess.HasExited) - { - throw "Application host process exited with exit code $($applicationProcess.ExitCode)!`nCheck if another application host process (IIS Express or dotnet) is running under a different user account using the same port and terminate it!" - } - - $setupScreenResponse = Invoke-WebRequest -Uri $applicationUrl -UseBasicParsing -ErrorAction Stop - - if ($setupScreenResponse.StatusCode -ne 200) - { - throw "Application host process started, but the setup screen returned status code $($setupScreenResponse.StatusCode)!" - } - - $applicationRunning = $true - } - until ($applicationRunning) - - - - # Running setup. - - "Application started, attempting to run setup!`n" - - $tenantSetupSettings = @{ - SiteName = $SetupSiteName - DatabaseProvider = $SetupDatabaseProvider - TablePrefix = $SetupDatabaseTablePrefix - ConnectionString = $SetupDatabaseConnectionString - RecipeName = $SetupRecipeName - UserName = $SetupUserName - Password = $SetupPassword - Email = $SetupEmail - Name = $SetupTenantName - } - - $setupRequest = Invoke-WebRequest -Method Post -Uri "$applicationUrl/api/tenants/setup" -Body (ConvertTo-Json($tenantSetupSettings)) -ContentType "application/json" -UseBasicParsing - - if ($setupRequest.StatusCode -ne 200) - { - Stop-Process $applicationProcess - - throw "Setup failed with status code $($setupRequest.StatusCode)!" - } - - "Setup successful!`n" - - - - # Terminating the .NET application host process if Keep Alive is not requested. - - if (-not $KeepAlive.IsPresent) - { - "Keep Alive not requested, shutting down application host process!" - - Stop-Process $applicationProcess - } - - - - if ($Pause.IsPresent) - { - pause - } - - exit 0 - } - */ - } - - /// - /// Looking for the Web Project DLL and selecting the latest ASP.NET Core variant if more than one found. - /// - private string GetWebProjectDllPath(string WebProjectPath) - { - var siteName = Path.GetFileName(WebProjectPath); - var netCoreAppDirectoryPath = Directory - .GetDirectories(Path.Combine(WebProjectPath, "bin", "Debug")) - .FirstOrDefault(); - - if (netCoreAppDirectoryPath == null) return string.Empty; - var webProjectDllPath = Path.Combine(netCoreAppDirectoryPath, siteName + ".dll"); - - return File.Exists(webProjectDllPath) - ? webProjectDllPath - : string.Empty; - } - } -} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Constants/NounNames.cs b/src/Lombiq.UtilityScripts.OrchardCore/Constants/NounNames.cs deleted file mode 100644 index 29edabe..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/Constants/NounNames.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace Lombiq.UtilityScripts.OrchardCore.Constants -{ - public static class NounNames - { - public const string OrchardCore = nameof(OrchardCore); - public const string OrchardCoreSolution = nameof(OrchardCoreSolution); - public const string OrchardCoreApp = nameof(OrchardCoreApp); - } -} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Constants/ParameterSetNames.cs b/src/Lombiq.UtilityScripts.OrchardCore/Constants/ParameterSetNames.cs deleted file mode 100644 index ad9bd5a..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/Constants/ParameterSetNames.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace Lombiq.UtilityScripts.OrchardCore.Constants -{ - public class ParameterSetNames - { - public const string ServerDB = nameof(ServerDB); - } -} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj b/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj deleted file mode 100644 index 8406e84..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/Lombiq.UtilityScripts.OrchardCore.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - netstandard2.1 - Lombiq.UtilityScripts.OrchardCore - Lombiq.UtilityScripts.OrchardCore - enable - - - - - - All - - - - - - - PreserveNewest - - - - - - - - diff --git a/src/Lombiq.UtilityScripts.OrchardCore/gitignore.template b/src/Lombiq.UtilityScripts.OrchardCore/gitignore.template deleted file mode 100644 index 2305c85..0000000 --- a/src/Lombiq.UtilityScripts.OrchardCore/gitignore.template +++ /dev/null @@ -1,189 +0,0 @@ -## Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. - -# User-specific files -*.suo -*.user -*.sln.docstates -*.sln.ide/ - -# Build results - -[Dd]ebug/ -[Rr]elease/ -x64/ -build/ -app.publish/ -[Bb]in/ -[Oo]bj/ - -# Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets -!packages/*/build/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -*_i.c -*_p.c -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.log -*.scc -project.lock.json - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile - -# Visual Studio profiler -*.psess -*.vsp -*.vspx - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# NCrunch -*.ncrunch* -.*crunch*.local.xml - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.Publish.xml -*.pubxml - -# NuGet Packages Directory -packages/ - -# Windows Azure Build Output -csx -*.build.csdef - -# Windows Store app package directory -AppPackages/ - -# Others -*.Cache -!OrchardCore.Environment.Cache -ClientBin/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.[Pp]ublish.xml -*.pfx -*.publishsettings - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file to a newer -# Visual Studio version. Backup files are not needed, because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm - -# SQL Server files -App_Data/*.mdf -App_Data/*.ldf - - -## Windows and MAC detritus - -# Windows image file caches -Thumbs.db -ehthumbs.db - -# Folder config file -Desktop.ini - -# Recycle Bin used on file shares -$RECYCLE.BIN/ - -# Mac -.DS_Store - - -## ASP.NET Core and Orchard Core specifics - -App_Data/ -*.user -*.patch -*.hg -build/ -/buildazure -/buildtasks -/artifacts -site/ -*.sln.cache -log.xml -profiling/ -*.orig -.vs/ -#.vscode/ -.build/ -.testPublish/ - -nuget.exe -.nuget/ - -# Enable all /lib artifacts -!lib/*/*.* - -# Exclude node modules -node_modules/ - -# Exclude wwwroot and add exceptions -**/wwwroot/* -!**/wwwroot/favicon.ico -!**/wwwroot/.placeholder - -src/*.Web/Localization From 11026c3c49ffe2744e6322a559ee5317be1bb5cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Sun, 5 Sep 2021 23:57:56 +0200 Subject: [PATCH 09/14] Added Get-ProcessByArgument. --- Utility-Scripts.sln | 15 +++++ .../Lombiq.UtilityScripts.SqlServer.csproj | 1 - .../GetProcessByArgumentCmdletCommand.cs | 58 +++++++++++++++++++ .../Lombiq.UtilityScripts.Utilities.csproj | 15 +++++ 4 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs create mode 100644 src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln index 74feeb1..42b5ff1 100644 --- a/Utility-Scripts.sln +++ b/Utility-Scripts.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Commo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.SqlServer", "src\Lombiq.UtilityScripts.SqlServer\Lombiq.UtilityScripts.SqlServer.csproj", "{79B8C1DD-ADBD-4266-B89A-D938D0614D50}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Utilities", "src\Lombiq.UtilityScripts.Utilities\Lombiq.UtilityScripts.Utilities.csproj", "{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,9 +48,22 @@ Global {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x64.Build.0 = Release|Any CPU {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.ActiveCfg = Release|Any CPU {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.Build.0 = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x64.ActiveCfg = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x64.Build.0 = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x86.ActiveCfg = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x86.Build.0 = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|Any CPU.Build.0 = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x64.ActiveCfg = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x64.Build.0 = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x86.ActiveCfg = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} {79B8C1DD-ADBD-4266-B89A-D938D0614D50} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} EndGlobalSection EndGlobal diff --git a/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj b/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj index bf2048d..3b2d659 100644 --- a/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj +++ b/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj @@ -10,7 +10,6 @@ - diff --git a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs new file mode 100644 index 0000000..fccc977 --- /dev/null +++ b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs @@ -0,0 +1,58 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Management; +using System.Management.Automation; +using System.Runtime.InteropServices; + +namespace Lombiq.UtilityScripts.Utilities.Cmdlets +{ + [Cmdlet(VerbsCommon.Get, "ProcessByArgument")] + [OutputType(typeof(ProcessStartInfo))] + public class GetProcessByArgumentCmdletCommand : Cmdlet + { + [Parameter(Mandatory = true, Position = 0)] + public string Argument { get; set; } + + [Parameter(Mandatory = false, Position = 1)] + public string ProcessName { get; set; } + + protected override void ProcessRecord() + { + var infos = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + ? ProcessLinux() + : ProcessWindows(); + + foreach (var info in infos) WriteObject(info); + } + + private IEnumerable ProcessWindows() + { + var query = + $"SELECT CommandLine FROM Win32_Process " + + $"WHERE (Name = '{ProcessName}.exe') and CommandLine like '%{Argument}%'"; + + var list = new List(); + using (var searcher = new ManagementObjectSearcher(query)) + { + foreach (var result in searcher.Get()) + { + var processIdString = result["ProcessId"]?.ToString(); + var processStartInfo = int.TryParse(processIdString, out var processId) + ? Process.GetProcessById(processId)?.StartInfo + : null; + + if (processStartInfo == null) continue; + processStartInfo.Arguments = result["CommandLine"]?.ToString() ?? string.Empty; + + list.Add(processStartInfo); + } + } + + return list; + } + + private IEnumerable ProcessLinux() => + throw new NotSupportedException("Linux support is coming soon. See GitHub issue here: TODO"); + } +} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj b/src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj new file mode 100644 index 0000000..21a8d81 --- /dev/null +++ b/src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + Lombiq.UtilityScripts.Utilities + + + + + All + + + + + From 86ae4e2280ce37208697ad8be17c34e1d81bef2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Sun, 5 Sep 2021 23:57:56 +0200 Subject: [PATCH 10/14] Added Get-ProcessByArgument. --- Utility-Scripts.sln | 15 +++++ .../Lombiq.UtilityScripts.SqlServer.csproj | 1 - .../GetProcessByArgumentCmdletCommand.cs | 65 +++++++++++++++++++ .../Lombiq.UtilityScripts.Utilities.csproj | 15 +++++ 4 files changed, 95 insertions(+), 1 deletion(-) create mode 100644 src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs create mode 100644 src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj diff --git a/Utility-Scripts.sln b/Utility-Scripts.sln index 74feeb1..42b5ff1 100644 --- a/Utility-Scripts.sln +++ b/Utility-Scripts.sln @@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Commo EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.SqlServer", "src\Lombiq.UtilityScripts.SqlServer\Lombiq.UtilityScripts.SqlServer.csproj", "{79B8C1DD-ADBD-4266-B89A-D938D0614D50}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lombiq.UtilityScripts.Utilities", "src\Lombiq.UtilityScripts.Utilities\Lombiq.UtilityScripts.Utilities.csproj", "{E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -46,9 +48,22 @@ Global {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x64.Build.0 = Release|Any CPU {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.ActiveCfg = Release|Any CPU {79B8C1DD-ADBD-4266-B89A-D938D0614D50}.Release|x86.Build.0 = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x64.ActiveCfg = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x64.Build.0 = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x86.ActiveCfg = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Debug|x86.Build.0 = Debug|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|Any CPU.Build.0 = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x64.ActiveCfg = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x64.Build.0 = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x86.ActiveCfg = Release|Any CPU + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {CA3CF7A3-71B4-442E-9CF7-3982F4CE9490} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} {79B8C1DD-ADBD-4266-B89A-D938D0614D50} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} + {E39E4A3D-81FE-45CE-9A10-28DD5FB3B615} = {8EA34D28-4D2E-4E4E-BDE7-AC8E8C10AD18} EndGlobalSection EndGlobal diff --git a/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj b/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj index bf2048d..3b2d659 100644 --- a/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj +++ b/src/Lombiq.UtilityScripts.SqlServer/Lombiq.UtilityScripts.SqlServer.csproj @@ -10,7 +10,6 @@ - diff --git a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs new file mode 100644 index 0000000..6233688 --- /dev/null +++ b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Management; +using System.Management.Automation; +using System.Runtime.InteropServices; + +namespace Lombiq.UtilityScripts.Utilities.Cmdlets +{ + [Cmdlet(VerbsCommon.Get, "ProcessByArgument")] + [OutputType(typeof(Process))] + public class GetProcessByArgumentCmdletCommand : Cmdlet + { + [Parameter(Mandatory = true, Position = 0)] + public string Argument { get; set; } + + [Parameter(Mandatory = false, Position = 1)] + public string ProcessName { get; set; } + + protected override void ProcessRecord() + { + try + { + var infos = RuntimeInformation.IsOSPlatform(OSPlatform.Linux) + ? ProcessLinux() + : ProcessWindows(); + + foreach (var info in infos) WriteObject(info); + } + catch (Exception ex) + { + Console.WriteLine(ex); + } + } + + private IEnumerable ProcessWindows() + { + var nameWhere = string.IsNullOrWhiteSpace(ProcessName) ? string.Empty : $"(Name = '{ProcessName}.exe') and"; + var query = + $"SELECT ProcessId, Name, CommandLine FROM Win32_Process " + + $"WHERE {nameWhere} CommandLine like '%{Argument}%'"; + + var list = new List(); + using (var searcher = new ManagementObjectSearcher(query)) + { + foreach (var result in searcher.Get()) + { + var processIdString = result["ProcessId"]?.ToString(); + var process = int.TryParse(processIdString, out var processId) + ? Process.GetProcessById(processId) + : null; + + if (process == null) continue; + + list.Add(process); + } + } + + return list; + } + + private IEnumerable ProcessLinux() => + throw new NotSupportedException("Linux support is coming soon. See GitHub issue here: TODO"); + } +} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj b/src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj new file mode 100644 index 0000000..21a8d81 --- /dev/null +++ b/src/Lombiq.UtilityScripts.Utilities/Lombiq.UtilityScripts.Utilities.csproj @@ -0,0 +1,15 @@ + + + + netstandard2.0 + Lombiq.UtilityScripts.Utilities + + + + + All + + + + + From f2e67a19e21b7c78ef0fd32aefd541bccdae1abe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Mon, 6 Sep 2021 00:39:43 +0200 Subject: [PATCH 11/14] Get rid of some WMI stuff in the Reset-OrchardCoreApp.psm1. --- AddPathToPSModulePath.ps1 | 1 + .../Reset-OrchardCoreApp.psm1 | 16 ++-------------- .../Cmdlets/GetProcessByArgumentCmdletCommand.cs | 4 ++-- 3 files changed, 5 insertions(+), 16 deletions(-) diff --git a/AddPathToPSModulePath.ps1 b/AddPathToPSModulePath.ps1 index a6fbc02..7bc9155 100644 --- a/AddPathToPSModulePath.ps1 +++ b/AddPathToPSModulePath.ps1 @@ -22,6 +22,7 @@ $paths = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine").Split( if(!$paths.Contains($Path)) { [System.Environment]::SetEnvironmentVariable("PSModulePath", [string]::Join(";", $paths + $Path), "Machine") + [System.Environment]::SetEnvironmentVariable("LOMBIQ_UTILITY_SCRIPTS_PATH", $pwd.Path, "Machine") Write-Information "The path `"$Path`" was successfully added to the PSModulePath environment variable." } else diff --git a/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 b/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 index 773b7e2..391d97a 100644 --- a/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 +++ b/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 @@ -82,20 +82,8 @@ function Reset-OrchardCoreApp # Trying to find IIS Express and .NET host processes that run a Web Project with a matching name and terminate them. - $siteHostProcessFilter = "(Name = 'iisexpress.exe' or Name = 'dotnet.exe') and CommandLine like '%$siteName%'" - $siteHostProcesses = Get-WmiObject Win32_Process -Filter $siteHostProcessFilter - - if ($siteHostProcesses -ne $null -or $siteHostProcesses.Count -gt 0) - { - foreach ($siteHostProcess in $siteHostProcesses) - { - "Terminating application host process running `"$($siteHostProcess.CommandLine)`"!`n" - - $siteHostProcess.Terminate() | Out-Null - } - - Start-Sleep 1 - } + Import-Module "$env:LOMBIQ_UTILITY_SCRIPTS_PATH\src\Lombiq.UtilityScripts.Utilities\bin\Debug\netstandard2.0\Lombiq.UtilityScripts.Utilities.dll" + Get-ProcessByArgument $siteName | Stop-Process diff --git a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs index 6233688..b92476c 100644 --- a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs @@ -35,10 +35,10 @@ protected override void ProcessRecord() private IEnumerable ProcessWindows() { - var nameWhere = string.IsNullOrWhiteSpace(ProcessName) ? string.Empty : $"(Name = '{ProcessName}.exe') and"; + var nameWhere = string.IsNullOrWhiteSpace(ProcessName) ? string.Empty : $"Name LIKE '{ProcessName}' AND"; var query = $"SELECT ProcessId, Name, CommandLine FROM Win32_Process " + - $"WHERE {nameWhere} CommandLine like '%{Argument}%'"; + $"WHERE {nameWhere} CommandLine LIKE '%{Argument}%'"; var list = new List(); using (var searcher = new ManagementObjectSearcher(query)) From 3cf84982af268b69587ab081cd96e983f8f3a684 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Mon, 6 Sep 2021 01:50:09 +0200 Subject: [PATCH 12/14] Restore termination notification. --- .../Reset-OrchardCoreApp.psm1 | 12 +++++++++++- .../GetProcessByArgumentCmdletCommand.cs | 17 +++++++++++------ .../Models/ExternalProcessWithArguments.cs | 10 ++++++++++ 3 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 src/Lombiq.UtilityScripts.Utilities/Models/ExternalProcessWithArguments.cs diff --git a/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 b/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 index 391d97a..5297d22 100644 --- a/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 +++ b/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 @@ -83,9 +83,19 @@ function Reset-OrchardCoreApp # Trying to find IIS Express and .NET host processes that run a Web Project with a matching name and terminate them. Import-Module "$env:LOMBIQ_UTILITY_SCRIPTS_PATH\src\Lombiq.UtilityScripts.Utilities\bin\Debug\netstandard2.0\Lombiq.UtilityScripts.Utilities.dll" - Get-ProcessByArgument $siteName | Stop-Process + $siteHostProcesses = Get-ProcessByArgument $siteName + if ($siteHostProcesses.Count -gt 0) + { + foreach ($siteHostProcess in $siteHostProcesses) + { + "Terminating application host process running `"$($siteHostProcess.CommandLine)`"!`n" + + $siteHostProcess | Stop-Process + } + Start-Sleep 1 + } # Delete App_Data if exists. diff --git a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs index b92476c..28e346a 100644 --- a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs @@ -4,11 +4,12 @@ using System.Management; using System.Management.Automation; using System.Runtime.InteropServices; +using Lombiq.UtilityScripts.Utilities.Models; namespace Lombiq.UtilityScripts.Utilities.Cmdlets { [Cmdlet(VerbsCommon.Get, "ProcessByArgument")] - [OutputType(typeof(Process))] + [OutputType(typeof(ExternalProcessWithArguments))] public class GetProcessByArgumentCmdletCommand : Cmdlet { [Parameter(Mandatory = true, Position = 0)] @@ -33,14 +34,14 @@ protected override void ProcessRecord() } } - private IEnumerable ProcessWindows() + private IEnumerable ProcessWindows() { var nameWhere = string.IsNullOrWhiteSpace(ProcessName) ? string.Empty : $"Name LIKE '{ProcessName}' AND"; var query = - $"SELECT ProcessId, Name, CommandLine FROM Win32_Process " + + $"SELECT ProcessId, CommandLine FROM Win32_Process " + $"WHERE {nameWhere} CommandLine LIKE '%{Argument}%'"; - var list = new List(); + var list = new List(); using (var searcher = new ManagementObjectSearcher(query)) { foreach (var result in searcher.Get()) @@ -52,14 +53,18 @@ private IEnumerable ProcessWindows() if (process == null) continue; - list.Add(process); + list.Add(new ExternalProcessWithArguments + { + Process = process, + CommandLine = result["CommandLine"]?.ToString() ?? string.Empty + }); } } return list; } - private IEnumerable ProcessLinux() => + private IEnumerable ProcessLinux() => throw new NotSupportedException("Linux support is coming soon. See GitHub issue here: TODO"); } } \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.Utilities/Models/ExternalProcessWithArguments.cs b/src/Lombiq.UtilityScripts.Utilities/Models/ExternalProcessWithArguments.cs new file mode 100644 index 0000000..ddf404d --- /dev/null +++ b/src/Lombiq.UtilityScripts.Utilities/Models/ExternalProcessWithArguments.cs @@ -0,0 +1,10 @@ +using System.Diagnostics; + +namespace Lombiq.UtilityScripts.Utilities.Models +{ + public class ExternalProcessWithArguments + { + public Process Process { get; set; } + public string CommandLine { get; set; } + } +} \ No newline at end of file From 4469af9a033ed80943520afe1f9d2ddbcdce37cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Mon, 6 Sep 2021 18:31:05 +0200 Subject: [PATCH 13/14] Add help and docs. --- .../Helpers/FormerlyScriptHelper.cs | 40 ------------------ .../GetProcessByArgumentCmdletCommand.cs | 42 +++++++++++++++---- 2 files changed, 33 insertions(+), 49 deletions(-) delete mode 100644 src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs diff --git a/src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs b/src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs deleted file mode 100644 index b5edf9c..0000000 --- a/src/Lombiq.UtilityScripts.Common/Helpers/FormerlyScriptHelper.cs +++ /dev/null @@ -1,40 +0,0 @@ -using System; -using System.IO; -using CliWrap; -using Lombiq.UtilityScripts.Common.Cmdlets; - -namespace Lombiq.UtilityScripts.Common.Helpers -{ - /// - /// Helper to ease transition from the scripts. - /// - public static class FormerlyScriptHelper - { - private static string? _psScriptRoot = null; - - public static string DotnetPath { get; set; } = "dotnet"; - - /// - /// Gets the string that behaves like the Powershell builtin $PSScriptRoot. - /// - public static string PSScriptRoot - { - get - { - if (_psScriptRoot == null) - { - var assemblyLocation = typeof(AsyncCmdletBase).Assembly.Location; - _psScriptRoot = Path.GetDirectoryName(assemblyLocation) ?? Environment.CurrentDirectory; - } - - return _psScriptRoot; - } - } - - public static CommandTask DotnetAsync(params string[] arguments) => - Cli - .Wrap(DotnetPath) - .WithArguments(arguments) - .ExecuteAsync(); - } -} \ No newline at end of file diff --git a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs index 28e346a..9efeb6a 100644 --- a/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs +++ b/src/Lombiq.UtilityScripts.Utilities/Cmdlets/GetProcessByArgumentCmdletCommand.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.IO; using System.Management; using System.Management.Automation; using System.Runtime.InteropServices; @@ -8,15 +9,19 @@ namespace Lombiq.UtilityScripts.Utilities.Cmdlets { + /// + /// Returns a collection of & command line argument pairs where it matches the search text + /// in the parameter (case-insensitive). + /// [Cmdlet(VerbsCommon.Get, "ProcessByArgument")] [OutputType(typeof(ExternalProcessWithArguments))] public class GetProcessByArgumentCmdletCommand : Cmdlet { - [Parameter(Mandatory = true, Position = 0)] + [Parameter( + Mandatory = true, + Position = 0, + HelpMessage = "The text to be searched (case-insensitive) in the process command line arguments.")] public string Argument { get; set; } - - [Parameter(Mandatory = false, Position = 1)] - public string ProcessName { get; set; } protected override void ProcessRecord() { @@ -33,13 +38,12 @@ protected override void ProcessRecord() Console.WriteLine(ex); } } - + private IEnumerable ProcessWindows() { - var nameWhere = string.IsNullOrWhiteSpace(ProcessName) ? string.Empty : $"Name LIKE '{ProcessName}' AND"; var query = $"SELECT ProcessId, CommandLine FROM Win32_Process " + - $"WHERE {nameWhere} CommandLine LIKE '%{Argument}%'"; + $"WHERE CommandLine LIKE '%{Argument}%'"; var list = new List(); using (var searcher = new ManagementObjectSearcher(query)) @@ -64,7 +68,27 @@ private IEnumerable ProcessWindows() return list; } - private IEnumerable ProcessLinux() => - throw new NotSupportedException("Linux support is coming soon. See GitHub issue here: TODO"); + private IEnumerable ProcessLinux() + { + var argument = Argument.ToUpperInvariant(); + var list = new List(); + + foreach (var process in Process.GetProcesses()) + { + if (!File.Exists($"/proc/{process.Id}/cmdline")) continue; + var commandLine = File.ReadAllText($"/proc/{process.Id}/cmdline") ?? string.Empty; + + if (commandLine.ToUpperInvariant().Contains(argument)) + { + list.Add(new ExternalProcessWithArguments + { + Process = process, + CommandLine = commandLine, + }); + } + } + + return list; + } } } \ No newline at end of file From aa2948e429733f4a6542ac942cd4010582efadb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C3=A1vid=20El-Saig?= Date: Tue, 7 Sep 2021 04:53:28 +0200 Subject: [PATCH 14/14] Bug fix. --- OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 b/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 index 5297d22..13167d6 100644 --- a/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 +++ b/OrchardCore/Reset-OrchardCoreApp/Reset-OrchardCoreApp.psm1 @@ -91,7 +91,7 @@ function Reset-OrchardCoreApp { "Terminating application host process running `"$($siteHostProcess.CommandLine)`"!`n" - $siteHostProcess | Stop-Process + $siteHostProcess.Process | Stop-Process } Start-Sleep 1