Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(Import-PSDependModule): Sanitize version string used for Import-Module #140

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

fourpastmidnight
Copy link

@fourpastmidnight fourpastmidnight commented Sep 7, 2023

This commit fixes one particular issue out of two identified issues.

The first identified issue is that when initially "getting" a dependency, it does not seem to be imported. (I may be mistaken on this point, but read on.) The second issue, and the one this commit addresses, is that upon a subsequent run of PSDepend, the now "installed" module is attempted to be imported, and this fails in the case of modules whose PSDepend specification's version string includes a pre-release version tag.

For example, the following spec:

@{
    'PSResourceGet' = @{
        Name = 'Micrsooft.PowerShell.PSResourceGet'
        Version = 'latest'
        Parameters = @{
            AllowPreRelease = $true
        }
    }
}

The first time you run PSDepend, everything "works" fine. The reason I say that an "install" is performed but not an import is because there are no errors when running this the first time. But using this same configuration, running PSDepend a subsequent time results in the following error:

Checking for and installing the latest versions of the build system dependencies...
WARNING: Access to the path 'D:\src\git\MyProject\build\deps\Microsoft.PowerShell.PSResourceGet\0.5.24' is denied.
Save-Package: Unable to save the module 'Microsoft.PowerShell.PSResourceGet'.
Import-Module: C:\Users\me\Documents\PowerShell\Modules\PSDepend\0.3.8\Private\Import-PSDependModule.ps1:21
Line |
  21 |              Import-Module @importParams
     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The specified module 'D:\src\git\MyProject\build\deps\Microsoft.PowerShell.PSResourceGet' was not loaded because no valid module
     | file was found in any module directory.

The issue here is that now that the module is "installed", the version string, as specified in the PSDepend spec, is passed directly to Import-Module via Import-PSDependModule. It is necessary to sanitize the version string to remove any pre-release tags since Import-Module doesn't know anything about pre-release versions. The RquiredVersion parameter is a System.Version from the .NET BCL and is a Microsoft-proprietary version number format, not a SemVer string.

This commit fixes this subsequent "import issue".

Fixes #132

…odule

This commit fixes one particular issue out of two identified issues.

The first identified issue is that when initially "getting" a
dependency, it does not seem to be imported. (I may be mistaken on this
point, but read on.) The second issue, and the one this commit
addresses, is that upon a subsequent run of PSDepend, the now
"installed" module is attempted to be imported, and this fails in the
case of modules whose PSDepend specification's version string includes a
pre-release version tag.

For example, the following spec:

```powershell
@{
    'PSResourceGet' = @{
        Name = 'Micrsooft.PowerShell.PSResourceGet'
        Version = 'latest'
        Parameters = @{
            AllowPreRelease = $true
        }
    }
}
```

The first time you run PSDepend, everything "works" fine. The reason I
say that an "install" is preformed but not an import is because there
are no errors when running this thi ferist time. But using this same
configuration, running PSDepend a subsequent time results in the
following error:

```text
Checking for and installing the latest versions of the build system dependencies...
WARNING: Access to the path 'D:\src\git\MyProject\build\deps\Microsoft.PowerShell.PSResourceGet\0.5.24' is denied.
Save-Package: Unable to save the module 'Microsoft.PowerShell.PSResourceGet'.
Import-Module: C:\Users\me\Documents\PowerShell\Modules\PSDepend\0.3.8\Private\Import-PSDependModule.ps1:21
Line |
  21 |              Import-Module @importParams
     |              ~~~~~~~~~~~~~~~~~~~~~~~~~~~
     | The specified module 'D:\src\git\MyProject\build\deps\Microsoft.PowerShell.PSResourceGet' was not loaded because no valid module
     | file was found in any module directory.
```

The issue here is that now that the module is "installed", the version
string, as specified in the PSDepend spec, is passed directly to
Import-Module via Import-PSDependModule. It is necessary to sanitize the
version string to remove any pre-release tags since Import-Module
doesn't know anything about pre-release versions. The RquiredVersion
parameter is a `System.Version` from the .NET BCL and is a
Microsoft-proprietary version number  format, not a SemVer string.

This commit fixes this subsequent "import issue".
@fourpastmidnight
Copy link
Author

One could argue that this change should be hoisted up to PSDepend\PSDependScripts\PSGalleryModule.ps1. However, one counter-argument to that argument is that potentially any PSDependScript passing data to Import-PSDependModule could be susceptible to not sanitizing the version string prior to invoking Import-PSdependModule, resulting in the same or a similar error; and so I thought it made sense to put this change there.

@johlju
Copy link

johlju commented Sep 8, 2023

If you would have both version 2.0.0 and 2.0.0-preview1 and you want to import 2.0.0-preview1 the suggested change would wrongly import 2.0.0. Ignore that - actually thought that Import-Module in PS7 actually supported that, but no. 🙂

The first error that is reported is Save-Package: Unable to save the module 'Microsoft.PowerShell.PSResourceGet'.. This is probably due to that the PSResourceGet is imported into the session, and it will load assemblies which will make it impossible to remove the folder until the session is closed that has those assemblies loaded.

@fourpastmidnight
Copy link
Author

fourpastmidnight commented Sep 8, 2023

@johlju, Yes, you are correct, but that's because PowerShell has no idea about pre-release versions. The -RequiredVersion parameter of Import-Module is a System.Version, which is a Microsoft-proprietary version number format that does not follow semver. There is no way to specify a pre-release version when importing a module (for Desktop PowerShell—I need to check on PowerShell Core).

If you install a prerelease version, let's say MyModule, version 2.0.0-preview1, here's the directory structure you will find of the installed module:

C:\Users\<me>\Documents\WindowsPowerShell\Modules
 └─ MyModule
     └─ 2.0.0
         └─ <Module files and folders>

Notice the folder for the version--there is no pre-release tag there.

@johlju
Copy link

johlju commented Sep 8, 2023

Yes, correct. The preview release string is in the module manifest.

@fourpastmidnight
Copy link
Author

fourpastmidnight commented Sep 8, 2023

Exactly. So, because PSDepend was passing the full SemVer version string as the -RequiredVersion parameter to Import-Module, this was breaking the import of pre-release modules.

Looking at PowerShell Core, I don't see that that has changed. One thing I want to research once more, is it possible to specify a pre-release version string in a full "module declaration" when importing? But IIRC, I don't believe there is.

@fourpastmidnight
Copy link
Author

Per your other comment regarding Save-Package, I got this, too. And PSDepend cannot help with this. You are correct. Some modules have binary dependencies. For example, if you write a PowerShell script and use the Add-Type -AssemblyName System.Messaging, then those types are forever in your session. There's no way to "unload" the assembly. This has implications for modules that are imported by PSDepend that have such external DLL dependencies. A subsequent dependency installation will fail if those DLLs have been loaded into your session already. The only thing you can do is close your session and start a new one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Cannot reference specific version of prerelease
2 participants