All Downloads are FREE. Search and download functionalities are using the official Maven repository.

dev.jbang.cli.Alias Maven / Gradle / Ivy

There is a newer version: 0.121.0
Show newest version
package dev.jbang.cli;

import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import dev.jbang.Settings;
import dev.jbang.catalog.Alias.JavaAgent;
import dev.jbang.catalog.Catalog;
import dev.jbang.catalog.CatalogUtil;
import dev.jbang.source.Project;
import dev.jbang.source.ProjectBuilder;
import dev.jbang.source.ResourceRef;
import dev.jbang.util.ConsoleOutput;
import dev.jbang.util.Util;

import picocli.CommandLine;

@CommandLine.Command(name = "alias", description = "Manage aliases for scripts.", subcommands = { AliasAdd.class,
		AliasList.class, AliasRemove.class })
public class Alias {
}

abstract class BaseAliasCommand extends BaseCommand {

	@CommandLine.Option(names = { "--global", "-g" }, description = "Use the global (user) catalog file")
	boolean global;

	@CommandLine.Option(names = { "--file", "-f" }, description = "Path to the catalog file to use")
	Path catalogFile;

	protected Path getCatalog(boolean strict) {
		Path cat;
		if (global) {
			cat = Settings.getUserCatalogFile();
		} else {
			if (catalogFile != null && Files.isDirectory(catalogFile)) {
				Path defaultCatalog = catalogFile.resolve(Catalog.JBANG_CATALOG_JSON);
				Path hiddenCatalog = catalogFile.resolve(Settings.JBANG_DOT_DIR).resolve(Catalog.JBANG_CATALOG_JSON);
				if (!Files.exists(defaultCatalog) && Files.exists(hiddenCatalog)) {
					cat = hiddenCatalog;
				} else {
					cat = defaultCatalog;
				}
			} else {
				cat = catalogFile;
			}
			if (strict && cat != null && !Files.isRegularFile(cat)) {
				throw new IllegalArgumentException("Catalog file not found at: " + catalogFile);
			}
		}
		return cat;
	}
}

@CommandLine.Command(name = "add", description = "Add alias for script reference.")
class AliasAdd extends BaseAliasCommand {

	@CommandLine.Mixin
	ScriptMixin scriptMixin;

	@CommandLine.Mixin
	BuildMixin buildMixin;

	@CommandLine.Mixin
	DependencyInfoMixin dependencyInfoMixin;

	@CommandLine.Mixin
	NativeMixin nativeMixin;

	@CommandLine.Mixin
	RunMixin runMixin;

	@CommandLine.Option(names = { "--description" }, description = "A description for the alias")
	String description;

	@CommandLine.Option(names = { "--name" }, description = "A name for the alias")
	String name;

	@CommandLine.Option(names = {
			"--force" }, description = "Force overwriting of existing alias")
	boolean force;

	@CommandLine.Option(names = { "--enable-preview" }, description = "Activate Java preview features")
	Boolean enablePreviewRequested;

	@CommandLine.Parameters(paramLabel = "params", index = "1..*", arity = "0..*", description = "Parameters to pass on to the script")
	List userParams;

	@Override
	public Integer doCall() {
		scriptMixin.validate();
		if (name != null && !Catalog.isValidName(name)) {
			throw new IllegalArgumentException(
					"Invalid alias name, it should start with a letter followed by 0 or more letters, digits, underscores or hyphens");
		}

		ProjectBuilder pb = createProjectBuilder();
		Project prj = pb.build(scriptMixin.scriptOrFile);
		if (name == null) {
			name = CatalogUtil.nameFromRef(scriptMixin.scriptOrFile);
		}

		String desc = description != null ? description : prj.getDescription().orElse(null);

		dev.jbang.catalog.Alias alias = new dev.jbang.catalog.Alias(scriptMixin.scriptOrFile, desc, userParams,
				runMixin.javaRuntimeOptions, scriptMixin.sources, scriptMixin.resources,
				dependencyInfoMixin.getDependencies(),
				dependencyInfoMixin.getRepositories(), dependencyInfoMixin.getClasspaths(),
				dependencyInfoMixin.getProperties(), buildMixin.javaVersion, buildMixin.main, buildMixin.module,
				buildMixin.compileOptions, nativeMixin.nativeImage, nativeMixin.nativeOptions,
				runMixin.flightRecorderString, runMixin.debugString, runMixin.cds, runMixin.interactive,
				enablePreviewRequested,
				runMixin.enableAssertions, runMixin.enableSystemAssertions, buildMixin.manifestOptions,
				createJavaAgents(), null);
		Path catFile = getCatalog(false);
		if (catFile == null) {
			catFile = Catalog.getCatalogFile(null);
		}
		if (force || !CatalogUtil.hasAlias(catFile, name)) {
			CatalogUtil.addAlias(catFile, name, alias);
		} else {
			Util.infoMsg("A script with name '" + name + "' already exists, use '--force' to add anyway.");
			return EXIT_INVALID_INPUT;
		}
		info(String.format("Alias '%s' added to '%s'", name, catFile));
		return EXIT_OK;
	}

