Skip to content

Commit 038f946

Browse files
committed
! Unify package and generator repository
Previously, there was a separate repository for packages and for manifest generators, but the two had to be kept in sync. Original rationale for the split has two parts: 1) Conceptually, packages are for users, while generators are for the author - users are interested in the repository, but not necessarily in the generators. Since we now have remote repos, this is more-or-less solved. 2) A package author might want to have a public package repo, but private generators that rely on internal tooling. This is still potentially an issue, but I don't see it coming up in practice; if necessary, it can also be solved by generating a remote repo and keeping the sources private, at the cost of having the origin local package repo public. TODO: when next release is published, push changes in `PogPackages` and remove `PogManifestGenerators`.
1 parent dd01a41 commit 038f946

12 files changed

+74
-144
lines changed

app/Pog/Pog.Format.ps1xml

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -177,31 +177,5 @@
177177
</TableRowEntries>
178178
</TableControl>
179179
</View>
180-
<View>
181-
<Name>Pog.PackageGenerator</Name>
182-
<ViewSelectedBy>
183-
<TypeName>Pog.PackageGenerator</TypeName>
184-
</ViewSelectedBy>
185-
<TableControl>
186-
<TableHeaders>
187-
<TableColumnHeader>
188-
<Width>20</Width>
189-
</TableColumnHeader>
190-
<TableColumnHeader/>
191-
</TableHeaders>
192-
<TableRowEntries>
193-
<TableRowEntry>
194-
<TableColumnItems>
195-
<TableColumnItem>
196-
<PropertyName>PackageName</PropertyName>
197-
</TableColumnItem>
198-
<TableColumnItem>
199-
<PropertyName>Path</PropertyName>
200-
</TableColumnItem>
201-
</TableColumnItems>
202-
</TableRowEntry>
203-
</TableRowEntries>
204-
</TableControl>
205-
</View>
206180
</ViewDefinitions>
207181
</Configuration>

app/Pog/container/Env_ManifestGenerator.psm1

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,32 +13,32 @@ $PSDefaultParameterValues = @{
1313

1414
$ContainerModule = New-ContainerModule
1515

16-
function ListVersions($Generator, $ExistingVersionSet) {
16+
function ListVersions($Package, $ExistingVersionSet) {
1717
try {
18-
return & $ContainerModule $Generator.Manifest.ListVersionsSb $ExistingVersionSet
18+
return & $ContainerModule $Package.Generator.ListVersionsSb $ExistingVersionSet
1919
} catch {
20-
throw [Exception]::new("Manifest generator for package '$($Generator.PackageName)' failed while listing versions: $_", $_.Exception)
20+
throw [Exception]::new("Manifest generator for package '$($Package.PackageName)' failed while listing versions: $_", $_.Exception)
2121
}
2222
}
2323

2424
<# Retrieve all existing versions of a package by calling the package version generator script. #>
25-
function RetrievePackageVersions([Pog.PackageGenerator]$Generator, $ExistingVersionSet) {
26-
foreach ($Obj in ListVersions $Generator $ExistingVersionSet) {
25+
function RetrievePackageVersions($Package, $ExistingVersionSet) {
26+
foreach ($Obj in ListVersions $Package $ExistingVersionSet) {
2727
# the returned object should either be the version string directly, or a map object
2828
# (hashtable/pscustomobject/psobject/ordered) that has the Version property
2929
# why not use -is? that's why: https://github.com/PowerShell/PowerShell/issues/16361
3030
$IsMap = $Obj.PSTypeNames[0] -in @("System.Collections.Hashtable", "System.Management.Automation.PSCustomObject", "System.Collections.Specialized.OrderedDictionary")
3131
$VersionStr = if (-not $IsMap) {$Obj} else {
3232
try {$Obj.Version}
3333
catch {
34-
throw "Version generator for package '$($Generator.PackageName)' returned a custom object without a Version property: $Obj" +`
34+
throw "Version generator for package '$($Package.PackageName)' returned a custom object without a Version property: $Obj" +`
3535
" (Version generators must return either a version string, or a" +`
3636
" map container (hashtable, psobject, pscustomobject) with a Version property.)"
3737
}
3838
}
3939

4040
if ([string]::IsNullOrEmpty($VersionStr)) {
41-
throw "Empty package version generated by the version generator for package '$($Generator.PackageName)' (either `$null or empty string)."
41+
throw "Empty package version generated by the version generator for package '$($Package.PackageName)' (either `$null or empty string)."
4242
}
4343

4444
[pscustomobject]@{
@@ -56,7 +56,6 @@ function __main {
5656
### Internally, it invokes `ListVersions` for the generator and then invokes `Generate` for each version
5757
### that should be regenerated.
5858
param(
59-
[Pog.PackageGenerator]$Generator,
6059
[Pog.LocalRepositoryVersionedPackage]$Package,
6160
[string[]]$Version,
6261
[bool]$Force,
@@ -70,7 +69,7 @@ function __main {
7069
# list available versions without existing manifest (unless -Force is set, then all versions are listed)
7170
# only generate manifests for versions that don't already exist, unless -Force is passed
7271
$ExistingVersions = [System.Collections.Generic.HashSet[string]]::new($Package.EnumerateVersionStrings())
73-
$GeneratedVersions = RetrievePackageVersions $Generator $ExistingVersions `
72+
$GeneratedVersions = RetrievePackageVersions $Package $ExistingVersions `
7473
<# if -Force was not passed, filter out versions with already existing manifest #> `
7574
| ? {$Force -or -not $ExistingVersions.Contains($_.Version)} `
7675
<# if $Version was passed, filter out the versions; as the versions generated by the script
@@ -97,8 +96,8 @@ function __main {
9796
$p = $Package.GetVersionPackage($v.Version, $false)
9897

9998
try {
100-
$TemplateData = if ($Generator.Manifest.GenerateSb) {
101-
$Sb = $ContainerModule.NewBoundScriptBlock($Generator.Manifest.GenerateSb)
99+
$TemplateData = if ($Package.Generator.GenerateSb) {
100+
$Sb = $ContainerModule.NewBoundScriptBlock($Package.Generator.GenerateSb)
102101
# pass the value both as $_ and as a parameter, the scriptblock can accept whichever one is more convenient
103102
Invoke-DollarUnder $Sb $v.OriginalValue $v.OriginalValue
104103
} else {

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ private void ValidateTemplatedPackage(LocalRepositoryVersionedPackage vp) {
181181
}
182182

183183
// validate .template dir
184-
ValidateManifestDirectory($"package '{vp.PackageName}'", templateDirPath);
184+
ValidateManifestDirectory($"package '{vp.PackageName}'", templateDirPath, true);
185185

186186
// validate that manifest template exists
187187
if (!File.Exists(templatePath)) {
@@ -220,7 +220,7 @@ private void ValidatePackageVersions(LocalRepositoryVersionedPackage vp, bool va
220220
private void ValidatePackageVersion(LocalRepositoryPackage p, bool validateManifestDir = true) {
221221
if (validateManifestDir) {
222222
var path = p is TemplatedLocalRepositoryPackage tp ? tp.TemplateDirPath : p.Path;
223-
ValidateManifestDirectory(p.GetDescriptionString(), path);
223+
ValidateManifestDirectory(p.GetDescriptionString(), path, false);
224224
}
225225

226226
// validate the manifest
@@ -254,18 +254,25 @@ private void ValidatePackageVersion(LocalRepositoryPackage p, bool validateManif
254254
}
255255
}
256256

257-
private void ValidateManifestDirectory(string packageInfoStr, string templateDirPath) {
258-
var extraEntries = GetFileList(Directory.EnumerateFileSystemEntries(templateDirPath)
259-
.Where(p => !p.EndsWith(@"\pog.psd1") && !p.EndsWith(@"\.pog")));
260-
if (extraEntries != "") {
261-
AddIssue($"Manifest directory for {packageInfoStr} at '{templateDirPath}' contains extra " +
262-
$"entries: {extraEntries}. Only a 'pog.psd1' manifest file and an optional '.pog' directory for extra " +
263-
$"files is allowed.");
257+
private void ValidateManifestDirectory(string packageInfoStr, string manifestDirPath, bool isTemplate) {
258+
var extraEntries = Directory.EnumerateFileSystemEntries(manifestDirPath)
259+
.Where(p => !p.EndsWith(@"\pog.psd1") && !p.EndsWith(@"\.pog"));
260+
261+
if (isTemplate) {
262+
// allow the generator manifest for template dir
263+
extraEntries = extraEntries.Where(p => !p.EndsWith(@"\generator.psd1"));
264+
}
265+
266+
var extraEntriesStr = GetFileList(extraEntries);
267+
if (extraEntriesStr != "") {
268+
AddIssue($"Manifest directory for {packageInfoStr} at '{manifestDirPath}' contains extra entries: " +
269+
$"{extraEntriesStr}. Only a 'pog.psd1' manifest file{(isTemplate ? ", a 'generator.psd1' generator file" : "")} " +
270+
$"and an optional '.pog' directory for extra files is allowed.");
264271
}
265272

266-
if (File.Exists($"{templateDirPath}\\.pog")) {
273+
if (File.Exists($"{manifestDirPath}\\.pog")) {
267274
AddIssue($"Extra resource directory for {packageInfoStr} must be a directory, " +
268-
$"found a file at '{templateDirPath}\\.pog'.");
275+
$"found a file at '{manifestDirPath}\\.pog'.");
269276
}
270277

271278
// pog.psd1 manifest is validated separately

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

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System;
2-
using System.Linq;
1+
using System.Linq;
32
using System.Management.Automation;
43
using System.Security;
54
using JetBrains.Annotations;
@@ -79,49 +78,46 @@ protected override void ProcessRecord() {
7978
if (PackageName == null) return;
8079

8180
foreach (var pn in PackageName) {
82-
var generator = InternalState.GeneratorRepository.GetPackage(pn, true, true);
83-
// ensure manifest is loaded
84-
generator.ReloadManifest();
81+
var p = (LocalRepositoryVersionedPackage) _repo.GetPackage(pn, true, true);
82+
if (!p.HasGenerator) {
83+
WriteError(new PackageGeneratorNotFoundException($"Package '{p.PackageName}' does not have a generator."),
84+
"MissingGenerator", ErrorCategory.ObjectNotFound, pn);
85+
continue;
86+
}
8587

8688
// if -Version was passed, overwrite even existing manifests
87-
ProcessPackage(generator, Force || Version != null);
89+
ProcessPackage(p, Force || Version != null);
8890
}
8991
}
9092

9193
private void UpdateAll() {
92-
var generators = InternalState.GeneratorRepository.Enumerate().ToArray();
93-
if (generators.Length == 0) {
94+
var packages = _repo.EnumerateGeneratedPackages().ToArray();
95+
if (packages.Length == 0) {
9496
return;
9597
}
9698

9799
using var progressBar = new CmdletProgressBar(this, new() {
98100
Activity = "Updating repository",
99101
// this duplicates the code below in the loop, but we have to do that due to
100102
// https://github.com/PowerShell/PowerShell/issues/24728
101-
Description = $"Updating '{generators[0].PackageName}'...",
103+
Description = $"Updating '{packages[0].PackageName}'...",
102104
});
103105

104106
var i = 0;
105-
foreach (var generator in generators) {
106-
progressBar.Update((double) i++ / generators.Length, $"Updating '{generator.PackageName}'...");
107-
ProcessPackage(generator, Force);
107+
foreach (var p in packages) {
108+
progressBar.Update((double) i++ / packages.Length, $"Updating '{p.PackageName}'...");
109+
ProcessPackage(p, Force);
108110
}
109111
}
110112

111-
private void ProcessPackage(PackageGenerator generator, bool force) {
112-
var package = (LocalRepositoryVersionedPackage) _repo.GetPackage(generator.PackageName, true, true);
113-
if (!package.IsTemplated) {
114-
var e = new ArgumentException(
115-
$"Package '{package.PackageName}' {(package.Exists ? "is not templated" : "does not exist yet")}, " +
116-
"generators are only supported for existing templated packages.");
117-
WriteError(e, "NonTemplatedPackage", ErrorCategory.InvalidArgument, generator.PackageName);
118-
return;
119-
}
113+
private void ProcessPackage(LocalRepositoryVersionedPackage package, bool force) {
114+
// ensure generator manifest is loaded
115+
package.ReloadGenerator();
120116

121117
var it = InvokePogCommand(new InvokeContainer(this) {
122118
Modules = [$@"{InternalState.PathConfig.ContainerDir}\Env_ManifestGenerator.psm1"],
123119
Run = ps => ps.AddCommand("__main").AddParameters(
124-
new object?[] {generator, package, Version, force, ListOnly, GitHubToken}),
120+
new object?[] {package, Version, force, ListOnly, GitHubToken}),
125121
});
126122

127123
foreach (var o in it) {

app/Pog/lib_compiled/Pog/src/LocalRepositoryTypes.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ public IEnumerable<RepositoryVersionedPackage> Enumerate(string searchPattern =
2727
return EnumeratePackageNames(searchPattern).Select(p => new LocalRepositoryVersionedPackage(repo, p));
2828
}
2929

30+
public IEnumerable<string> EnumerateGeneratedPackageNames(string searchPattern = "*") {
31+
return EnumerateGeneratedPackages(searchPattern).Select(p => p.PackageName);
32+
}
33+
34+
public IEnumerable<LocalRepositoryVersionedPackage> EnumerateGeneratedPackages(string searchPattern = "*") {
35+
return Enumerate(searchPattern).Cast<LocalRepositoryVersionedPackage>().Where(p => p.HasGenerator);
36+
}
37+
3038
public RepositoryVersionedPackage GetPackage(string packageName, bool resolveName, bool mustExist) {
3139
Verify.PackageName(packageName);
3240
if (resolveName) {
@@ -51,9 +59,15 @@ public sealed class LocalRepositoryVersionedPackage : RepositoryVersionedPackage
5159
public readonly string Path;
5260
public override bool Exists => Directory.Exists(Path);
5361
public bool IsTemplated => Directory.Exists(TemplateDirPath);
62+
public bool HasGenerator => File.Exists(GeneratorPath);
5463

5564
public string TemplateDirPath => $"{Path}\\{PPaths.RepositoryTemplateDirName}";
5665
public string TemplatePath => $"{TemplateDirPath}\\{PPaths.ManifestFileName}";
66+
public string GeneratorPath => $"{TemplateDirPath}\\{PPaths.GeneratorFileName}";
67+
68+
private PackageGeneratorManifest? _generator;
69+
public PackageGeneratorManifest Generator => _generator ?? ReloadGenerator();
70+
5771
internal override string ExpectedPathStr => $"expected path: {Path}";
5872

5973
internal LocalRepositoryVersionedPackage(LocalRepository repository, string packageName) : base(packageName) {
@@ -88,6 +102,12 @@ protected override RepositoryPackage GetPackageUnchecked(PackageVersion version)
88102
? new TemplatedLocalRepositoryPackage(this, version)
89103
: new DirectLocalRepositoryPackage(this, version);
90104
}
105+
106+
/// <exception cref="PackageManifestNotFoundException">Thrown if the package generator does not exist.</exception>
107+
/// <exception cref="PackageManifestParseException">Thrown if the package generator file is not a valid PowerShell data file (.psd1).</exception>
108+
public PackageGeneratorManifest ReloadGenerator() {
109+
return _generator = new PackageGeneratorManifest(GeneratorPath);
110+
}
91111
}
92112

93113
[PublicAPI]

app/Pog/lib_compiled/Pog/src/PSAttributes/Completers.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,9 @@ protected override IEnumerable<string> GetMatchingItems(string searchPattern, ID
117117
[PublicAPI]
118118
public sealed class RepositoryPackageGeneratorNameCompleter : DirectoryListingArgumentCompleter {
119119
protected override IEnumerable<string> GetMatchingItems(string searchPattern, IDictionary _) {
120-
return InternalState.GeneratorRepository.EnumerateGeneratorNames(searchPattern);
120+
return InternalState.Repository is LocalRepository localRepo
121+
? localRepo.EnumerateGeneratedPackageNames(searchPattern)
122+
: [];
121123
}
122124
}
123125

app/Pog/lib_compiled/Pog/src/PackageGeneratorTypes.cs

Lines changed: 0 additions & 65 deletions
This file was deleted.

app/Pog/lib_compiled/Pog/src/Pog.InternalState.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,6 @@ public static IRepository Repository {
6262
set => Interlocked.Exchange(ref _repository, value);
6363
}
6464

65-
private static GeneratorRepository? _generatorRepository;
66-
public static GeneratorRepository GeneratorRepository => LazyInitializer.EnsureInitialized(ref _generatorRepository,
67-
() => new GeneratorRepository(PathConfig.ManifestGeneratorDir))!;
68-
6965
private static ImportedPackageManager? _importedPackageManager;
7066
public static ImportedPackageManager ImportedPackageManager => LazyInitializer.EnsureInitialized(
7167
ref _importedPackageManager,

app/Pog/lib_compiled/Pog/src/Pog.PackageManifestGenerator.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
using System;
22
using System.Collections;
3+
using System.IO;
34
using System.Management.Automation;
45
using JetBrains.Annotations;
56

67
namespace Pog;
78

89
public class InvalidGeneratorManifestException(string message) : Exception(message);
910

11+
public class PackageGeneratorNotFoundException(string message) : FileNotFoundException(message);
12+
1013
[PublicAPI]
1114
public class PackageGeneratorManifest {
1215
public readonly Hashtable Raw;

app/Pog/lib_compiled/Pog/src/Pog.PathConfig.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ public static class PackagePaths {
3838
internal const string ManifestFileName = "pog.psd1";
3939
internal const string ManifestResourceDirName = ".pog";
4040
internal const string RepositoryTemplateDirName = ".template";
41+
internal const string GeneratorFileName = "generator.psd1";
4142

4243
// suffixes, not relative paths (do not add a slash when joining these)
4344
internal const string ShortcutDirRelSuffix = "";
@@ -71,7 +72,6 @@ public static class PackagePaths {
7172
/// Directory where exported shortcuts from packages are copied (per-user).
7273
public readonly string ExportedShortcutDir;
7374
public readonly string ExportedCommandDir;
74-
public readonly string ManifestGeneratorDir;
7575

7676
/// Directory where package files with known hash are cached.
7777
public readonly string DownloadCacheDir;
@@ -102,7 +102,6 @@ public PathConfig(string pogRootPath, string? dataRootPath = null, string? short
102102

103103
var dataPath = $"{dataRootPath}\\data";
104104
ExportedCommandDir = $"{dataPath}\\package_bin";
105-
ManifestGeneratorDir = $"{dataPath}\\manifest_generators";
106105
PackageRoots = new PackageRootConfig($"{dataPath}\\package_roots.txt");
107106
Path7Zip = $"{ExportedCommandDir}\\7z.exe";
108107
PathOpenedFilesView = $"{ExportedCommandDir}\\OpenedFilesView.exe";

0 commit comments

Comments
 (0)