Skip to content

Commit

Permalink
Rename Pog stub to shim
Browse files Browse the repository at this point in the history
All other projects (probably inspired by Scoop) call it a shim. I think that stub is a bit more accurate name, but I don't have a strong opinion about it, so let's go with the existing convention to simplify the terminology.
  • Loading branch information
MatejKafka committed May 9, 2024
1 parent e8d71ff commit f84a0ca
Show file tree
Hide file tree
Showing 17 changed files with 201 additions and 202 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ Pog is composed of 4 parts:

1. `app/Pog`: The main PowerShell module (`Pog.psm1` and imported modules). You don't need to build this.
2. `app/Pog/lib_compiled/Pog`: The `Pog.dll` C# library, where a lot of the core functionality lives. The library targets `.netstandard2.0`.
3. `app/Pog/lib_compiled/PogNative`: The `PogExecutableStubTemplate.exe` executable stub.
3. `app/Pog/lib_compiled/PogNative`: The `PogShimTemplate.exe` executable shim.
4. `app/Pog/lib_compiled/vc_redist`: Directory of VC Redistributable DLLs, used by some packages with the `-VcRedist` switch parameter on `Export-Command`/`Export-Shortcut`.

After all parts are ready, import the main module (`Import-Module app/Pog` from the root directory). Note that Pog assumes that the top-level directory is inside a package root, and it will place its data and cache directories in the top-level directory.
Expand All @@ -78,7 +78,7 @@ dotnet publish

### `lib_compiled/PogNative`

This project contains the executable stub used to set arguments and environment variables when exporting entry points to a package using `Export-Command` and `Export-Shortcut`. The output binary should appear at `lib_compiled/PogExecutableStubTemplate.exe`.
This project contains the executable shim used to set arguments and environment variables when exporting entry points to a package using `Export-Command` and `Export-Shortcut`. The output binary should appear at `lib_compiled/PogShimTemplate.exe`.

