Skip to content

Commit 377d18b

Browse files
committed
Invoke-Pog: WIP port to C#
1 parent f4320e9 commit 377d18b

File tree

4 files changed

+123
-74
lines changed

4 files changed

+123
-74
lines changed

app/Pog/Pog.psd1

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
AliasesToExport = @('pog')
1414

1515
CmdletsToExport = @(
16+
'Invoke-Pog'
1617
'Import-Pog'
1718
'Install-Pog'
1819
'Enable-Pog'
@@ -32,8 +33,6 @@
3233
)
3334

3435
FunctionsToExport = @(
35-
'Invoke-Pog'
36-
3736
'Update-PogManifest'
3837
'New-PogPackage'
3938
'New-PogImportedPackage'

app/Pog/Pog.psm1

Lines changed: 2 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ using module .\lib\Utils.psm1
33
. $PSScriptRoot\lib\header.ps1
44

55
# re-export binary cmdlets from Pog.dll
6-
Export-ModuleMember -Cmdlet `
7-
Import-Pog, Install-Pog, Enable-Pog, Export-Pog, Disable-Pog, Uninstall-Pog, `
6+
Export-ModuleMember -Alias pog -Cmdlet `
7+
Invoke-Pog, Import-Pog, Install-Pog, Enable-Pog, Export-Pog, Disable-Pog, Uninstall-Pog, `
88
Get-PogPackage, Get-PogRepositoryPackage, Get-PogRoot, `
99
Confirm-PogPackage, Confirm-PogRepositoryPackage, `
1010
Clear-PogDownloadCache, Show-PogManifestHash
@@ -21,71 +21,6 @@ Export function Edit-PogRootList {
2121
Start-Process $Path
2222
}
2323

24-
# defined below
25-
Export alias pog Invoke-Pog
26-
27-
# CmdletBinding is manually copied from Import-Pog, there doesn't seem any way to dynamically copy this like with dynamicparam
28-
# TODO: rollback on error
29-
# TODO: allow wildcards in PackageName and Version arguments for commands where it makes sense
30-
Export function Invoke-Pog {
31-
# .SYNOPSIS
32-
# Import, install, enable and export a package.
33-
# .DESCRIPTION
34-
# Runs all four installation stages in order. All arguments passed to this cmdlet,
35-
# except for the `-InstallOnly` switch, are forwarded to `Import-Pog`.
36-
[CmdletBinding(PositionalBinding = $false, DefaultParameterSetName = "PackageName_")]
37-
param(
38-
### Only import and install the package, do not enable and export.
39-
[switch]
40-
$InstallOnly,
41-
### Import, install and enable the package, do not export it.
42-
[switch]
43-
$NoExport
44-
)
45-
46-
dynamicparam {
47-
$ParamBuilder = [Pog.Commands.Common.DynamicCommandParameters+Builder]::new("", "None", {
48-
param($ParamName, $Attr)
49-
throw "Cannot copy parameter '$ParamName', attribute '$($Attr.GetType().ToString())'."
50-
})
51-
$CopiedParams = $ParamBuilder.CopyParameters((Get-Command Import-Pog))
52-
return $CopiedParams
53-
}
54-
55-
begin {
56-
$Params = $CopiedParams.Extract()
57-
58-
# reuse PassThru parameter from Import-Pog for Enable-Pog
59-
$PassThru = [bool]$Params["PassThru"]
60-
61-
$LogArgs = @{}
62-
if ($PSBoundParameters.ContainsKey("Verbose")) {$LogArgs["Verbose"] = $PSBoundParameters.Verbose}
63-
if ($PSBoundParameters.ContainsKey("Debug")) {$LogArgs["Debug"] = $PSBoundParameters.Debug}
64-
65-
$null = $Params.Remove("PassThru")
66-
67-
$SbAll = {Import-Pog -PassThru @Params | Install-Pog -PassThru @LogArgs | Enable-Pog -PassThru @LogArgs | Export-Pog -PassThru:$PassThru @LogArgs}
68-
$SbNoExport = {Import-Pog -PassThru @Params | Install-Pog -PassThru @LogArgs | Enable-Pog -PassThru:$PassThru @LogArgs}
69-
$SbNoEnable = {Import-Pog -PassThru @Params | Install-Pog -PassThru:$PassThru @LogArgs}
70-
71-
$Sb = if ($InstallOnly) {$SbNoEnable}
72-
elseif ($NoExport) {$SbNoExport}
73-
else {$SbAll}
74-
75-
$sp = $Sb.GetSteppablePipeline()
76-
$sp.Begin($PSCmdlet)
77-
}
78-
79-
process {
80-
$sp.Process($_)
81-
}
82-
83-
end {
84-
$sp.End()
85-
}
86-
}
87-
88-
8924
<# Ad-hoc template format used to create default manifests in the following 2 functions. #>
9025
function RenderTemplate($SrcPath, $DestinationPath, [Hashtable]$TemplateData) {
9126
$Template = Get-Content -Raw $SrcPath

app/Pog/lib_compiled/Pog/src/Commands/ImportPogCommand.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ public sealed class ImportPogCommand : PackageCommandBase {
5353
// Import-Pog -TargetName [-TargetPackageRoot]
5454
private const string TargetName_PS = "_TargetName";
5555

56+
internal const string DefaultPS = PackageName_PS;
57+
5658
// split parameter set into flags for each possible value
5759
[Flags]
5860
private enum PS {
@@ -270,11 +272,6 @@ private static ImportedPackage GetTargetPackage(string packageName, string? pack
270272
}
271273

272274
private void ImportPackage(RepositoryPackage package, ImportedPackage target) {
273-
var actionStr = $"Importing {package.GetDescriptionString()} to '{target.Path}'.";
274-
if (!ShouldProcess(actionStr, actionStr, null)) {
275-
return;
276-
}
277-
278275
// TODO: in the PowerShell version, we used to run Confirm-PogRepositoryManifest here;
279276
// think through whether it's a good idea to add that back
280277

@@ -286,6 +283,11 @@ private void ImportPackage(RepositoryPackage package, ImportedPackage target) {
286283
return;
287284
}
288285

286+
var actionStr = $"Importing {package.GetDescriptionString()} to '{target.Path}'.";
287+
if (!ShouldProcess(actionStr, actionStr, null)) {
288+
return;
289+
}
290+
289291
if (!ConfirmManifestOverwrite(package, target)) {
290292
WriteInformation($"Skipping import of package '{package.PackageName}'.");
291293
return;
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
using System.Collections;
2+
using System.Management.Automation;
3+
using System.Reflection;
4+
using JetBrains.Annotations;
5+
using Pog.Commands.Common;
6+
7+
namespace Pog.Commands;
8+
9+
// TODO: allow wildcards in PackageName and Version arguments for commands where it makes sense
10+
11+
/// <summary>
12+
/// <para type="synopsis">Import, install, enable and export a package.</para>
13+
/// <para type="description">
14+
/// Runs all four installation stages in order. All arguments passed to this cmdlet except for <c>-InstallOnly</c> and
15+
/// <c>-NoExport</c> are forwarded to <c>Import-Pog</c>.
16+
/// </para>
17+
/// </summary>
18+
[PublicAPI]
19+
[Alias("pog")]
20+
// Cmdlet(...) params are manually copied from Import-Pog, there doesn't seem any way to dynamically copy this like with dynamicparam
21+
[Cmdlet(VerbsLifecycle.Invoke, "Pog", DefaultParameterSetName = ImportPogCommand.DefaultPS)]
22+
[OutputType(typeof(ImportedPackage))]
23+
public sealed class InvokePogCommand : PackageCommandBase, IDynamicParameters {
24+
/// <summary><para type="description">
25+
/// Import and install the package, do not enable and export.
26+
/// </para></summary>
27+
[Parameter] public SwitchParameter Install;
28+
29+
/// <summary><para type="description">
30+
/// Import, install and enable the package, do not export it.
31+
/// </para></summary>
32+
[Parameter] public SwitchParameter Enable;
33+
34+
// TODO: add an `-Imported` parameter set to allow installing+enabling+exporting an imported package
35+
36+
private static readonly CommandInfo ImportPogInfo = new CmdletInfo("Import-Pog", typeof(ImportPogCommand));
37+
private static readonly CommandInfo InstallPogInfo = new CmdletInfo("Install-Pog", typeof(InstallPogCommand));
38+
private static readonly CommandInfo EnablePogInfo = new CmdletInfo("Enable-Pog", typeof(EnablePogCommand));
39+
private static readonly CommandInfo ExportPogInfo = new CmdletInfo("Export-Pog", typeof(ExportPogCommand));
40+
41+
private DynamicCommandParameters? _proxiedParams;
42+
private PowerShell _ps = PowerShell.Create();
43+
private SteppablePipeline? _pipeline;
44+
45+
public object GetDynamicParameters() {
46+
if (_proxiedParams != null) {
47+
return _proxiedParams;
48+
}
49+
var builder = new DynamicCommandParameters.Builder(UnknownAttributeHandler: (paramName, attr) =>
50+
throw new InternalError($"Cannot copy parameter '{paramName}', attribute '{attr.GetType()}'."));
51+
return _proxiedParams = builder.CopyParameters(ImportPogInfo);
52+
}
53+
54+
// TODO: rollback on error
55+
protected override void BeginProcessing() {
56+
base.BeginProcessing();
57+
58+
var importParams = _proxiedParams!.Extract();
59+
60+
// reuse PassThru parameter from Import-Pog for Enable-Pog
61+
var passThru = (importParams["PassThru"] as SwitchParameter?)?.IsPresent ?? false;
62+
importParams.Remove("PassThru");
63+
64+
// TODO: check if these aren't forwarded automatically, alternatively expand to all common parameters
65+
var logArgs = new Hashtable();
66+
if (MyInvocation.BoundParameters.ContainsKey("Verbose")) {
67+
logArgs["Verbose"] = MyInvocation.BoundParameters["Verbose"];
68+
}
69+
if (MyInvocation.BoundParameters.ContainsKey("Debug")) {
70+
logArgs["Debug"] = MyInvocation.BoundParameters["Debug"];
71+
}
72+
73+
_ps.AddCommand(ImportPogInfo).AddParameters(logArgs).AddParameter("PassThru").AddParameters(importParams);
74+
if (Install) {
75+
_ps.AddCommand(InstallPogInfo).AddParameters(logArgs).AddParameter("PassThru", passThru);
76+
} else {
77+
_ps.AddCommand(InstallPogInfo).AddParameters(logArgs).AddParameter("PassThru");
78+
if (Enable) {
79+
_ps.AddCommand(EnablePogInfo).AddParameters(logArgs).AddParameter("PassThru", passThru);
80+
} else {
81+
_ps.AddCommand(EnablePogInfo).AddParameters(logArgs).AddParameter("PassThru");
82+
_ps.AddCommand(ExportPogInfo).AddParameters(logArgs).AddParameter("PassThru", passThru);
83+
}
84+
}
85+
86+
_pipeline = (SteppablePipeline) PowerShellGetSteppablePipelineMethod.Invoke(_ps, []);
87+
_pipeline.Begin(this);
88+
}
89+
90+
protected override void ProcessRecord() {
91+
base.ProcessRecord();
92+
93+
// https://github.com/orgs/PowerShell/discussions/21356
94+
var value = CurrentPipelineObjectProperty.GetValue(this);
95+
_pipeline!.Process(value);
96+
}
97+
98+
protected override void EndProcessing() {
99+
base.EndProcessing();
100+
_pipeline!.End();
101+
}
102+
103+
public override void Dispose() {
104+
_ps.Dispose();
105+
_pipeline?.Dispose();
106+
}
107+
108+
private static readonly MethodInfo PowerShellGetSteppablePipelineMethod = typeof(PowerShell).GetMethod(
109+
"GetSteppablePipeline", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, null, [], [])!;
110+
111+
private static readonly PropertyInfo CurrentPipelineObjectProperty = typeof(PSCmdlet).GetProperty(
112+
"CurrentPipelineObject", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)!;
113+
}

0 commit comments

Comments
 (0)