	ProjectBuilder createProjectBuilder() {
		ProjectBuilder pb = Project
									.builder()
									.setProperties(dependencyInfoMixin.getProperties())
									.additionalDependencies(dependencyInfoMixin.getDependencies())
									.additionalRepositories(dependencyInfoMixin.getRepositories())
									.additionalClasspaths(dependencyInfoMixin.getClasspaths())
									.additionalSources(scriptMixin.sources)
									.additionalResources(scriptMixin.resources)
									.forceType(scriptMixin.forceType)
									.javaVersion(buildMixin.javaVersion)
									.moduleName(buildMixin.module)
									.compileOptions(buildMixin.compileOptions)
									.nativeImage(nativeMixin.nativeImage)
									.nativeOptions(nativeMixin.nativeOptions)
									.enablePreview(enablePreviewRequested);
		Path cat = getCatalog(false);
		if (cat != null) {
			pb.catalog(cat.toFile());
		}
		return pb;
	}

	private List createJavaAgents() {
		if (runMixin.javaAgentSlots == null) {
			return Collections.emptyList();
		}
		return runMixin.javaAgentSlots	.entrySet()
										.stream()
										.map(e -> new JavaAgent(e.getKey(), e.getValue()))
										.collect(Collectors.toList());
	}
}

@CommandLine.Command(name = "list", description = "Lists locally defined aliases or from the given catalog.")
class AliasList extends BaseAliasCommand {

	@CommandLine.Option(names = { "--show-origin" }, description = "Show the origin of the alias")
	boolean showOrigin;

	@CommandLine.Parameters(paramLabel = "catalogName", index = "0", description = "The name of a catalog", arity = "0..1")
	String catalogName;

	@CommandLine.Mixin
	FormatMixin formatMixin;

	private static final int INDENT_SIZE = 3;

	@Override
	public Integer doCall() {
		PrintStream out = System.out;
		Catalog catalog;
		Path cat = getCatalog(true);
		if (catalogName != null) {
			catalog = Catalog.getByName(catalogName);
		} else if (cat != null) {
			catalog = Catalog.get(cat);
		} else {
			catalog = Catalog.getMerged(true, false);
		}
		if (showOrigin) {
			printAliasesWithOrigin(out, catalogName, catalog, formatMixin.format);
		} else {
			printAliases(out, catalogName, catalog, formatMixin.format);
		}
		return EXIT_OK;
	}

	static void printAliases(PrintStream out, String catalogName, Catalog catalog, FormatMixin.Format format) {
		List aliases = catalog.aliases
												.keySet()
												.stream()
												.sorted()
												.map(name -> getAliasOut(catalogName, catalog, name))
												.collect(Collectors.toList());

		if (format == FormatMixin.Format.json) {
			Gson parser = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
			parser.toJson(aliases, out);
		} else {
			aliases.forEach(a -> printAlias(out, a, 0));
		}
	}

	static List getAliasesWithOrigin(String catalogName, Catalog catalog) {
		Map> groups = catalog.aliases
																	.keySet()
																	.stream()
																	.sorted()
																	.map(name -> getAliasOut(catalogName, catalog,
																			name))
																	.collect(Collectors.groupingBy(
																			a -> a._catalogRef));
		return groups	.entrySet()
						.stream()
						.map(e -> new CatalogList.CatalogOut(null, e.getKey(),
								e.getValue(), null, null))
						.collect(Collectors.toList());
	}

