2024-07-19 19:36:35 +00:00
|
|
|
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
|
|
import os
|
|
|
|
import shutil
|
|
|
|
import subprocess
|
|
|
|
import sys
|
|
|
|
from enum import Enum
|
|
|
|
|
|
|
|
|
|
|
|
class Language(Enum):
|
2024-10-01 19:58:43 +00:00
|
|
|
ANSIBLE = "ansible"
|
|
|
|
BASH = "bash"
|
2024-07-19 19:36:35 +00:00
|
|
|
CSS = "css"
|
|
|
|
DOCKER = "docker"
|
2024-10-01 19:58:43 +00:00
|
|
|
GO = "go"
|
2024-07-19 19:36:35 +00:00
|
|
|
HTML = "html"
|
2024-10-01 19:58:43 +00:00
|
|
|
JAVASCRIPT = "javascript"
|
2024-07-19 19:36:35 +00:00
|
|
|
JSON = "json"
|
2024-10-01 19:58:43 +00:00
|
|
|
KOTLIN = "kotlin"
|
|
|
|
LUA = "lua"
|
|
|
|
NEOVIM = "neovim"
|
|
|
|
PYTHON = "python"
|
|
|
|
RUST = "rust"
|
|
|
|
TERRAFORM = "terraform"
|
|
|
|
TEXT = "text"
|
|
|
|
VIM = "vim"
|
2024-07-19 19:36:35 +00:00
|
|
|
WEB = "web"
|
2024-10-01 19:58:43 +00:00
|
|
|
YAML = "yaml"
|
2024-07-19 19:36:35 +00:00
|
|
|
|
|
|
|
|
2024-11-02 00:03:01 +00:00
|
|
|
META_LANGS: dict[Language, set[Language]] = {
|
|
|
|
Language.NEOVIM: {Language.VIM, Language.LUA},
|
|
|
|
Language.WEB: {Language.CSS, Language.JAVASCRIPT, Language.HTML},
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-07-19 19:36:35 +00:00
|
|
|
def command_exists(command: str) -> bool:
|
|
|
|
return shutil.which(command) is not None
|
|
|
|
|
|
|
|
|
|
|
|
def maybe_run(*args: str) -> bool:
|
|
|
|
if command_exists(args[0]):
|
|
|
|
print("> " + " ".join(args))
|
|
|
|
result = subprocess.run(args)
|
|
|
|
return result.returncode == 0
|
|
|
|
else:
|
|
|
|
print(f"ERROR: {args[0]} does not exist. Could not run {' '.join(args)}")
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def should_install_user(command: str) -> bool:
|
|
|
|
bin_path = shutil.which(command)
|
|
|
|
if not bin_path:
|
|
|
|
return True
|
|
|
|
|
|
|
|
if bin_path.startswith(os.path.expanduser("~")):
|
|
|
|
return True
|
|
|
|
|
|
|
|
print("WARNING: Already installed by system. Skipping installation of", command)
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
|
def maybe_pip_install(*args: str, library=False) -> bool:
|
|
|
|
user_bins = [arg for arg in args if should_install_user(arg)]
|
|
|
|
if not user_bins:
|
|
|
|
return True
|
|
|
|
|
|
|
|
if not library and command_exists("pipx"):
|
2024-11-02 00:03:01 +00:00
|
|
|
return all(
|
|
|
|
[maybe_run("pipx", "upgrade", "--install", bin) for bin in user_bins]
|
|
|
|
)
|
2024-07-19 19:36:35 +00:00
|
|
|
elif command_exists("pip3"):
|
|
|
|
return maybe_run(
|
|
|
|
"pip3",
|
|
|
|
"install",
|
|
|
|
"--user",
|
|
|
|
"--upgrade",
|
|
|
|
"--break-system-packages",
|
|
|
|
*user_bins,
|
|
|
|
)
|
|
|
|
else:
|
|
|
|
return maybe_run(
|
|
|
|
"pip",
|
|
|
|
"install",
|
|
|
|
"--user",
|
|
|
|
"--upgrade",
|
|
|
|
"--break-system-packages",
|
|
|
|
*user_bins,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def maybe_npm_install(*args: str) -> bool:
|
|
|
|
user_bins = [arg for arg in args if should_install_user(arg)]
|
|
|
|
if not user_bins:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return maybe_run("npm", "install", "-g", *user_bins)
|
|
|
|
|
|
|
|
|
2024-11-01 23:42:32 +00:00
|
|
|
def maybe_go_install(**kwargs: str) -> bool:
|
|
|
|
urls = [url for name, url in kwargs.items() if should_install_user(name)]
|
|
|
|
if not urls:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return maybe_run("go", "install", *urls)
|
|
|
|
|
|
|
|
|
|
|
|
def maybe_cargo_install(*args: str) -> bool:
|
|
|
|
user_bins = [arg for arg in args if should_install_user(arg)]
|
|
|
|
if not user_bins:
|
|
|
|
return True
|
|
|
|
|
|
|
|
return maybe_run("cargo", "install", *user_bins)
|
|
|
|
|
|
|
|
|
|
|
|
def maybe_release_gitter(**commands: list[str]) -> bool:
|
|
|
|
command_names = [key for key in commands.keys() if should_install_user(key)]
|
|
|
|
if not command_names:
|
|
|
|
return True
|
|
|
|
|
|
|
|
result = True
|
|
|
|
for command in command_names:
|
|
|
|
args = commands[command]
|
|
|
|
result = result and maybe_run("release-gitter", *args)
|
|
|
|
|
|
|
|
return result
|
|
|
|
|
|
|
|
|
2024-07-19 19:36:35 +00:00
|
|
|
def install_language_servers(langs: set[Language]):
|
|
|
|
if Language.PYTHON in langs:
|
|
|
|
maybe_npm_install("pyright")
|
|
|
|
if Language.RUST in langs:
|
|
|
|
maybe_run(
|
|
|
|
"rustup",
|
|
|
|
"component",
|
|
|
|
"add",
|
|
|
|
"rustfmt",
|
|
|
|
"rust-src",
|
|
|
|
"clippy",
|
|
|
|
"rust-analyzer",
|
|
|
|
)
|
|
|
|
if Language.GO in langs:
|
2024-11-01 23:42:32 +00:00
|
|
|
maybe_go_install(gopls="golang.org/x/tools/gopls@latest")
|
2024-07-19 19:36:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
def install_linters(langs: set[Language]):
|
|
|
|
if Language.PYTHON in langs:
|
|
|
|
maybe_pip_install("mypy")
|
2024-11-02 00:03:01 +00:00
|
|
|
if Language.CSS in langs:
|
2024-07-19 19:36:35 +00:00
|
|
|
maybe_npm_install("csslint")
|
2024-11-02 00:03:01 +00:00
|
|
|
if Language.VIM in langs:
|
2024-07-19 19:36:35 +00:00
|
|
|
maybe_pip_install("vim-vint")
|
|
|
|
if Language.YAML in langs:
|
|
|
|
maybe_pip_install("yamllint")
|
|
|
|
if Language.TEXT in langs:
|
|
|
|
maybe_npm_install("alex", "write-good")
|
|
|
|
maybe_pip_install("proselint")
|
2024-10-01 19:58:43 +00:00
|
|
|
if Language.ANSIBLE in langs:
|
|
|
|
maybe_pip_install("ansible-lint")
|
2024-07-19 19:36:35 +00:00
|
|
|
if Language.GO in langs:
|
2024-11-01 23:42:32 +00:00
|
|
|
# NOTE: Can't use maybe_release_gitter because name has a -
|
2024-07-19 19:36:35 +00:00
|
|
|
maybe_run(
|
|
|
|
"release-gitter",
|
|
|
|
"--git-url",
|
|
|
|
"https://github.com/golangci/golangci-lint",
|
|
|
|
"--extract-all",
|
|
|
|
"--exec",
|
2024-11-01 23:42:32 +00:00
|
|
|
os.path.expanduser(
|
|
|
|
"mv /tmp/$(echo {}|sed s/\\.tar\\.gz$//)/golangci-lint ~/bin/"
|
|
|
|
),
|
2024-07-19 19:36:35 +00:00
|
|
|
"golangci-lint-{version}-{system}-{arch}.tar.gz",
|
|
|
|
"/tmp/",
|
|
|
|
)
|
2024-11-02 00:03:01 +00:00
|
|
|
if Language.LUA in langs:
|
2024-07-19 19:36:35 +00:00
|
|
|
if not maybe_run("lua", "-e", "require('lfs')"):
|
|
|
|
maybe_run("luarocks", "--local", "install", "luafilesystem")
|
|
|
|
maybe_run("luarocks", "--local", "install", "luacheck", "1.1.0")
|
|
|
|
if Language.DOCKER in langs:
|
2024-11-01 23:42:32 +00:00
|
|
|
hadolint_arm64 = "arm64"
|
|
|
|
if sys.platform == "darwin":
|
|
|
|
hadolint_arm64 = "x86_64"
|
|
|
|
maybe_release_gitter(
|
|
|
|
hadolint=[
|
2024-07-19 19:36:35 +00:00
|
|
|
"--git-url",
|
|
|
|
"https://github.com/hadolint/hadolint",
|
|
|
|
"--map-arch",
|
|
|
|
f"aarch64={hadolint_arm64}",
|
|
|
|
"--map-arch",
|
|
|
|
f"arm64={hadolint_arm64}",
|
|
|
|
"--exec",
|
2024-11-01 23:42:32 +00:00
|
|
|
os.path.expanduser(
|
|
|
|
"mv ~/bin/{} ~/bin/hadolint && chmod +x ~/bin/hadolint"
|
|
|
|
),
|
2024-07-19 19:36:35 +00:00
|
|
|
"hadolint-{system}-{arch}",
|
|
|
|
os.path.expanduser("~/bin"),
|
2024-11-01 23:42:32 +00:00
|
|
|
]
|
2024-07-19 19:36:35 +00:00
|
|
|
)
|
2024-11-01 23:42:32 +00:00
|
|
|
if Language.TERRAFORM in langs:
|
|
|
|
maybe_release_gitter(
|
|
|
|
tfsec=[
|
|
|
|
"--git-url",
|
|
|
|
"https://github.com/aquasecurity/tfsec",
|
|
|
|
"--exec",
|
|
|
|
os.path.expanduser("mv ~/bin/{} ~/bin/tfsec && chmod +x ~/bin/tfsec"),
|
|
|
|
"tfsec-{system}-{arch}",
|
|
|
|
os.path.expanduser("~/bin"),
|
|
|
|
],
|
|
|
|
tflint=[
|
|
|
|
"--git-url",
|
|
|
|
"https://github.com/terraform-linters/tflint",
|
|
|
|
"--extract-all",
|
|
|
|
"--exec",
|
|
|
|
os.path.expanduser("chmod +x ~/bin/tflint"),
|
|
|
|
"tflint_{system}_{arch}.zip",
|
|
|
|
os.path.expanduser("~/bin"),
|
|
|
|
],
|
2024-07-19 19:36:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
def install_fixers(langs: set[Language]):
|
|
|
|
if {
|
|
|
|
Language.PYTHON,
|
|
|
|
Language.HTML,
|
|
|
|
Language.CSS,
|
|
|
|
Language.WEB,
|
|
|
|
Language.JSON,
|
2024-11-02 00:03:01 +00:00
|
|
|
} & langs:
|
2024-07-19 19:36:35 +00:00
|
|
|
maybe_npm_install("prettier")
|
|
|
|
if Language.PYTHON in langs:
|
|
|
|
maybe_pip_install("black", "reorder-python-imports", "isort")
|
|
|
|
if Language.RUST in langs:
|
|
|
|
maybe_run("rustup", "component", "add", "rustfmt")
|
2024-11-02 00:03:01 +00:00
|
|
|
if Language.LUA in langs:
|
2024-11-01 23:42:32 +00:00
|
|
|
_ = maybe_release_gitter(
|
|
|
|
stylua=[
|
|
|
|
"--git-url",
|
|
|
|
"https://github.com/JohnnyMorganz/StyLua",
|
|
|
|
"--extract",
|
|
|
|
"stylua",
|
|
|
|
"--exec",
|
|
|
|
os.path.expanduser("chmod +x ~/bin/stylua"),
|
|
|
|
"stylua-{system}-{arch}.zip",
|
|
|
|
os.path.expanduser("~/bin"),
|
|
|
|
]
|
|
|
|
) or maybe_cargo_install("stylua")
|
|
|
|
|
|
|
|
if Language.GO in langs:
|
|
|
|
maybe_go_install(
|
|
|
|
gofumpt="mvdan.cc/gofumpt@latest",
|
|
|
|
goimports="golang.org/x/tools/cmd/goimports@latest",
|
|
|
|
)
|
2024-07-19 19:36:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
def install_debuggers(langs):
|
|
|
|
if Language.PYTHON in langs:
|
2024-10-28 22:42:28 +00:00
|
|
|
maybe_pip_install("debugpy")
|
|
|
|
if Language.GO in langs:
|
2024-11-01 23:42:32 +00:00
|
|
|
maybe_go_install(dlv="github.com/go-delve/delve/cmd/dlv@latest")
|
2024-07-19 19:36:35 +00:00
|
|
|
|
|
|
|
|
|
|
|
def main():
|
|
|
|
parser = argparse.ArgumentParser()
|
|
|
|
parser.add_argument("--ignore-missing", action="store_true")
|
|
|
|
parser.add_argument("langs", nargs="*", type=Language)
|
2024-09-17 19:35:29 +00:00
|
|
|
parser.add_argument("--no-debuggers", action="store_true")
|
2024-07-19 19:36:35 +00:00
|
|
|
args = parser.parse_args()
|
|
|
|
|
|
|
|
maybe_pip_install("release-gitter")
|
|
|
|
|
|
|
|
os.environ["PYTHONPATH"] = ""
|
|
|
|
|
|
|
|
if args.ignore_missing:
|
|
|
|
os.environ["set"] = "+e"
|
|
|
|
else:
|
|
|
|
os.environ["set"] = "-e"
|
|
|
|
|
|
|
|
langs = set(args.langs or Language)
|
|
|
|
|
2024-11-02 00:03:01 +00:00
|
|
|
# Expand meta languages
|
|
|
|
for lang, aliases in META_LANGS.items():
|
|
|
|
if lang in langs:
|
|
|
|
langs.update(aliases)
|
|
|
|
|
2024-07-19 19:36:35 +00:00
|
|
|
|
|
|
|
install_language_servers(langs)
|
|
|
|
install_linters(langs)
|
|
|
|
install_fixers(langs)
|
2024-09-17 19:35:29 +00:00
|
|
|
|
|
|
|
if not args.no_debuggers:
|
|
|
|
install_debuggers(langs)
|
2024-07-19 19:36:35 +00:00
|
|
|
|
|
|
|
print("DONE")
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
main()
|