From f588dd7834f2c10f41846afa933c9a07f0090126 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Sun, 10 Nov 2024 20:43:46 +0100 Subject: [PATCH 01/52] initial cleanup --- .SRCINFO | 17 ----------------- PKGBUILD | 35 ----------------------------------- README.md | 8 +++++--- app.py | 48 +++++++++++++++++++++++++----------------------- install.bat | 12 ------------ install.sh | 14 -------------- requirements.txt | 9 --------- run.bat | 2 -- 8 files changed, 30 insertions(+), 115 deletions(-) delete mode 100644 .SRCINFO delete mode 100644 PKGBUILD delete mode 100644 install.bat delete mode 100644 install.sh delete mode 100644 requirements.txt delete mode 100644 run.bat diff --git a/.SRCINFO b/.SRCINFO deleted file mode 100644 index dbf7678..0000000 --- a/.SRCINFO +++ /dev/null @@ -1,17 +0,0 @@ -pkgbase = kjspkg-git - pkgdesc = A package manager for KubeJS. - pkgver = 1.0 - pkgrel = 1 - url = https://www.github.com/Modern-Modpacks/kjspkg.git - arch = x86_64 - arch = i686 - license = MIT - makedepends = python-pip - makedepends = curl - makedepends = sudo - depends = python - depends = git - source = git+https://www.github.com/Modern-Modpacks/kjspkg.git - md5sums = SKIP - -pkgname = kjspkg-git diff --git a/PKGBUILD b/PKGBUILD deleted file mode 100644 index 222e853..0000000 --- a/PKGBUILD +++ /dev/null @@ -1,35 +0,0 @@ -# Maintainer: G_cat -pkgname=kjspkg-git -pkgver=1.0 -pkgrel=1 -epoch= -pkgdesc="A package manager for KubeJS." -arch=(x86_64 i686) -url="https://www.github.com/Modern-Modpacks/kjspkg.git" -license=('MIT') -groups=() -depends=(python git) -makedepends=(python-pip curl sudo) -checkdepends=() -optdepends=() -provides=() -conflicts=() -replaces=() -backup=() -options=() -install= -changelog= -source=("git+$url") -noextract=() -md5sums=("SKIP") -validpgpkeys=() - -pkgver() { - cd "kjspkg" - git rev-parse --short HEAD -} - -package() { - sudo -v - curl -s https://raw.githubusercontent.com/Modern-Modpacks/kjspkg/main/install.sh | sh -} diff --git a/README.md b/README.md index 716e9e2..57aa6ad 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,9 @@ A simple package manager for KubeJS. ![logo](https://user-images.githubusercontent.com/79367505/227798123-5454e9b1-b39b-4c45-9e02-e18f2e807585.png) -## Installation & Update +_Work in progress_ + + diff --git a/app.py b/app.py index c1935d6..bc227fe 100755 --- a/app.py +++ b/app.py @@ -1,4 +1,6 @@ #!/usr/bin/python3 +print("This file is only here as a reference, please use the go one instead!") +print("Will be removed once the Go one is ready.") # IMPORTS @@ -190,11 +192,11 @@ def _get_mod_version(modpath:str) -> str: def _get_versions() -> list: # Get all mod versions modversions = {} for i in listdir(path.join(getcwd(), "..", "mods")): - if i.endswith(".jar"): + if i.endswith(".jar"): modversion = _get_mod_version(i) if modversion: modversions[_get_modid(i)] = modversion # For each mod file, get the mod version and add the mod id - mod version pair to the dict - return modversions # Return the dict of mod versions + return modversions # Return the dict of mod versions def _get_modid(modpath:str) -> str: # Get mod id from a mod file manifest = _get_mod_manifest(modpath) # Get manifest if manifest==None: return # Return none if not found @@ -204,11 +206,11 @@ def _get_modid(modpath:str) -> str: # Get mod id from a mod file def _get_modids() -> list: # Get all mod ids modids = [] for i in listdir(path.join(getcwd(), "..", "mods")): - if i.endswith(".jar"): + if i.endswith(".jar"): modid = _get_modid(i) if modid: modids.append(modid) # For each mod file, get the mod id and append - return modids # Return the list of modids + return modids # Return the list of modids # def _discord_login(): # Login with discord for discord prefixes # server.HTTPServer(("", 1337), HTTPDiscordLoginRequestHandler).handle_request() @@ -231,7 +233,7 @@ def _pkg_info(pkg:str, ghinfo:bool=True, refresh:bool=True) -> dict: # Get info if prefix=="kjspkg": info = _kjspkginfo(packagename) elif prefix in ("carbon", "carbonjs"): _carbon_err() # info = _carbonpkginfo(packagename) elif prefix in ("github", "external"): info = _githubpkginfo(packagename) - # elif prefix=="discord": + # elif prefix=="discord": # _discord_login() # exit() else: _err("Unknown prefix: "+_bold(prefix)) @@ -252,7 +254,7 @@ def _kjspkginfo(pkg:str) -> dict: # Get info about a default kjspkg pkg branch = repo.split("@")[-1] # Set the branch repo = repo.split("@")[0] # Remove the branch from the repo path = "." - if "$" in repo: + if "$" in repo: path = repo.split("$")[-1] # Set the path repo = repo.split("$")[0] # Remove the path from the repo @@ -275,7 +277,7 @@ def _kjspkginfo(pkg:str) -> dict: # Get info about a default kjspkg pkg # return { # Return formatted info # "author": info["author"], # "description": info["description"], - + # "versions": list(dict.fromkeys([VERSIONS[i] for i in info["minecraftVersion"]])), # "modloaders": info["modloaders"], # "dependencies": [], @@ -289,7 +291,7 @@ def _githubpkginfo(pkg:str) -> dict: # Get dummy info about an external pkg return { "author": pkg.split("/")[0], "description": "", - + "versions": [kjspkgfile["version"]], "modloaders": [kjspkgfile["modloader"]], "dependencies": [], @@ -300,7 +302,7 @@ def _githubpkginfo(pkg:str) -> dict: # Get dummy info about an external pkg } def _move_pkg_contents(pkg:str, tmpdir:str, furtherpath:str): # Move the contents of the pkg to the .kjspkg folders # Find the license - licensefile = path.join(tmpdir, "LICENSE") + licensefile = path.join(tmpdir, "LICENSE") if not path.exists(licensefile): licensefile = path.join(tmpdir, "LICENSE.txt") if not path.exists(licensefile): licensefile = path.join(tmpdir, "LICENSE.md") @@ -325,13 +327,13 @@ def _move_pkg_contents(pkg:str, tmpdir:str, furtherpath:str): # Move the content makedirs(path.sep.join(finalpath.split(path.sep)[:-1]), exist_ok=True) # Create parent dirs move(tmppath, finalpath) # Move it to the permanent dir assetfiles.append(finalpath) # Add it to assetfiles - + kjspkgfile["installed"][pkg] = assetfiles # Add the pkg to installed def _install_pkg(pkg:str, update:bool, quiet:bool, skipmissing:bool, reload:bool, *, _depmode:bool=False): # Install the pkg if not update and _format_github(pkg) in kjspkgfile["installed"]: # If the pkg is already installed and the update parameter is false, notify the user and just return if not quiet: print(_bold(f"Package \"{pkg}\" already installed ✓")) return - if update: + if update: if pkg=="*": # If updating all packages for p in list(kjspkgfile["installed"].keys()): _install_pkg(p, True, quiet, skipmissing, reload, _depmode=True) # Update all packages return @@ -339,7 +341,7 @@ def _install_pkg(pkg:str, update:bool, quiet:bool, skipmissing:bool, reload:bool _remove_pkg(pkg, False) # If update is true, remove the previous version of the pkg package = _pkg_info(pkg, False, reload) # Get pkg - if not package and reload: + if not package and reload: _reload_pkgs() # Reload if not found package = _pkg_info(pkg, False, reload) # Try to get the pkg again @@ -359,10 +361,10 @@ def _install_pkg(pkg:str, update:bool, quiet:bool, skipmissing:bool, reload:bool if (("dependencies" in package.keys() and any([i.startswith("mod:") for i in package["dependencies"]])) or ("incompatibilities" in package.keys() and any([i.startswith("mod:") for i in package["incompatibilities"]]))): modids = _get_modids() # Get a list of all mod ids if "dependencies" in package.keys(): - for dep in package["dependencies"]: + for dep in package["dependencies"]: if dep.lower().startswith("mod:") and _remove_prefix(dep.lower()) not in modids: _err(f"Mod \"{_remove_prefix(dep.replace('_', ' ').replace('-', ' ')).title()}\" not found.") # Check for mod dependency elif not dep.lower().startswith("mod:"): _install_pkg(dep.lower(), dep.lower() in kjspkgfile["installed"], quiet, skipmissing, reload) # Install/update package dependency - if "incompatibilities" in package.keys(): + if "incompatibilities" in package.keys(): for i in package["incompatibilities"]: if i.lower().startswith("mod:") and _remove_prefix(i.lower()) in modids: _err(f"Incompatible mod: "+_remove_prefix(i.replace('_', ' ').replace('-', ' ')).title()) # Check for mod incompats elif i in kjspkgfile["installed"].keys(): _err(f"Incompatible package: "+i) # Throw err if incompats detected @@ -383,7 +385,7 @@ def _install_pkg(pkg:str, update:bool, quiet:bool, skipmissing:bool, reload:bool loadthread.terminate() # Kill the loading animation if pkg=="*": print(_bold(f"All packages updated succesfully! ✓")) # Show message if all packages are updated else: print(_bold(f"Package \"{_format_github(pkg)}\" {'installed' if not update else 'updated'} succesfully! ✓")) # Show message if one package is installed/updated - + def _remove_pkg(pkg:str, skipmissing:bool): # Remove the pkg if pkg not in kjspkgfile["installed"].keys(): if not skipmissing: _err(f"Package \"{pkg}\" is not installed") # If the pkg is not installed, err @@ -417,7 +419,7 @@ def install(*pkgs:str, update:bool=False, quiet:bool=False, skipmissing:bool=Fal if update and pkg not in kjspkgfile["installed"].keys() and not skipmissing and pkg!="*": _err(f"Package \"{_format_github(pkg)}\" not found") # Err if package not found during update _install_pkg(pkg, update, quiet, skipmissing, reload) # Install package - + def removepkg(*pkgs:str, quiet:bool=False, skipmissing:bool=False): # Remove pkgs for pkg in pkgs: pkg = _remove_prefix(pkg.lower()) @@ -499,7 +501,7 @@ def fetch(*, logo:bool=True, script:bool=False): # Fetch data about the project # Prepare it to look pretty datastr = _bold(f"KJSPKG@{getcwd()}\n") longeststr = len(max(data.keys(), key=len))+1 - for k,v in data.items(): datastr += f"{_purple(k)}{' '*(longeststr-len(k))}{v}\n" + for k,v in data.items(): datastr += f"{_purple(k)}{' '*(longeststr-len(k))}{v}\n" selectedlogo = LOGO if logo else "" # Print it (pretty) @@ -568,7 +570,7 @@ def init(*, quiet:bool=False, override:bool=False, cancreate:str=None, **configa with open(".kjspkg", "w+") as f: dump(kjspkgfile, f) # Create .kjspkg file if not quiet: print(_bold("Project created!")) # Woo! def uninit(*, confirm:bool=False): # Remove the project - if confirm or input("\u001b[31;1mDOING THIS WILL REMOVE ALL PACKAGES AND UNINSTALL KJSPKG COMPLETELY, ARE YOU SURE YOU WANT TO PROCEED? (y/N): \u001b[0m").lower()=="y": + if confirm or input("\u001b[31;1mDOING THIS WILL REMOVE ALL PACKAGES AND UNINSTALL KJSPKG COMPLETELY, ARE YOU SURE YOU WANT TO PROCEED? (y/N): \u001b[0m").lower()=="y": _delete_project() print("\u001b[31;1mProject deleted\u001b[0m") else: print(_bold("Aborted.")) @@ -711,14 +713,14 @@ def devdist(description:str=None, author:str=None, dependencies:list=None, incom if name.startswith("kjspkg_"): # If the file starts with kjspkg_ makedirs(path.join(distdir, dirpath), exist_ok=True) # Create parents copy(path.join(dirpath, name), path.join(distdir, dirpath, name.removeprefix("kjspkg_"))) # Copy it - + # Write .kjspkg manifest if generatemanifest: with open(path.join(distdir, ".kjspkg"), "w+") as f: dump({ "author": author, "description": description, - + "versions": versions, "modloaders": modloaders, "dependencies": dependencies, @@ -877,7 +879,7 @@ def kombucha(): # Kombucha easter egg The kombucha is ready to drink immediately, or you can start a ‘secondary fermentation’ by adding flavours such as fruit, herbs and spices to the drawn-off liquid and leaving it bottled for a few more days before drinking. Will keep in the fridge for up to three months. """ print(RECIPE) - + # PARSER FUNCTION def _parser(func:str="help", *args, help:bool=False, **kwargs): global kjspkgfile @@ -933,7 +935,7 @@ def _parser(func:str="help", *args, help:bool=False, **kwargs): } if func not in FUNCTIONS.keys(): _err(f"Command \"{func}\" is not found. Run \"kjspkg {'dev ' if devparser else ''}help\" to see all of the available commands") # Wrong command err - + if not devparser: # Skip the .kjspkg file stuff if the parser is the dev parser helperfuncs = (info, guiinfo, init, pkginfo, listall, search, kombucha) # Helper commands that don't require a project if FUNCTIONS[func] not in helperfuncs and not _project_exists(): # If a project is not found, call init @@ -960,4 +962,4 @@ def _parser(func:str="help", *args, help:bool=False, **kwargs): _clear_tmp() # Remove tmp again -# Ok that's it bye \ No newline at end of file +# Ok that's it bye diff --git a/install.bat b/install.bat deleted file mode 100644 index c597429..0000000 --- a/install.bat +++ /dev/null @@ -1,12 +0,0 @@ -@echo off - -def %localappdata%\Microsoft\WindowsApps\kjspkg >nul 2>&1 -def %localappdata%\Microsoft\WindowsApps\kjspkg.py >nul 2>&1 -curl https://raw.githubusercontent.com/Modern-Modpacks/kjspkg/main/run.bat > %localappdata%\Microsoft\WindowsApps\kjspkg.bat -curl https://raw.githubusercontent.com/Modern-Modpacks/kjspkg/main/app.py > %localappdata%\Microsoft\WindowsApps\kjspkg.py - -curl -s https://raw.githubusercontent.com/Modern-Modpacks/kjspkg/main/requirements.txt > kjspkgreqs.txt -python -m pip -q install -r kjspkgreqs.txt >nul 2>&1 -del kjspkgreqs.txt - -msg "%username%" "KJSPKG install successful! Reload your terminal for the command to work" diff --git a/install.sh b/install.sh deleted file mode 100644 index 45613cc..0000000 --- a/install.sh +++ /dev/null @@ -1,14 +0,0 @@ -if [ `id -u` != 0 ] -then - sudo -v -fi - -echo "Installation started..." - -sudo rm -f /usr/local/bin/kjspkg - -sudo sh -c "curl -s https://raw.githubusercontent.com/Modern-Modpacks/kjspkg/main/app.py > /usr/local/bin/kjspkg" -python3 -m pip -q install $(curl -s https://raw.githubusercontent.com/Modern-Modpacks/kjspkg/main/requirements.txt) > /dev/null -sudo chmod +x /usr/local/bin/kjspkg - -echo "Done!" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 3aa7122..0000000 --- a/requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -fire -requests -psutil -GitPython -thefuzz -python-Levenshtein -toml -esprima -flatten_json \ No newline at end of file diff --git a/run.bat b/run.bat deleted file mode 100644 index bab7735..0000000 --- a/run.bat +++ /dev/null @@ -1,2 +0,0 @@ -@echo off -python %~dp0\kjspkg.py %* \ No newline at end of file From 5d5bc1ec140588df2a18d4ddaf72c73203a4d4d4 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Wed, 13 Nov 2024 23:34:37 +0100 Subject: [PATCH 02/52] okay this is a huge mess, gcast trust the process :3 --- .gitignore | 2 + README.md | 2 + app.py | 4 +- cmd/kjspkg/c.go | 15 ++++ cmd/kjspkg/c_dev_run.go | 31 ++++++++ cmd/kjspkg/c_fetch.go | 51 +++++++++++++ cmd/kjspkg/c_init.go | 60 +++++++++++++++ cmd/kjspkg/c_install.go | 76 +++++++++++++++++++ cmd/kjspkg/c_list.go | 48 ++++++++++++ cmd/kjspkg/c_listall.go | 24 ++++++ cmd/kjspkg/c_pkg.go | 49 ++++++++++++ cmd/kjspkg/c_remove.go | 46 ++++++++++++ cmd/kjspkg/c_uninit.go | 51 +++++++++++++ cmd/kjspkg/c_update.go | 57 ++++++++++++++ cmd/kjspkg/main.go | 64 ++++++++++++++++ cmd/kjspkg/utils.go | 43 +++++++++++ go.mod | 41 ++++++++++ go.sum | 98 ++++++++++++++++++++++++ pkg/kjspkg/collect.go | 103 +++++++++++++++++++++++++ pkg/kjspkg/config.go | 29 ++++++++ pkg/kjspkg/configfs.go | 55 ++++++++++++++ pkg/kjspkg/directories.go | 19 +++++ pkg/kjspkg/install.go | 153 ++++++++++++++++++++++++++++++++++++++ pkg/kjspkg/modlist.go | 101 +++++++++++++++++++++++++ pkg/kjspkg/pkg.go | 107 ++++++++++++++++++++++++++ pkg/kjspkg/pkglist.go | 140 ++++++++++++++++++++++++++++++++++ pkg/kjspkg/remove.go | 27 +++++++ pkg/kjspkg/utils.go | 42 +++++++++++ pkg/kjspkg/versions.go | 23 ++++++ 29 files changed, 1559 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 cmd/kjspkg/c.go create mode 100644 cmd/kjspkg/c_dev_run.go create mode 100644 cmd/kjspkg/c_fetch.go create mode 100644 cmd/kjspkg/c_init.go create mode 100644 cmd/kjspkg/c_install.go create mode 100644 cmd/kjspkg/c_list.go create mode 100644 cmd/kjspkg/c_listall.go create mode 100644 cmd/kjspkg/c_pkg.go create mode 100644 cmd/kjspkg/c_remove.go create mode 100644 cmd/kjspkg/c_uninit.go create mode 100644 cmd/kjspkg/c_update.go create mode 100644 cmd/kjspkg/main.go create mode 100644 cmd/kjspkg/utils.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 pkg/kjspkg/collect.go create mode 100644 pkg/kjspkg/config.go create mode 100644 pkg/kjspkg/configfs.go create mode 100644 pkg/kjspkg/directories.go create mode 100644 pkg/kjspkg/install.go create mode 100644 pkg/kjspkg/modlist.go create mode 100644 pkg/kjspkg/pkg.go create mode 100644 pkg/kjspkg/pkglist.go create mode 100644 pkg/kjspkg/remove.go create mode 100644 pkg/kjspkg/utils.go create mode 100644 pkg/kjspkg/versions.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1b0580b --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +kubejs +mods diff --git a/README.md b/README.md index 57aa6ad..c120774 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ A simple package manager for KubeJS. _Work in progress_ +**The Go API exposed at github.com/Modern-Modpacks/kjspkg/pkg/kjspkg is not stable. It is not recommended to use it just yet.** + -## Usage + -Removing packages: - -```sh -kjspkg remove [package] [package] -``` +### Using Go -Updating packages: +This requires a working Go installation of at least 1.23.2. ```sh -kjspkg update [package] [package] +go install github.com/Modern-Modpacks/kjspkg/cmd/kjspkg@latest ``` -More info in the help page: +## Usage + +KJSPKG comes with extensive help text, so you can just run `kjspkg` to see all +the commands and options available. You may also use `--help` after any command +to get more information about it. ```sh -kjspkg help +kjspkg install [package] [package] +kjspkg remove [package] [package] +kjspkg update [package] [package] ``` ## Adding your own package @@ -100,8 +96,6 @@ kjspkg help ![Version list](https://github.com/user-attachments/assets/5a3b8e3a-bd91-456e-8443-bbffa894a38f) -(Thanks tizu.dev on discord for the figma template) - Tested means that the version is confirmed to be working; Not tested means that the version should work, but hasn't been tested. Feel free to test it yourself and let us know so we'll update the readme. @@ -112,4 +106,4 @@ Partial support means that the version is supported, but not as much as the full No support means that the version works, but any issues that you have with it won't be fixed. -Borked means it doesn't work lmao. --> +Borked means it doesn't work lmao. From 80346b20abb4ae635348e502ffc5c5a7f15c5edd Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Sun, 17 Nov 2024 21:13:48 +0100 Subject: [PATCH 39/52] feat:misc/installation-scripts --- install.ps1 | 24 ++++++++++++++++++++++++ install.sh | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+) create mode 100755 install.ps1 create mode 100755 install.sh diff --git a/install.ps1 b/install.ps1 new file mode 100755 index 0000000..b3174e2 --- /dev/null +++ b/install.ps1 @@ -0,0 +1,24 @@ +$INFO = "::" +$WARN = "::" + +Write-Host "$INFO Getting ready" + +$REPO = "Modern-Modpacks/kjspkg" +$LATEST_RELEASE_URL = (Invoke-RestMethod -Uri "https://api.github.com/repos/$REPO/releases/latest").assets | Where-Object { $_.browser_download_url -like "*kjspkg_windows_amd64.exe" } | Select-Object -ExpandProperty browser_download_url + +if (-not $LATEST_RELEASE_URL) { + Write-Host "$WARN Failed to fetch the latest release. Please check your internet connection!" + exit 1 +} + +Write-Host "$INFO Downloading KJSPKG" +$installPath = "$env:LOCALAPPDATA\Microsoft\WindowsApps" + +try { + Invoke-WebRequest -Uri $LATEST_RELEASE_URL -OutFile "$installPath\kjspkg.exe" +} catch { + Write-Host "$WARN Download failed. Please try again." + exit 1 +} + +Write-Host "$INFO Done! Run 'kjspkg' to get started" diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..7fd6630 --- /dev/null +++ b/install.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +INFO="\033[34m::\033[0m" +WARN="\033[33m::\033[0m" + +if [ "$(id -u)" != 0 ]; then + echo -e "$INFO Escalation is required to install KJSPKG globally" + sudo -v + if [ $? -ne 0 ]; then + echo -e "$WARN Failed to escalate privileges. Please run the script again." + exit 1 + fi +fi + +echo -e "$INFO Getting ready" + +REPO="Modern-Modpacks/kjspkg" +LATEST_RELEASE_URL=$(curl -s "https://api.github.com/repos/$REPO/releases/latest" | grep -oP '"browser_download_url": "\K[^"]*kjspkg_linux_amd64') +if [ -z "$LATEST_RELEASE_URL" ]; then + echo -e "$WARN Failed to fetch the latest release. Please check your internet connection!" + exit 1 +fi + +echo -e "$INFO Downloading KJSPKG" +sudo curl --progress-bar -L -o /usr/local/bin/kjspkg "$LATEST_RELEASE_URL" | cat +if [ $? -ne 0 ]; then + echo -e "$WARN Download failed. Please try again." + exit 1 +fi + +sudo chmod +x /usr/local/bin/kjspkg +echo -e "$INFO Done! Run \`kjspkg\` to get started" From 7830eb90d60550324435792ca30f65e33c446782 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Sun, 17 Nov 2024 21:43:17 +0100 Subject: [PATCH 40/52] feat:misc/readme-updates --- README.md | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 77f23da..9ad7738 100644 --- a/README.md +++ b/README.md @@ -61,20 +61,8 @@ kjspkg update [package] [package] 1. Create a repository containing your scripts and assets 2. [Don't forget to license your code](https://choosealicense.com/) -3. Add a file to your repo named `.kjspkg` and format it like this: - - ```json - { - "author": "", - "description": "", - - "versions": [], - "modloaders": [. Can contain multiple modloaders], - "dependencies": [], - "incompatibilities": [] - } - ``` - +3. Create an empty directory and run `kjspkg dev init` +4. Do your thing and create a repository with the code 4. Fork this repo 5. Clone it 6. Add your package to `pkgs.json` file. Format it like this: `"your_package_id": "your_github_name/your_repo_name[$path/to/your/package/directory][@branch_name]",` @@ -83,6 +71,7 @@ kjspkg update [package] [package] * Branch is `main` by default 7. Create a pull request 8. Wait for it to be accepted +9. profit ### KJSPKG badges From 491dfe62d89e4a910823e6cecbcbb9c55753b96d Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Sun, 17 Nov 2024 22:23:54 +0100 Subject: [PATCH 41/52] fix:misc/install-bash-consistency --- install.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install.sh b/install.sh index 7fd6630..942b228 100755 --- a/install.sh +++ b/install.sh @@ -29,4 +29,4 @@ if [ $? -ne 0 ]; then fi sudo chmod +x /usr/local/bin/kjspkg -echo -e "$INFO Done! Run \`kjspkg\` to get started" +echo -e "$INFO Done! Run 'kjspkg' to get started" From 92124e8ac60eb9fa7a3487632ba49353b6aadb88 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:55:06 +0100 Subject: [PATCH 42/52] fix:cli/gcast-fix-verbose-flag --- cmd/kjspkg/c_install.go | 2 +- cmd/kjspkg/c_pkg.go | 6 ++++-- cmd/kjspkg/utils.go | 15 +++++++++++++-- pkg/kjspkg/install.go | 15 ++++++++++----- 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/cmd/kjspkg/c_install.go b/cmd/kjspkg/c_install.go index 7f79fb8..0eb82e8 100644 --- a/cmd/kjspkg/c_install.go +++ b/cmd/kjspkg/c_install.go @@ -59,7 +59,7 @@ func (c *CInstall) Run(ctx *Context) error { for _, ref := range toInstall { errs.Go(func() error { startTime := time.Now() - assets, err := kjspkg.Install(ctx.Path, ref, cfg, c.Update) + assets, err := kjspkg.Install(ctx.Path, ref, cfg, c.Update, If(ctx.Verbose, os.Stdout, nil)) tookTime := time.Since(startTime).Milliseconds() fmt.Printf(colr.Green(" +")+" %s "+colr.Dim("(took %dms)\n"), ref.Id, tookTime) cfg.Installed[ref.Id] = assets diff --git a/cmd/kjspkg/c_pkg.go b/cmd/kjspkg/c_pkg.go index 78959a2..de304b4 100644 --- a/cmd/kjspkg/c_pkg.go +++ b/cmd/kjspkg/c_pkg.go @@ -43,7 +43,6 @@ func (c *CPkg) Run(ctx *Context) error { return nil } - fmt.Printf("\n") fmt.Printf(colr.Bold(colr.Blue("%s"))+" by "+colr.Blue("%s")+"\n", commons.TitleCase(c.Package), pkg.Author) fmt.Printf("%s\n", pkg.Description) fmt.Printf("\n") @@ -51,7 +50,10 @@ func (c *CPkg) Run(ctx *Context) error { fmt.Printf(colr.Blue("GitHub:")+" %s\n", loc.URLFrontend()) fmt.Printf(colr.Blue("Views:")+" %-6d "+colr.Blue("Downloads:")+" %-6d\n", pkg.Views, pkg.Downloads) fmt.Printf("\n") - fmt.Printf(colr.Blue("Available for:")+" %s on %s\n", strings.Join(loaders, ", "), strings.Join(versions, ", ")) + fmt.Printf(colr.Blue("Available for:") + "\n") + fmt.Printf(colr.Blue(" Modloaders:")+" %s\n", strings.Join(loaders, ", ")) + fmt.Printf(colr.Blue(" Versions:")+" %s\n", strings.Join(versions, ", ")) + fmt.Printf("\n") fmt.Printf(colr.Blue("Dependencies:")+" %s\n", kjspkg.DepsJoin(pkg.Dependencies)) fmt.Printf(colr.Blue("Incompatibilities:")+" %s\n", kjspkg.DepsJoin(pkg.Incompatibilities)) diff --git a/cmd/kjspkg/utils.go b/cmd/kjspkg/utils.go index a6bfb4c..90bda08 100644 --- a/cmd/kjspkg/utils.go +++ b/cmd/kjspkg/utils.go @@ -27,14 +27,18 @@ func remove[T comparable](slice []T, s int) []T { func LoadLocators() (map[string]kjspkg.PackageLocator, error) { var packages map[string]kjspkg.PackageLocator packages, err := kjspkg.GetPackageList() - info("Parsed package list") + if cli.Verbose { + info("Parsed package list") + } return packages, err } func LoadPackage(ref kjspkg.PackageLocator, withStats bool) (kjspkg.Package, error) { var pkg kjspkg.Package pkg, err := kjspkg.GetPackage(ref, withStats) - info("Obtained package metadata") + if cli.Verbose { + info("Obtained package metadata") + } return pkg, err } @@ -55,3 +59,10 @@ func LoadPackageById(id string, withStats bool) (kjspkg.Package, kjspkg.PackageL pkg, err = LoadPackage(loc, withStats) return pkg, loc, err } + +func If[T any](cond bool, a, b T) T { + if cond { + return a + } + return b +} diff --git a/pkg/kjspkg/install.go b/pkg/kjspkg/install.go index 3b2410b..2a42bc6 100644 --- a/pkg/kjspkg/install.go +++ b/pkg/kjspkg/install.go @@ -3,6 +3,7 @@ package kjspkg import ( "fmt" + "io" "io/fs" "os" "os/exec" @@ -16,7 +17,7 @@ import ( // This will also update/reinstall packages that have already been installed. // If mass is provided, some actions won't be done that may cause other concurrent // install calls to fail, like deleting the tmp directory. -func Install(path string, loc PackageLocator, cfg *Config, mass bool) ([]string, error) { +func Install(path string, loc PackageLocator, cfg *Config, mass bool, stdout io.Writer) ([]string, error) { if !mass { os.RemoveAll(filepath.Join(path, "tmp")) } @@ -31,13 +32,13 @@ func Install(path string, loc PackageLocator, cfg *Config, mass bool) ([]string, return nil, err } - err = InstallClone(path, loc) + err = InstallClone(path, loc, stdout) if err != nil { return nil, err } if loc.Branch == nil { - err = InstallBranch(path, loc) + err = InstallBranch(path, loc, stdout) if err != nil { return nil, err } @@ -81,7 +82,7 @@ func InstallDiscardExisting(path string, loc PackageLocator, cfg *Config) error return Remove(path, loc.Id, cfg) } -func InstallClone(path string, loc PackageLocator) error { +func InstallClone(path string, loc PackageLocator, stdout io.Writer) error { err := os.MkdirAll(filepath.Join(path, "tmp", loc.Id), 0744) if err != nil { return err @@ -89,13 +90,15 @@ func InstallClone(path string, loc PackageLocator) error { cmd := exec.Command("git", "clone", loc.URLBase(), loc.Id) cmd.Dir = filepath.Join(path, "tmp") + cmd.Stdout = stdout + cmd.Stderr = stdout if err := cmd.Start(); err != nil { return err } return cmd.Wait() } -func InstallBranch(path string, loc PackageLocator) error { +func InstallBranch(path string, loc PackageLocator, stdout io.Writer) error { if loc.Branch == nil { return nil } @@ -103,6 +106,8 @@ func InstallBranch(path string, loc PackageLocator) error { // TODO: migrate to 'git switch' cmd := exec.Command("git", "checkout", *loc.Branch) cmd.Dir = filepath.Join(path, "tmp", loc.Id) + cmd.Stdout = stdout + cmd.Stderr = stdout return cmd.Run() } From 307236ab6e784d0eb64bbfddf307e01ddf7c73e6 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Thu, 21 Nov 2024 15:59:56 +0100 Subject: [PATCH 43/52] fix:cli/gcast-fix-uninit-yesno --- cmd/kjspkg/c_uninit.go | 8 +++++++- cmd/kjspkg/selectors.go | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/cmd/kjspkg/c_uninit.go b/cmd/kjspkg/c_uninit.go index 6c0cb70..c9e9693 100644 --- a/cmd/kjspkg/c_uninit.go +++ b/cmd/kjspkg/c_uninit.go @@ -18,7 +18,13 @@ type CUninit struct { func (c *CUninit) Run(ctx *Context) error { if !c.Confirm { warn(colr.Red("DOING THIS WILL REMOVE ALL PACKAGES AND UNINSTALL KJSPKG COMPLETELY!")) - return fmt.Errorf("please use --confirm to continue") + confirm := false + if err := NewConfirm("Are you sure?", "You can't undo this, which may cause data loss!", &confirm, false); err != nil { + return err + } + if !confirm { + return fmt.Errorf("aborted") + } } cfg, err := kjspkg.GetConfig(ctx.Path, true) diff --git a/cmd/kjspkg/selectors.go b/cmd/kjspkg/selectors.go index 4f7e7aa..619f590 100644 --- a/cmd/kjspkg/selectors.go +++ b/cmd/kjspkg/selectors.go @@ -80,6 +80,19 @@ func NewMultiSelect[T comparable]( return sel.WithTheme(huh.ThemeBase16()).Run() } +// NewConfirm is a wrapper function that displays a confirmation prompt. +func NewConfirm(title string, description string, selected *bool, askIf bool) error { + if !askIf == *selected { + return nil + } + return huh.NewConfirm(). + Title(title). + Description(description). + Value(selected). + WithTheme(huh.ThemeBase16()). + Run() +} + // NewInput is a wrapper function that displays a selection prompt only if // the provided variable isn't empty and can be validated. func NewInput( From ee3e858a4303feb5d6d6a2b95d8f64c5cee15dbd Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:16:04 +0100 Subject: [PATCH 44/52] fix:cli/gcast-fix-always-mass-install --- cmd/kjspkg/c_install.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kjspkg/c_install.go b/cmd/kjspkg/c_install.go index 0eb82e8..2b737df 100644 --- a/cmd/kjspkg/c_install.go +++ b/cmd/kjspkg/c_install.go @@ -59,7 +59,7 @@ func (c *CInstall) Run(ctx *Context) error { for _, ref := range toInstall { errs.Go(func() error { startTime := time.Now() - assets, err := kjspkg.Install(ctx.Path, ref, cfg, c.Update, If(ctx.Verbose, os.Stdout, nil)) + assets, err := kjspkg.Install(ctx.Path, ref, cfg, true, If(ctx.Verbose, os.Stdout, nil)) tookTime := time.Since(startTime).Milliseconds() fmt.Printf(colr.Green(" +")+" %s "+colr.Dim("(took %dms)\n"), ref.Id, tookTime) cfg.Installed[ref.Id] = assets From e2a7a458333a234b4e4914434ad269881f5f1d0f Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Thu, 21 Nov 2024 16:19:08 +0100 Subject: [PATCH 45/52] fix:cli/gcast-fix-no-cfg-error --- pkg/kjspkg/configfs.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/kjspkg/configfs.go b/pkg/kjspkg/configfs.go index 06aaaa0..2478bef 100644 --- a/pkg/kjspkg/configfs.go +++ b/pkg/kjspkg/configfs.go @@ -24,7 +24,7 @@ func GetConfig(path string, noKubeOk bool) (*Config, error) { } if _, err := os.Stat(configFilePath); os.IsNotExist(err) { - return nil, fmt.Errorf(".kjspkg file not found") + return nil, fmt.Errorf("no KJSPKG instance, use 'init' to create one") } data, err := os.ReadFile(configFilePath) From 2d1697a4f8a5bd11a2657495442ba913a06a0a97 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:07:04 +0100 Subject: [PATCH 46/52] fix:cli/gcast-fix-init-version-order --- cmd/kjspkg/c_init.go | 6 +++--- pkg/kjspkg/config.go | 7 +++++++ pkg/kjspkg/versions.go | 1 + 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cmd/kjspkg/c_init.go b/cmd/kjspkg/c_init.go index 0c5f448..f7d4152 100644 --- a/cmd/kjspkg/c_init.go +++ b/cmd/kjspkg/c_init.go @@ -23,8 +23,8 @@ func (c *CInit) Run(ctx *Context) error { cfg := kjspkg.DefaultConfig() err := NewSelect("Pick a game version", func(opts *[]huh.Option[int]) { - for display, id := range kjspkg.Versions { - *opts = append(*opts, huh.NewOption(display, id)) + for _, ver := range kjspkg.VersionsInOrder { + *opts = append(*opts, huh.NewOption(ver, kjspkg.Versions[ver])) } }, &c.Version, "") if err != nil { @@ -35,7 +35,7 @@ func (c *CInit) Run(ctx *Context) error { err = NewSelect("Pick a mod loader", func(opts *[]huh.Option[kjspkg.ModLoader]) { for _, loader := range kjspkg.ModLoaders { - *opts = append(*opts, huh.NewOption(loader.String(), loader)) + *opts = append(*opts, huh.NewOption(loader.StringLong(), loader)) } }, &c.Modloader, "") if err != nil { diff --git a/pkg/kjspkg/config.go b/pkg/kjspkg/config.go index 022c767..70b39ab 100644 --- a/pkg/kjspkg/config.go +++ b/pkg/kjspkg/config.go @@ -14,11 +14,18 @@ type ModLoader string func (s ModLoader) String() string { return commons.TitleCase(string(s)) } +func (s ModLoader) StringLong() string { + return ModLoadersLong[s] +} func (s ModLoader) Identifier() string { return string(s) } var ModLoaders = []ModLoader{MLForge, MLFabric} +var ModLoadersLong = map[ModLoader]string{ + MLForge: "Forge/NeoForge", + MLFabric: "Fabric/Quilt", +} const ( MLForge ModLoader = "forge" diff --git a/pkg/kjspkg/versions.go b/pkg/kjspkg/versions.go index b7b7277..71dc27f 100644 --- a/pkg/kjspkg/versions.go +++ b/pkg/kjspkg/versions.go @@ -4,6 +4,7 @@ import ( "strconv" ) +var VersionsInOrder = []string{"1.12", "1.16", "1.18", "1.19", "1.20", "1.21"} var Versions = map[string]int{ "1.12": 2, "1.16": 6, From ab6e0df5734e36b5eeba6f4bee776d8179bfad85 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:15:15 +0100 Subject: [PATCH 47/52] fix:cli/gcast-fix-mod-check-oopsies --- pkg/kjspkg/collect.go | 2 +- pkg/kjspkg/modlist.go | 14 +++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/pkg/kjspkg/collect.go b/pkg/kjspkg/collect.go index ec13ccd..2075e2e 100644 --- a/pkg/kjspkg/collect.go +++ b/pkg/kjspkg/collect.go @@ -64,7 +64,7 @@ func CollectPackages(refs map[string]PackageLocator, cfg *Config, id string, tru } } else if mods != nil { dep = strings.TrimPrefix(dep, "mod:") - if _, ok := mods[dep]; ok { + if _, ok := mods[dep]; !ok { return nil, fmt.Errorf("%s requires mod %s, but not found", ref.Id, dep) } } diff --git a/pkg/kjspkg/modlist.go b/pkg/kjspkg/modlist.go index e22704e..3b497cc 100644 --- a/pkg/kjspkg/modlist.go +++ b/pkg/kjspkg/modlist.go @@ -37,9 +37,7 @@ func GetMods(path string, modlessOk bool, corruptedOk bool) (map[string]string, } defer r.Close() - var modID, modVersion string var foundManifest bool - for _, f := range r.File { forgeLike, fabricLike := strings.HasSuffix(f.Name, "mods.toml"), strings.HasSuffix(f.Name, ".mod.json") if forgeLike || fabricLike { @@ -66,8 +64,9 @@ func GetMods(path string, modlessOk bool, corruptedOk bool) (map[string]string, continue } if len(manifest.Mods) > 0 { - modID = manifest.Mods[0].ModId - modVersion = manifest.Mods[0].Version + for _, mod := range manifest.Mods { + modVersions[mod.ModId] = mod.Version + } foundManifest = true } } else if fabricLike { @@ -82,16 +81,13 @@ func GetMods(path string, modlessOk bool, corruptedOk bool) (map[string]string, } continue } - modID = manifest.ID - modVersion = manifest.Version + modVersions[manifest.ID] = manifest.Version foundManifest = true } } } - if foundManifest { - modVersions[modID] = modVersion - } else if !corruptedOk { + if !foundManifest && !corruptedOk { return nil, fmt.Errorf("manifest not found in mod file %s", file.Name()) } } From d54bf895a042a74b5be28f9c1b90a7f436717e7c Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Sat, 23 Nov 2024 09:36:23 +0100 Subject: [PATCH 48/52] fix:cli/gcast-fix-update-saying-install --- cmd/kjspkg/c_install.go | 9 +++++++-- cmd/kjspkg/c_update.go | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cmd/kjspkg/c_install.go b/cmd/kjspkg/c_install.go index 2b737df..8f9e266 100644 --- a/cmd/kjspkg/c_install.go +++ b/cmd/kjspkg/c_install.go @@ -18,6 +18,7 @@ type CInstall struct { NoModCheck bool `help:"If mod dependency check should be skipped"` Skipmissing bool `help:"Skips dependencies that can't be found"` Update bool `help:"If packages already downloaded should be updated (same as 'update')"` + NoInstall bool `help:"If new packages should not be installed (requires --update)" hidden:""` } func (c *CInstall) Run(ctx *Context) error { @@ -26,6 +27,10 @@ func (c *CInstall) Run(ctx *Context) error { return err } + if c.NoInstall && !c.Update { + return fmt.Errorf("--no-install requires --update") + } + refs, err := LoadLocators() // this caches them if err != nil { return err @@ -54,7 +59,7 @@ func (c *CInstall) Run(ctx *Context) error { } errs, _ := errgroup.WithContext(context.Background()) - info("Installing") + info(If(c.NoInstall, "Updating", "Installing")) os.RemoveAll(filepath.Join(ctx.Path, "tmp")) for _, ref := range toInstall { errs.Go(func() error { @@ -71,7 +76,7 @@ func (c *CInstall) Run(ctx *Context) error { } os.RemoveAll(filepath.Join(ctx.Path, "tmp")) - info("Successfully installed %d package(s)!", len(toInstall)) + info("Successfully %s %d package(s)!", If(c.NoInstall, "updated", "installed"), len(toInstall)) kjspkg.SetConfig(ctx.Path, cfg) return nil } diff --git a/cmd/kjspkg/c_update.go b/cmd/kjspkg/c_update.go index 37880d0..6084e12 100644 --- a/cmd/kjspkg/c_update.go +++ b/cmd/kjspkg/c_update.go @@ -40,6 +40,7 @@ func (c *CUpdate) Run(ctx *Context) error { NoModCheck: c.NoModCheck, Skipmissing: c.Skipmissing, Update: true, + NoInstall: true, } return cmd.Run(ctx) } From c58717f6c0b95afb8ab156b85ecc5b6f1def2b4c Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Mon, 25 Nov 2024 18:41:04 +0100 Subject: [PATCH 49/52] fix: cli: handle noinstall properly --- cmd/kjspkg/c_install.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmd/kjspkg/c_install.go b/cmd/kjspkg/c_install.go index 8f9e266..a8c875b 100644 --- a/cmd/kjspkg/c_install.go +++ b/cmd/kjspkg/c_install.go @@ -53,6 +53,11 @@ func (c *CInstall) Run(ctx *Context) error { return err } for dep, loc := range list { + if c.NoInstall { + if _, ok := cfg.Installed[dep]; !ok { + return fmt.Errorf("package %s is not installed", dep) + } + } toInstall[dep] = loc fmt.Printf(colr.Dim(" >")+" %s\n", loc.Id) } From 30f73d0de707e03026c2e7823ff014b7686628e7 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Mon, 25 Nov 2024 19:56:05 +0100 Subject: [PATCH 50/52] fix: cli: handle noinstall properly the second, maybe, maybe not, i didnt test this --- cmd/kjspkg/c_install.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmd/kjspkg/c_install.go b/cmd/kjspkg/c_install.go index a8c875b..f5155dc 100644 --- a/cmd/kjspkg/c_install.go +++ b/cmd/kjspkg/c_install.go @@ -54,8 +54,8 @@ func (c *CInstall) Run(ctx *Context) error { } for dep, loc := range list { if c.NoInstall { - if _, ok := cfg.Installed[dep]; !ok { - return fmt.Errorf("package %s is not installed", dep) + if _, ok := cfg.Installed[loc.Id]; !ok { + return fmt.Errorf("package %s is not installed", loc.Id) } } toInstall[dep] = loc From 50f8d355b15d115595b6ff0a8c6e52d43e0483b2 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:01:26 +0100 Subject: [PATCH 51/52] feat: cli: env var to set --source --- cmd/kjspkg/main.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/kjspkg/main.go b/cmd/kjspkg/main.go index 6d2035e..b127051 100644 --- a/cmd/kjspkg/main.go +++ b/cmd/kjspkg/main.go @@ -66,6 +66,10 @@ func main() { if cli.Quiet { os.Stdout.Close() } + + if os.Getenv("KJSPKG_REPO") != "" { + kjspkg.PackageList = os.Getenv("KJSPKG_REPO") + } if cli.Source != "" { kjspkg.PackageList = cli.Source } From 89c7b8f86ab99d5c000b69884b52cb444aad1c19 Mon Sep 17 00:00:00 2001 From: tizu69 <60812901+tizu69@users.noreply.github.com> Date: Mon, 25 Nov 2024 20:03:31 +0100 Subject: [PATCH 52/52] fix: cli: docs: document the env var --- cmd/kjspkg/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/kjspkg/main.go b/cmd/kjspkg/main.go index b127051..6cef6f7 100644 --- a/cmd/kjspkg/main.go +++ b/cmd/kjspkg/main.go @@ -26,7 +26,7 @@ var cli struct { Verbose bool `help:"Print verbose"` Quiet bool `help:"No non-error output" short:"q" hidden:""` Path string `help:"Path to KubeJS directory (defaults to current)" default:"." type:"existingdir"` - Source string `help:"URL source to package list" type:"url"` + Source string `help:"URL source to package list (takes preference over KJSPKG_REPO envvar)" type:"url"` Install CInstall `cmd:"" help:"Installs packages" aliases:"download"` Remove CRemove `cmd:"" help:"Removes packages" aliases:"uninstall"`