	static void printAliasesWithOrigin(PrintStream out, String catalogName, Catalog catalog,
			FormatMixin.Format format) {
		List catalogs = getAliasesWithOrigin(catalogName, catalog);
		if (format == FormatMixin.Format.json) {
			Gson parser = new GsonBuilder().disableHtmlEscaping().setPrettyPrinting().create();
			parser.toJson(catalogs, out);
		} else {
			catalogs.forEach(cat -> {
				out.println(ConsoleOutput.bold(dev.jbang.catalog.Catalog.simplifyRef(cat.resourceRef)));
				cat.aliases.forEach(a -> printAlias(out, a, 1));
			});
		}
	}

	static class AliasOut {
		public String name;
		public String catalogName;
		public String fullName;
		public String scriptRef;
		public String description;
		public List arguments;
		public String javaVersion;
		public String mainClass;
		public List javaOptions;
		public Map properties;
		public transient ResourceRef _catalogRef;
		public Boolean enablePreview;
	}

	private static AliasOut getAliasOut(String catalogName, Catalog catalog, String name) {
		dev.jbang.catalog.Alias alias = catalog.aliases.get(name);
		String catName = catalogName != null ? Catalog.simplifyRef(catalogName) : CatalogUtil.catalogRef(name);
		String fullName = catalogName != null ? name + "@" + catName : name;
		String scriptRef = alias.scriptRef;
		if (!catalog.aliases.containsKey(scriptRef)
				&& !Catalog.isValidCatalogReference(scriptRef)) {
			scriptRef = alias.resolve();
		}

		AliasOut out = new AliasOut();
		out.name = name;
		out.catalogName = catName;
		out.fullName = fullName;
		out.scriptRef = scriptRef;
		out.description = alias.description;
		out.arguments = alias.arguments;
		out.javaVersion = alias.javaVersion;
		out.mainClass = alias.mainClass;
		out.javaOptions = alias.runtimeOptions;
		out.properties = alias.properties;
		out._catalogRef = alias.catalog.catalogRef;
		out.enablePreview = alias.enablePreview;
		return out;
	}

	private static void printAlias(PrintStream out, AliasOut alias, int indent) {
		String prefix1 = Util.repeat(" ", indent * INDENT_SIZE);
		String prefix2 = Util.repeat(" ", (indent + 1) * INDENT_SIZE);
		String prefix3 = Util.repeat(" ", (indent + 2) * INDENT_SIZE);
		out.println(prefix1 + dev.jbang.cli.CatalogList.getColoredFullName(alias.fullName));
		if (alias.description != null) {
			out.println(prefix2 + alias.description);
		}
		out.println(prefix2 + ConsoleOutput.faint(alias.scriptRef));
		if (alias.arguments != null) {
			out.println(prefix3 + ConsoleOutput.cyan("   Arguments: ") + String.join(" ", alias.arguments));
		}
		if (alias.javaVersion != null) {
			out.println(prefix3 + ConsoleOutput.cyan("   Java Version: ") + alias.javaVersion);
		}
		if (alias.mainClass != null) {
			out.println(prefix3 + ConsoleOutput.cyan("   Main Class: ") + alias.mainClass);
		}
		if (alias.enablePreview != null) {
			out.println(prefix3 + ConsoleOutput.cyan("   Enable Preview: ") + alias.enablePreview);
		}
		if (alias.javaOptions != null) {
			out.println(prefix3 + ConsoleOutput.cyan("   Java Options: ") + String.join(" ", alias.javaOptions));
		}
		if (alias.properties != null) {
			out.println(prefix3 + ConsoleOutput.magenta("   Properties: ") + alias.properties);
		}
	}
}

@CommandLine.Command(name = "remove", description = "Remove existing alias.")
class AliasRemove extends BaseAliasCommand {

	@CommandLine.Parameters(paramLabel = "name", index = "0", description = "The name of the alias", arity = "1")
	String name;

	@Override
	public Integer doCall() {
		final Path cat = getCatalog(true);
		if (cat != null) {
			CatalogUtil.removeAlias(cat, name);
		} else {
			CatalogUtil.removeNearestAlias(name);
		}
		return EXIT_OK;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy