Read-only mirrors. Development, issues and pull requests are on GitHub.

summaryrefslogtreecommitdiffhomepage
path: root/apps/api/ViGet/ViGetCommand.cs
diff options
context:
space:
mode:
authorLeitwolf112026-10-29 09:53:57 +0300
committerLeitwolf112026-10-29 09:53:57 +0300
commit58fa0d19d223aaebf9973ebd446c4bb855351ef9 (patch)
tree6fce1c3d9f2255e80ec92c3040e7280c0ce131ae /apps/api/ViGet/ViGetCommand.cs
parentf22418235a0a87bc05b3bf9079fcdefba002d3b2 (diff)
downloadprogmaweb-58fa0d19d223aaebf9973ebd446c4bb855351ef9.tar.gz
Add the Tazel plugin catalog of ViGet to the API
ViGet opens in stages: first only Progmasoft publishes Tazel plugins, later every account. This adds the catalog and the server-side publishing for the first stage; nothing publishes through the API yet. - ViGet/: the catalog of Tazel plugins (in memory, or in PostgreSQL beside the accounts with its own numbered schema steps), the descriptor read from the JAR (META-INF/tazel-plugin.properties, with a reader of the Java properties format, and the ProjectPlugin service entry), and publishing: the publisher must be in ViGet:TazelPublishers (Progmasoft for now) and an existing account of that exact name, a version is never replaced, names that differ only in letter case are refused, and ViGet needs a description, an author and a license. The JAR is kept at dslplugins/tazel/<Publisher>/<Name>/<Version>/<Name>-<Version>.jar below ViGet:ArtifactRoot. - Read endpoints under /api/v1/viget/dslplugins/tazel: the list, a plugin, and index.json, the index Tazel reads. - 'viget publish-tazel-plugin <jar>' and 'viget yank-tazel-plugin' run with the configuration of the service instead of the service. - The account store can find an account by name. The pages, the Nginx routes and the deployment follow.
Diffstat (limited to 'apps/api/ViGet/ViGetCommand.cs')
-rw-r--r--apps/api/ViGet/ViGetCommand.cs85
1 files changed, 85 insertions, 0 deletions
diff --git a/apps/api/ViGet/ViGetCommand.cs b/apps/api/ViGet/ViGetCommand.cs
new file mode 100644
index 0000000..ad99aee
--- /dev/null
+++ b/apps/api/ViGet/ViGetCommand.cs
@@ -0,0 +1,85 @@
+// SPDX-FileCopyrightText: 2026 Progmasoft <support@progmasoft.com>
+// SPDX-License-Identifier: AGPL-3.0-or-later WITH AdditionRef-Progmasoft-Patent-Grant-1.1
+
+using Npgsql;
+
+namespace Progmasoft.Progmaweb.Api.ViGet;
+
+/// <summary>
+/// The commands that manage the Tazel plugin catalog on the server, while publishing is not open through the API:
+/// <c>viget publish-tazel-plugin &lt;jar&gt;</c> and <c>viget yank-tazel-plugin &lt;Publisher&gt; &lt;Name&gt;
+/// &lt;Version&gt; [--undo]</c>. They run with the configuration of the service, as its user.
+/// </summary>
+internal static class ViGetCommand
+{
+ /// <summary>Whether the arguments of the program ask for a ViGet command rather than the web service.</summary>
+ public static bool IsCommand(string[] args) => args is ["viget", ..];
+
+ /// <summary>Runs a ViGet command.</summary>
+ /// <param name="services">The services of the API, not started.</param>
+ /// <param name="args">The arguments after <c>viget</c>.</param>
+ /// <param name="output">Where results go.</param>
+ /// <param name="errors">Where errors go.</param>
+ /// <param name="cancellationToken">Cancels the command.</param>
+ /// <returns>The exit code: 0 on success, 1 when the command was refused, 2 for a wrong command line.</returns>
+ public static async Task<int> RunAsync(
+ IServiceProvider services,
+ string[] args,
+ TextWriter output,
+ TextWriter errors,
+ CancellationToken cancellationToken)
+ {
+ // The service applies the schema when it starts; a command may run before it ever did.
+ if (services.GetService<NpgsqlDataSource>() is { } dataSource)
+ {
+ await ViGetSchema.ApplyAsync(dataSource, cancellationToken);
+ }
+
+ switch (args)
+ {
+ case ["publish-tazel-plugin", string path]:
+ {
+ if (!File.Exists(path))
+ {
+ await errors.WriteLineAsync($"{path} does not exist.");
+ return 1;
+ }
+
+ TazelPluginPublishing publishing = services.GetRequiredService<TazelPluginPublishing>();
+ PublishResult result = await publishing.PublishAsync(
+ await File.ReadAllBytesAsync(path, cancellationToken), cancellationToken);
+ if (!result.Published)
+ {
+ await errors.WriteLineAsync(result.Error);
+ return 1;
+ }
+
+ TazelPluginDescriptor plugin = result.Plugin!;
+ await output.WriteLineAsync(
+ $"Published {plugin.Publisher}.{plugin.Name} {plugin.Version}: " +
+ $"https://viget.progmasoft.com/dslplugins/tazel/{plugin.Publisher}/{plugin.Name}");
+ return 0;
+ }
+ case ["yank-tazel-plugin", string publisher, string name, string version, .. var rest]
+ when rest is [] or ["--undo"]:
+ {
+ bool yanked = rest is [];
+ ITazelPluginCatalog catalog = services.GetRequiredService<ITazelPluginCatalog>();
+ if (!await catalog.SetYankedAsync(publisher, name, version, yanked, cancellationToken))
+ {
+ await errors.WriteLineAsync($"{publisher}.{name} has no version {version}.");
+ return 1;
+ }
+
+ await output.WriteLineAsync(
+ $"{publisher}.{name} {version} is {(yanked ? "yanked" : "no longer yanked")}.");
+ return 0;
+ }
+ default:
+ await errors.WriteLineAsync(
+ "usage: viget publish-tazel-plugin <jar>\n" +
+ " viget yank-tazel-plugin <Publisher> <Name> <Version> [--undo]");
+ return 2;
+ }
+ }
+}