Build it using CMake and a recent-enough version of MSVC:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,12 +68,12 @@ to control this behavior more exactly, instead cast the string to [resolve] or [
# ISSUE: how to deal with single-argument formats like '--param=value'
# and '--param:value'?
#
<# Array of arguments that are passed to the target when the stub file is invoked.
Any arguments that the stub file is invoked with are appended to the arguments
<# Array of arguments that are passed to the target when the shim file is invoked.
Any arguments that the shim file is invoked with are appended to the arguments
defined here.

By default, all arguments starting with './' or '.\' are treated as relative
paths and resolved during stub file creation (not when the stub is invoked).
paths and resolved during shim file creation (not when the shim is invoked).
See the command description if you need more control over the resolution
([resolve] and [noresolve] types). #>
[Alias("Arguments")]
Expand All @@ -83,7 +83,7 @@ $ArgumentList = @(),
in addition to the environment variables inherited from the calling process.

By default, variable values starting with './' or '.\' are treated as relative
paths and resolved during stub file creation (NOT when the stub is invoked).
paths and resolved during shim file creation (NOT when the shim is invoked).
See the command description if you need more control over the resolution
([resolve] and [noresolve] types).

Expand Down
5 changes: 2 additions & 3 deletions app/Pog/_knowledge/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,12 +95,11 @@ https://github.com/miurahr/aqtinstall
- Export-Command should check if the file extension is in PATHEXT, especially if symlink is used
- if manifest writer changes download URL, forgets to update the hash, and has the URL cached, Pog will silently seem to work, using the cached archive; maybe use url as part of the cache entry key? Figure out how that would interact with multiple mirrors
- Add package for GIMP – https://www.gimp.org/man/gimp.html; environment variables like GIMP2_DIRECTORY
- ssh - when full stub binaries are implemented, pass -F to 'ssh.exe' to support package-local config dir without symlinks from ~/.ssh
- detect custom modifications to pog.psd1 inside a package and warn before overwriting (compare with repository manifest of the same version for differences)
- FileDownloader - figure out how to make BITS use filename from HTTP header instead of last segment of URL (this is an issue for e.g. rustup, where -NoArchive is passed, so user sees the actual downloaded binary name)
- substitute exe should correctly forward argv[0] (app name), so that e.g. ccache works
- always check that we're in a filesystem provider, and then use .ProviderPath for native commands to support network share paths
- manifest is not executed with strict mode
- investigate whether application manifests could be used on the stub to disable display scaling for the target, instead of modifying the manifest of the target directly
- investigate whether application manifests could be used on the shim to disable display scaling for the target, instead of modifying the manifest of the target directly
- probably build a separate Pog.dll for powershell < 7 and powershell >= 7 (to avoid duplicate definitions for Span and similar polyfilled types)
- consider whether unconditionally creating stubs for all exports would be better (otherwise what if .exe is used directly, and in next version, stub is added, and now half of the stuff in the system remembers and calls the old path (i.e. file associations)); this will also remove one place where symlinks are currently used for exporting commands
- consider whether unconditionally creating shims for all exports would be better (otherwise what if .exe is used directly, and in next version, shim is added, and now half of the stuff in the system remembers and calls the old path (i.e. file associations)); this will also remove one place where symlinks are currently used for exporting commands
4 changes: 2 additions & 2 deletions app/Pog/_scripts/release/build-release.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ try {
$SrcLibCompiled = "$Root/app/Pog/lib_compiled"
rm -Recurse app/Pog/lib_compiled/*
# copy Pog binaries and vc redist
@("Pog.dll", "Pog.dll-Help.xml", "PogExecutableStubTemplate.exe", "vc_redist") `
@("Pog.dll", "Pog.dll-Help.xml", "PogShimTemplate.exe", "vc_redist") `
| % {cp -Recurse $SrcLibCompiled/$_ app/Pog/lib_compiled/$_}


Expand Down Expand Up @@ -70,4 +70,4 @@ try {
if ($Run) {
Write-Information "Running Pog in Windows Sandbox..."
& $PSScriptRoot/run-release.ps1 $Version
}
}
6 changes: 3 additions & 3 deletions app/Pog/container/Env_Enable.psm1
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@ function RemoveStaleExports {

$InternalState = [Pog.EnableContainerContext]::GetCurrent($PSCmdlet)

if ($InternalState.StaleShortcuts.Count -gt 0 -or $InternalState.StaleShortcutStubs.Count -gt 0) {
if ($InternalState.StaleShortcuts.Count -gt 0 -or $InternalState.StaleShortcutShims.Count -gt 0) {
Write-Debug "Removing stale shortcuts..."
$InternalState.StaleShortcuts | % {
$ShortcutName = [IO.Path]::GetFileNameWithoutExtension($_)
Remove-Item $_
Write-Information "Removed stale shortcut '$ShortcutName'."
}
Remove-Item $InternalState.StaleShortcutStubs
Remove-Item $InternalState.StaleShortcutShims
}

if ($InternalState.StaleCommands.Count -gt 0) {
Expand Down Expand Up @@ -423,7 +423,7 @@ Export function Export-Shortcut {


if ($ArgumentList -or $EnvironmentVariables -or $VcRedist) {
Write-Debug "Creating a hidden stub to set arguments and environment..."
Write-Debug "Creating a hidden shim to set arguments and environment..."
# if -EnvironmentVariables was used, create a hidden command and point the shortcut to it,
# since shortcuts cannot set environment variables
# if -ArgumentList was passed, also create it, because if someone creates a file association by selecting
Expand Down
2 changes: 1 addition & 1 deletion app/Pog/lib_compiled/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,4 @@

/Pog.dll
/Pog.dll-Help.xml
/PogExecutableStubTemplate.exe
/PogShimTemplate.exe
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@
using System.Linq;
using System.Management.Automation;
using JetBrains.Annotations;
using Pog.Stub;
using Pog.Shim;
using Pog.Utils;

namespace Pog.Commands.ContainerCommands;

[PublicAPI]
[Cmdlet(VerbsData.Export, "Command", DefaultParameterSetName = StubPS)]
[Cmdlet(VerbsData.Export, "Command", DefaultParameterSetName = ShimPS)]
public class ExportCommandCommand : PSCmdlet {
private const string SymlinkPS = "Symlink";
private const string StubPS = "Stub";
private const string ShimPS = "Shim";

[Parameter(Mandatory = true, Position = 0)]
[Verify.FileName]
Expand All @@ -24,32 +24,32 @@ public class ExportCommandCommand : PSCmdlet {
[Verify.FilePath]
public string TargetPath = null!;

[Parameter(ParameterSetName = StubPS)]
[Parameter(ParameterSetName = ShimPS)]
[Verify.FilePath]
public string? WorkingDirectory;

[Parameter(ParameterSetName = StubPS)]
[Parameter(ParameterSetName = ShimPS)]
[Alias("Arguments")]
public string[]? ArgumentList;

// use IDictionary so that caller can use [ordered] if order is important
[Parameter(ParameterSetName = StubPS)]
[Parameter(ParameterSetName = ShimPS)]
[Alias("Environment")]
public IDictionary? EnvironmentVariables;

[Parameter(ParameterSetName = StubPS)]
[Parameter(ParameterSetName = ShimPS)]
[Verify.FilePath]
public string? MetadataSource;

// useful when the manifest wants to invoke the binary during Enable (e.g. initial config generation in Syncthing)
[Parameter] public SwitchParameter PassThru;
[Parameter(ParameterSetName = SymlinkPS)] public SwitchParameter Symlink;
[Parameter(ParameterSetName = StubPS)] public SwitchParameter VcRedist;
[Parameter(ParameterSetName = ShimPS)] public SwitchParameter VcRedist;
/// <summary><para type="description">
/// If set, argv[0] passed to the target is the absolute path to target, otherwise argv[0] is preserved from the stub.
/// If set, argv[0] passed to the target is the absolute path to target, otherwise argv[0] is preserved from the shim.
/// This switch is typically not necessary, but sometimes having a different `argv[0]` breaks the target.
/// </para></summary>
[Parameter(ParameterSetName = StubPS)] public SwitchParameter ReplaceArgv0;
[Parameter(ParameterSetName = ShimPS)] public SwitchParameter ReplaceArgv0;

// ReSharper disable once InconsistentNaming
// TODO: figure out some way to avoid this parameter without duplicating this cmdlet
Expand All @@ -70,7 +70,7 @@ protected override void BeginProcessing() {
var internalState = EnableContainerContext.GetCurrent(this);
var rTargetPath = GetUnresolvedProviderPathFromPSPath(TargetPath)!;
var commandDirRelPath = _InternalDoNotUse_Shortcut
? PathConfig.PackagePaths.ShortcutStubDirRelPath
? PathConfig.PackagePaths.ShortcutShimDirRelPath
: PathConfig.PackagePaths.CommandDirRelPath;
var commandDirPath = GetUnresolvedProviderPathFromPSPath(commandDirRelPath);

Expand All @@ -97,17 +97,17 @@ protected override void BeginProcessing() {
WriteVerbose($"Command {cmdName} is already exported as a symlink.");
}
} else {
if (ExportCommandStubExecutable(cmdName, rLinkPath, rTargetPath)) {
WriteInformation($"Exported command '{cmdName}' using a stub executable.", null);
if (ExportCommandShimExecutable(cmdName, rLinkPath, rTargetPath)) {
WriteInformation($"Exported command '{cmdName}' using a shim executable.", null);
} else {
WriteVerbose($"Command {cmdName} is already exported as a stub executable.");
WriteVerbose($"Command {cmdName} is already exported as a shim executable.");
}
}

// mark this command as not stale
// (stale = e.g. leftover command from previous version that was removed for this version)
if (_InternalDoNotUse_Shortcut) {
internalState.StaleShortcutStubs.Remove(rLinkPath);
internalState.StaleShortcutShims.Remove(rLinkPath);
} else {
internalState.StaleCommands.Remove(rLinkPath);
}
Expand All @@ -130,7 +130,7 @@ private bool ExportCommandSymlink(string cmdName, string rLinkPath, string rTarg
return true;
}

private bool ExportCommandStubExecutable(string cmdName, string rLinkPath, string rTargetPath) {
private bool ExportCommandShimExecutable(string cmdName, string rLinkPath, string rTargetPath) {
var rWorkingDirectory = WorkingDirectory == null ? null : GetUnresolvedProviderPathFromPSPath(WorkingDirectory)!;
var rMetadataSource = MetadataSource == null ? null : GetUnresolvedProviderPathFromPSPath(MetadataSource);

Expand All @@ -155,27 +155,27 @@ private bool ExportCommandStubExecutable(string cmdName, string rLinkPath, strin
}

// TODO: argument and env resolution
var stub = new StubExecutable(rTargetPath, rWorkingDirectory, resolvedArgs, resolvedEnvVars, ReplaceArgv0);
var shim = new ShimExecutable(rTargetPath, rWorkingDirectory, resolvedArgs, resolvedEnvVars, ReplaceArgv0);

if (File.Exists(rLinkPath)) {
if ((new FileInfo(rLinkPath).Attributes & FileAttributes.ReparsePoint) != 0) {
// reparse point, not an ordinary file, remove
File.Delete(rLinkPath);
WriteDebug("Overwriting symlink with a stub executable...");
WriteDebug("Overwriting symlink with a shim executable...");
} else {
try {
return stub.UpdateStub(rLinkPath, rMetadataSource);
} catch (StubExecutable.OutdatedStubException) {
// outdated stub exe, overwrite the stub with a new version
return shim.UpdateShim(rLinkPath, rMetadataSource);
} catch (ShimExecutable.OutdatedShimException) {
// outdated shim exe, overwrite with a new version
File.Delete(rLinkPath);
WriteDebug("Old stub executable, replacing with an up-to-date one...");
WriteDebug("Old shim executable, replacing with an up-to-date one...");
}
}
}

// copy empty stub to rLinkPath
File.Copy(InternalState.PathConfig.ExecutableStubPath, rLinkPath);
stub.WriteNewStub(rLinkPath, rMetadataSource);
// copy empty shim to rLinkPath
File.Copy(InternalState.PathConfig.ShimPath, rLinkPath);
shim.WriteNewShim(rLinkPath, rMetadataSource);
return true;
}

Expand All @@ -199,7 +199,7 @@ private string[] ResolveArguments(string[] args) {
private List<KeyValuePair<string, string[]>> ResolveEnvironmentVariables(IDictionary envVars) {
// if `envVars` is not a SortedDictionary, sort entries alphabetically, so that we get a consistent order
// this is important, because iteration order of dictionaries apparently differs between .NET Framework
// and .NET Core, and we want the stubs to be consistent between powershell.exe and pwsh.exe
// and .NET Core, and we want the shims to be consistent between powershell.exe and pwsh.exe
var envEnumerable = envVars is IOrderedDictionary
? envVars.Cast<DictionaryEntry>()
: envVars.Cast<DictionaryEntry>().OrderBy(e => e.Key);
Expand All @@ -208,7 +208,7 @@ private List<KeyValuePair<string, string[]>> ResolveEnvironmentVariables(IDictio
// this does not match strings (char is not an object)
IEnumerable<object> enumerable => enumerable.SelectOptional(ResolveEnvironmentVariableValue)
.ToArray(),
_ => new[] {ResolveEnvironmentVariableValue(e.Value) ?? ""},
_ => [ResolveEnvironmentVariableValue(e.Value) ?? ""],
})).ToList();
}
}
10 changes: 5 additions & 5 deletions app/Pog/lib_compiled/Pog/src/ImportedPackageTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ internal bool RemoveExportedCommands() {
return DeleteDirectoryRel(PathConfig.PackagePaths.CommandDirRelPath);
}

internal bool RemoveShortcutStubs() {
return DeleteDirectoryRel(PathConfig.PackagePaths.ShortcutStubDirRelPath);
internal bool RemoveShortcutShims() {
return DeleteDirectoryRel(PathConfig.PackagePaths.ShortcutShimDirRelPath);
}

private bool DeleteDirectoryRel(string relDirPath) {
Expand All @@ -201,9 +201,9 @@ public IEnumerable<FileInfo> EnumerateExportedCommands() {
return EnumerateFilesRel(PathConfig.PackagePaths.CommandDirRelPath);
}

/// Enumerates full paths of all internal shortcut stubs.
internal IEnumerable<FileInfo> EnumerateShortcutStubs() {
return EnumerateFilesRel(PathConfig.PackagePaths.ShortcutStubDirRelPath);
/// Enumerates full paths of all internal shortcut shims.
internal IEnumerable<FileInfo> EnumerateShortcutShims() {
return EnumerateFilesRel(PathConfig.PackagePaths.ShortcutShimDirRelPath);
}

private IEnumerable<FileInfo> EnumerateFilesRel(string relDirPath, string searchPattern = "*") {
Expand Down
2 changes: 1 addition & 1 deletion app/Pog/lib_compiled/Pog/src/InnerCommands/DisablePog.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ private void RemoveExportedItems(ImportedPackage package) {

package.RemoveExportedCommands();
package.RemoveExportedShortcuts();
package.RemoveShortcutStubs();
package.RemoveShortcutShims();
}

private void RemoveGloballyExportedShortcuts(ImportedPackage p) {
Expand Down
4 changes: 2 additions & 2 deletions app/Pog/lib_compiled/Pog/src/Pog.EnableContainerContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ public class EnableContainerContext : Container.EnvironmentContext<EnableContain
/// <see cref="StaleShortcuts"/>
public readonly HashSet<string> StaleCommands;
/// <see cref="StaleShortcuts"/>
public readonly HashSet<string> StaleShortcutStubs;
public readonly HashSet<string> StaleShortcutShims;

internal EnableContainerContext(ImportedPackage enabledPackage) {
StaleShortcuts = [..enabledPackage.EnumerateExportedShortcuts().Select(f => f.FullName)];
StaleCommands = [..enabledPackage.EnumerateExportedCommands().Select(f => f.FullName)];
StaleShortcutStubs = [..enabledPackage.EnumerateShortcutStubs().Select(f => f.FullName)];
StaleShortcutShims = [..enabledPackage.EnumerateShortcutShims().Select(f => f.FullName)];
}
}
6 changes: 3 additions & 3 deletions app/Pog/lib_compiled/Pog/src/Pog.PathConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public static class PackagePaths {

[PublicAPI] public const string ShortcutDirRelPath = ".";
internal const string CommandDirRelPath = "./.commands";
internal const string ShortcutStubDirRelPath = "./.commands/shortcuts";
internal const string ShortcutShimDirRelPath = "./.commands/shortcuts";

internal const string AppDirName = "app";
internal const string CacheDirName = "cache";
Expand Down Expand Up @@ -74,7 +74,7 @@ public static class PackagePaths {

public readonly string ContainerDir;
public readonly string CompiledLibDir;
public readonly string ExecutableStubPath;
public readonly string ShimPath;
public readonly string VcRedistDir;

public readonly string ExportedCommandDir;
Expand Down Expand Up @@ -106,7 +106,7 @@ public PathConfig(string appRootDirPath, string dataRootDirPath, string cacheRoo

ContainerDir = $"{appRootDirPath}\\container";
CompiledLibDir = $"{appRootDirPath}\\lib_compiled";
ExecutableStubPath = $"{CompiledLibDir}\\PogExecutableStubTemplate.exe";
ShimPath = $"{CompiledLibDir}\\PogShimTemplate.exe";
VcRedistDir = $"{CompiledLibDir}\\vc_redist";

ExportedCommandDir = $"{dataRootDirPath}\\package_bin";
Expand Down
Loading

0 comments on commit f84a0ca

Please sign in to comment.