Initial commit: 50 shell-script generators with web UI

- 8 categories / 50 generators covering middleware, databases, runtimes,
  systemd services, system tools, network, monitoring, security
- VNC supports XFCE / GNOME / KDE Plasma / MATE / LXQt desktops
- Node.js versions 18-26 (incl. current LTS 24 Krypton and current 26)
- Live preview, copy / download / multi-script bundle in web UI
- Distro-aware (Ubuntu/Debian/CentOS/RHEL/Rocky/Alma/Fedora)
- All 50 generators pass bash -n syntax check
- Zero pip dependencies (Flask stdlib only)
This commit is contained in:
cnbug
2026-08-04 00:36:35 +08:00
commit 319f683a16
17 changed files with 4177 additions and 0 deletions
+651
View File
@@ -0,0 +1,651 @@
"""
Runtime / language / compiler version installers.
Each generator supports multiple versions and uses source build for exotic versions
when no distro package is available.
"""
from . import register, Generator, Field
from . import bash_header, quote, bool_str, yes
# ========================== Python (pyenv-style from source) ==========================
class Python(Generator):
id = "python"
title = "Python 任意版本 (源码编译)"
category = "runtimes"
icon = "🐍"
tags = ["python", "pyenv", "source"]
description = "从 python.org 下载源码编译,支持 2.7 / 3.6 - 3.13 任意版本,启用 SSL/zlib/sqlite3。"
warnings = [
"源码编译会下载 ~25MB,编译 5-15 分钟,需要 build-essential。",
"建议先运行 gcc 编译器安装脚本(同分类)以保证编译依赖。",
]
fields = [
Field("version", "Python 版本", "select", default="3.12.6",
options=["2.7.18", "3.6.15", "3.7.17", "3.8.20", "3.9.20",
"3.10.14", "3.11.11", "3.12.6", "3.13.0", "3.13.1"]),
Field("install_dir", "安装目录", "text", default="/opt/python",
help="最终路径 = $install_dir/$version (如 /opt/python/3.12.6)"),
Field("enable_optimizations", "启用 PGO/LTO (慢但快 ~10%)", "checkbox", default="yes"),
Field("shared", "编译为 .so 共享库", "checkbox", default="no",
help="如果其他工具(如 mod_wsgi)需要动态链接则开启。"),
Field("install_pip", "安装 pip", "checkbox", default="yes"),
Field("symlink_bin", "软链 bin 目录到 PATH", "checkbox", default="no",
help="yes = 软链 /opt/python/$version/bin/* 到 /usr/local/bin/"),
Field("ssl_backend", "SSL 后端", "select", default="openssl",
options=["openssl", "libressl"]),
]
def render(self, p):
ver = p.get("version", "3.12.6")
d = p.get("install_dir", "/opt/python")
opt = " --enable-optimizations" if bool_str(p.get("enable_optimizations", True)) else ""
shared = " --enable-shared" if bool_str(p.get("shared")) else ""
ssl = p.get("ssl_backend", "openssl")
sym = bool_str(p.get("symlink_bin"))
pip = bool_str(p.get("install_pip", True))
out = [bash_header(self.title)]
out.append('log "Installing Python ' + ver + ' from source..."')
out.append('command -v gcc >/dev/null || $PKG_INSTALL gcc make build-essential \\\n'
' libssl-dev zlib1g-dev libbz2-dev libreadline-dev libsqlite3-dev \\\n'
' libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev \\\n'
' || $PKG_INSTALL gcc make openssl-devel bzip2-devel libffi-devel zlib-devel \\\n'
' readline-devel sqlite-devel ncurses-devel xz-devel')
out.append('cd /tmp')
out.append('curl -fsSL -o Python.tgz https://www.python.org/ftp/python/' + ver + '/Python-' + ver + '.tgz')
out.append('tar -xzf Python.tgz')
out.append('cd Python-' + ver)
cfg = ('./configure --prefix=' + d + '/' + ver +
' --with-ensurepip=install' if pip else './configure --prefix=' + d + '/' + ver + ' --without-ensurepip')
cfg += opt + shared
if ssl == "libressl":
cfg += ' --with-openssl=/usr/local'
out.append(cfg)
out.append('make -j"$(nproc)"')
out.append('make altinstall')
out.append('cd /tmp && rm -rf Python-' + ver + ' Python.tgz')
out.append('')
out.append('PYBIN=' + d + '/' + ver + '/bin/python' + '.'.join(ver.split('.')[:2]))
if sym:
out.append('log "Symlinking binaries to /usr/local/bin/..."')
out.append('for b in ' + d + '/' + ver + '/bin/*; do\n'
' ln -sf "$b" /usr/local/bin/"$(basename "$b")" || true\n'
'done')
out.append('log "Verifying..."')
out.append('$PYBIN --version')
if pip:
out.append('$PYBIN -m pip --version || $PYBIN -m ensurepip --upgrade')
return "\n".join(out) + "\n"
# ========================== Node.js (nvm-style from binary) ==========================
class NodeJS(Generator):
id = "nodejs"
title = "Node.js 任意版本 (官方二进制)"
category = "runtimes"
icon = "🟢"
tags = ["nodejs", "node", "npm"]
description = "从 nodejs.org 下载预编译二进制,可选装 yarn / pnpm / nvm。"
fields = [
Field("version", "Node 版本", "select", default="24",
options=["18", "20", "22", "24", "26"]),
Field("install_dir", "安装目录", "text", default="/opt/nodejs"),
Field("symlink_bin", "软链 bin 目录", "checkbox", default="yes"),
Field("install_yarn", "安装 yarn", "checkbox", default="yes"),
Field("install_pnpm", "安装 pnpm", "checkbox", default="yes"),
Field("npm_registry", "NPM Registry", "text",
default="https://registry.npmmirror.com",
help="默认走国内镜像,留空 = 官方。"),
]
def render(self, p):
ver = p.get("version", "20")
d = p.get("install_dir", "/opt/nodejs")
sym = bool_str(p.get("symlink_bin", True))
yarn = bool_str(p.get("install_yarn", True))
pnpm = bool_str(p.get("install_pnpm", True))
reg = p.get("npm_registry", "https://registry.npmmirror.com")
out = [bash_header(self.title)]
out.append('log "Installing Node.js v' + ver + '..."')
out.append('cd /tmp')
out.append('curl -fsSL -o node.tar.xz https://nodejs.org/dist/v' + ver + '.x/node-v' + ver + '.x-linux-x64.tar.xz')
out.append('rm -rf ' + d)
out.append('mkdir -p ' + d)
out.append('tar -xJf node.tar.xz --strip-components=1 -C ' + d)
out.append('rm -f node.tar.xz')
if sym:
out.append('for b in ' + d + '/bin/*; do ln -sf "$b" /usr/local/bin/"$(basename "$b")"; done')
if reg:
out.append('npm config set registry ' + quote(reg))
if yarn:
out.append('npm install -g yarn')
if pnpm:
out.append('npm install -g pnpm')
out.append('node --version')
out.append('npm --version')
return "\n".join(out) + "\n"
# ========================== GCC (from source) ==========================
class GCC(Generator):
id = "gcc"
title = "GCC 任意版本 (源码编译)"
category = "runtimes"
icon = "🛠️"
tags = ["gcc", "compiler", "source"]
description = "从 gcc.gnu.org 下载源码,编译并安装到 /opt/gcc-<ver>。"
warnings = [
"GCC 12+ 编译需 30-60 分钟,需要约 5GB 磁盘。",
"建议另装 'system gcc' (apt/yum) 留作系统默认,本工具不替换系统 gcc。",
]
fields = [
Field("version", "GCC 版本", "select", default="13.2.0",
options=["8.5.0", "9.5.0", "10.5.0", "11.4.0", "12.3.0",
"13.2.0", "14.1.0"]),
Field("languages", "支持语言", "text", default="c,c++,fortran",
help="逗号分隔,如 c,c++,objc,fortran,go"),
Field("install_dir", "安装目录", "text", default="/opt/gcc",
help="最终 = $install_dir/<ver>"),
Field("enable_lto", "启用 LTO (慢但快 ~10%)", "checkbox", default="no"),
Field("enable_libsan", "启用 Sanitizers (ASan/TSan)", "checkbox", default="no"),
Field("make_jobs", "make -j 任务数", "text", default="$(nproc)",
help="默认 = CPU 核数,改小可降低内存峰值。"),
]
def render(self, p):
ver = p.get("version", "13.2.0")
langs = p.get("languages", "c,c++,fortran")
d = p.get("install_dir", "/opt/gcc")
lto = " --enable-lto" if bool_str(p.get("enable_lto")) else ""
libsan = " --enable-libsanitizer" if bool_str(p.get("enable_libsan")) else ""
jobs = p.get("make_jobs", "$(nproc)")
out = [bash_header(self.title)]
out.append('log "Installing GCC ' + ver + ' from source..."')
out.append('$PKG_INSTALL wget gcc gcc-c++ make texinfo bison flex')
out.append('cd /tmp')
out.append('curl -fsSL -O https://ftp.gnu.org/gnu/gcc/gcc-' + ver + '/gcc-' + ver + '.tar.xz')
out.append('tar -xJf gcc-' + ver + '.tar.xz')
out.append('cd gcc-' + ver)
out.append('./contrib/download_prerequisites')
out.append('mkdir -p build && cd build')
out.append('../configure --prefix=' + d + '/' + ver +
' --enable-languages=' + langs +
' --disable-multilib --with-system-zlib' + lto + libsan)
out.append('make -j' + jobs)
out.append('make install')
out.append('cd /tmp && rm -rf gcc-' + ver + ' gcc-' + ver + '.tar.xz build')
out.append('log "Verifying..."')
out.append(d + '/' + ver + '/bin/gcc --version')
out.append('echo "Add to PATH: export PATH=' + d + '/' + ver + '/bin:$PATH"')
return "\n".join(out) + "\n"
# ========================== Make ==========================
class Make(Generator):
id = "make"
title = "GNU Make 任意版本 (源码编译)"
category = "runtimes"
icon = "🔨"
tags = ["make", "build", "gnu"]
description = "从 gnu.org 下载 make 源码并安装到 /opt。"
fields = [
Field("version", "Make 版本", "select", default="4.4.1",
options=["4.2.1", "4.3", "4.4", "4.4.1"]),
Field("install_dir", "安装目录", "text", default="/opt/make"),
]
def render(self, p):
ver = p.get("version", "4.4.1")
d = p.get("install_dir", "/opt/make")
out = [bash_header(self.title)]
out.append('log "Installing make ' + ver + '..."')
out.append('$PKG_INSTALL gcc make')
out.append('cd /tmp')
out.append('curl -fsSL -O https://ftp.gnu.org/gnu/make/make-' + ver + '.tar.gz')
out.append('tar -xzf make-' + ver + '.tar.gz')
out.append('cd make-' + ver)
out.append('./configure --prefix=' + d + '/' + ver)
out.append('make -j"$(nproc)"')
out.append('make install')
out.append('cd /tmp && rm -rf make-' + ver + ' make-' + ver + '.tar.gz')
out.append(d + '/' + ver + '/bin/make --version')
return "\n".join(out) + "\n"
# ========================== CMake ==========================
class CMake(Generator):
id = "cmake"
title = "CMake 任意版本 (官方脚本安装)"
category = "runtimes"
icon = "🧱"
tags = ["cmake", "build", "makefile"]
description = "从 cmake.org 下载官方二进制,安装到 /opt。"
fields = [
Field("version", "CMake 版本", "select", default="3.30.0",
options=["3.20.0", "3.22.0", "3.24.0", "3.25.0", "3.26.0",
"3.27.0", "3.28.0", "3.29.0", "3.30.0"]),
Field("install_dir", "安装目录", "text", default="/opt/cmake"),
Field("symlink_bin", "软链到 /usr/local/bin", "checkbox", default="yes"),
]
def render(self, p):
ver = p.get("version", "3.30.0")
d = p.get("install_dir", "/opt/cmake")
sym = bool_str(p.get("symlink_bin", True))
out = [bash_header(self.title)]
out.append('log "Installing CMake ' + ver + '..."')
out.append('cd /tmp')
out.append('curl -fsSL -O https://github.com/Kitware/CMake/releases/download/v' + ver + '/cmake-' + ver + '-linux-x86_64.tar.gz')
out.append('rm -rf ' + d)
out.append('mkdir -p ' + d)
out.append('tar -xzf cmake-' + ver + '-linux-x86_64.tar.gz --strip-components=1 -C ' + d)
out.append('rm -f cmake-' + ver + '-linux-x86_64.tar.gz')
if sym:
out.append('for b in ' + d + '/bin/*; do ln -sf "$b" /usr/local/bin/"$(basename "$b")"; done')
out.append('cmake --version')
return "\n".join(out) + "\n"
# ========================== Go ==========================
class GoLang(Generator):
id = "golang"
title = "Go 任意版本 (官方二进制)"
category = "runtimes"
icon = "🐹"
tags = ["go", "golang"]
description = "从 go.dev 下载 Go 官方二进制,设置 GOPROXY 国内镜像。"
fields = [
Field("version", "Go 版本", "select", default="1.22.5",
options=["1.18.10", "1.19.13", "1.20.14", "1.21.12", "1.22.5", "1.23.0"]),
Field("install_dir", "安装目录", "text", default="/opt/go"),
Field("goproxy", "GOPROXY", "text", default="https://goproxy.cn,direct",
help="默认 goproxy.cn,留空 = GOPROXY=off"),
Field("symlink_bin", "软链到 /usr/local/bin", "checkbox", default="yes"),
]
def render(self, p):
ver = p.get("version", "1.22.5")
d = p.get("install_dir", "/opt/go")
proxy = p.get("goproxy", "https://goproxy.cn,direct")
sym = bool_str(p.get("symlink_bin", True))
out = [bash_header(self.title)]
out.append('log "Installing Go ' + ver + '..."')
out.append('cd /tmp')
out.append('curl -fsSL -O https://go.dev/dl/go' + ver + '.linux-amd64.tar.gz')
out.append('rm -rf ' + d)
out.append('tar -C ' + d.rsplit('/', 1)[0] + ' -xzf go' + ver + '.linux-amd64.tar.gz')
out.append('mv ' + d.rsplit('/', 1)[0] + '/go ' + d)
out.append('rm -f go' + ver + '.linux-amd64.tar.gz')
if sym:
out.append('for b in ' + d + '/bin/*; do ln -sf "$b" /usr/local/bin/"$(basename "$b")"; done')
if proxy:
out.append('go env -w GOPROXY=' + quote(proxy))
out.append('go env -w GOSUMDB=sum.golang.google.cn')
out.append('go version')
out.append('echo "Add to PATH: export PATH=' + d + '/bin:$PATH"')
return "\n".join(out) + "\n"
# ========================== OpenJDK ==========================
class Java(Generator):
id = "java"
title = "OpenJDK 任意版本 (官方二进制)"
category = "runtimes"
icon = ""
tags = ["java", "jdk", "openjdk"]
description = "从 Adoptium 仓库下载 OpenJDK 预编译版本,无需 apt 仓库。"
fields = [
Field("version", "JDK 版本", "select", default="21",
options=["8", "11", "17", "21"]),
Field("install_dir", "安装目录", "text", default="/opt/jdk"),
Field("symlink_bin", "软链到 /usr/local/bin", "checkbox", default="yes"),
]
def render(self, p):
ver = p.get("version", "21")
d = p.get("install_dir", "/opt/jdk")
sym = bool_str(p.get("symlink_bin", True))
out = [bash_header(self.title)]
out.append('log "Installing OpenJDK ' + ver + '..."')
out.append('cd /tmp')
out.append('curl -fsSL -o jdk.tar.gz "https://download.java.net/java/GA/jdk' + ver + '.0.2/f2283984656d49d69e91c558476027ac/13/GPL/openjdk-' + ver + '.0.2_linux-x64_bin.tar.gz"')
out.append('rm -rf ' + d)
out.append('mkdir -p ' + d)
out.append('tar -xzf jdk.tar.gz --strip-components=1 -C ' + d)
out.append('rm -f jdk.tar.gz')
if sym:
out.append('update-alternatives --install /usr/bin/java java ' + d + '/bin/java 9999 || true')
out.append('update-alternatives --install /usr/bin/javac javac ' + d + '/bin/javac 9999 || true')
out.append('for b in ' + d + '/bin/*; do ln -sf "$b" /usr/local/bin/"$(basename "$b")"; done')
out.append('export JAVA_HOME=' + d)
out.append(d + '/bin/java --version')
out.append('echo "Add to PATH: export PATH=' + d + '/bin:$PATH"')
return "\n".join(out) + "\n"
# ========================== PHP ==========================
class PHP(Generator):
id = "php"
title = "PHP 任意版本 (源码编译)"
category = "runtimes"
icon = "🐘"
tags = ["php", "apache", "nginx", "fpm"]
description = "从 php.net 编译 PHP,启用 fpm、常用扩展。"
fields = [
Field("version", "PHP 版本", "select", default="8.3.10",
options=["7.4.33", "8.0.30", "8.1.29", "8.2.22", "8.3.10"]),
Field("install_dir", "安装目录", "text", default="/opt/php"),
Field("enable_fpm", "启用 PHP-FPM", "checkbox", default="yes"),
Field("extensions", "编译扩展", "text",
default="mysqli,pdo,pdo_mysql,gd,mbstring,curl,xml,zip,intl,opcache,bcmath"),
]
def render(self, p):
ver = p.get("version", "8.3.10")
d = p.get("install_dir", "/opt/php")
fpm = bool_str(p.get("enable_fpm", True))
exts = p.get("extensions", "mysqli,pdo,pdo_mysql,gd,mbstring,curl,xml,zip,intl,opcache,bcmath")
out = [bash_header(self.title)]
out.append('log "Installing PHP ' + ver + ' from source..."')
out.append('$PKG_INSTALL gcc make libxml2-dev libssl-dev libcurl4-openssl-dev \\\n'
' libonig-dev libzip-dev libicu-dev libsqlite3-dev libpng-dev libjpeg-dev \\\n'
' libfreetype6-dev libwebp-dev libxslt1-dev libreadline-dev 2>/dev/null \\\n'
' || $PKG_INSTALL gcc make libxml2-devel openssl-devel libcurl-devel \\\n'
' libonig-devel libzip-devel libicu-devel sqlite-devel libpng-devel \\\n'
' libjpeg-devel freetype-devel libwebp-devel libxslt-devel readline-devel')
out.append('cd /tmp')
out.append('curl -fsSL -O https://www.php.net/distributions/php-' + ver + '.tar.gz')
out.append('tar -xzf php-' + ver + '.tar.gz')
out.append('cd php-' + ver)
cfg = './configure --prefix=' + d + '/' + ver
cfg += ' --with-config-file-path=' + d + '/' + ver + '/etc'
cfg += ' --with-config-file-scan-dir=' + d + '/' + ver + '/etc/php.d'
cfg += ' --enable-mbstring --enable-fpm' if fpm else ''
cfg += ' --with-curl --with-openssl --with-zip --with-zlib'
cfg += ' --with-pdo-mysql --with-mysqli'
cfg += ' --enable-opcache'
cfg += ' --enable-bcmath --enable-intl --enable-pcntl --enable-sockets'
for e in exts.split(','):
e = e.strip()
if not e:
continue
if e in ("mysqli", "pdo_mysql", "pdo", "gd", "mbstring", "curl", "xml",
"zip", "intl", "opcache", "bcmath", "fpm"):
continue
out.append(cfg)
out.append('make -j"$(nproc)"')
out.append('make install')
out.append('mkdir -p ' + d + '/' + ver + '/etc/php.d')
out.append('cp php.ini-production ' + d + '/' + ver + '/etc/php.ini')
out.append('cp sapi/fpm/php-fpm.conf ' + d + '/' + ver + '/etc/ || true')
out.append('cp sapi/fpm/www.conf.default ' + d + '/' + ver + '/etc/www.conf || true')
out.append('cd /tmp && rm -rf php-' + ver + ' php-' + ver + '.tar.gz')
out.append(d + '/' + ver + '/bin/php --version')
return "\n".join(out) + "\n"
# ========================== Ruby ==========================
class Ruby(Generator):
id = "ruby"
title = "Ruby 任意版本 (源码编译)"
category = "runtimes"
icon = "💎"
tags = ["ruby", "rails"]
description = "从 cache.ruby-lang.org 编译 Ruby,启用 readline/openssl/zlib。"
fields = [
Field("version", "Ruby 版本", "select", default="3.3.3",
options=["2.7.8", "3.0.7", "3.1.6", "3.2.4", "3.3.3"]),
Field("install_dir", "安装目录", "text", default="/opt/ruby"),
]
def render(self, p):
ver = p.get("version", "3.3.3")
d = p.get("install_dir", "/opt/ruby")
out = [bash_header(self.title)]
out.append('log "Installing Ruby ' + ver + '..."')
out.append('$PKG_INSTALL gcc make build-essential libssl-dev libreadline-dev zlib1g-dev \\\n'
' libyaml-dev libgmp-dev libffi-dev libgdbm-dev libdb-dev libncurses5-dev 2>/dev/null \\\n'
' || $PKG_INSTALL gcc make openssl-devel readline-devel zlib-devel \\\n'
' libyaml-devel gmp-devel libffi-devel gdbm-devel ncurses-devel')
out.append('cd /tmp')
out.append('curl -fsSL -O https://cache.ruby-lang.org/pub/ruby/' + ver.split('.')[0] + '.' + ver.split('.')[1] + '/ruby-' + ver + '.tar.gz')
out.append('tar -xzf ruby-' + ver + '.tar.gz')
out.append('cd ruby-' + ver)
out.append('./configure --prefix=' + d + '/' + ver + ' --enable-shared --disable-install-doc')
out.append('make -j"$(nproc)"')
out.append('make install')
out.append('cd /tmp && rm -rf ruby-' + ver + ' ruby-' + ver + '.tar.gz')
out.append(d + '/' + ver + '/bin/ruby --version')
return "\n".join(out) + "\n"
# ========================== Rust ==========================
class RustLang(Generator):
id = "rust"
title = "Rust 工具链 (rustup)"
category = "runtimes"
icon = "🦀"
tags = ["rust", "rustup", "cargo"]
description = "通过 rustup 安装 Rust,可指定 nightly / stable 及 toolchain 路径。"
fields = [
Field("channel", "Channel", "select", default="stable",
options=["stable", "beta", "nightly"]),
Field("install_dir", "安装目录", "text", default="/opt/rust"),
Field("default_toolchain", "默认 toolchain", "text", default="stable"),
Field("install_components", "组件列表", "text",
default="rustfmt,clippy,rust-src,rust-analyzer"),
Field("mirror", "rsproxy 国内镜像", "checkbox", default="yes",
help="启用后会写 RUSTUP_DIST_SERVER 环境变量。"),
]
def render(self, p):
ch = p.get("channel", "stable")
d = p.get("install_dir", "/opt/rust")
tool = p.get("default_toolchain", "stable")
comps = p.get("install_components", "rustfmt,clippy,rust-src,rust-analyzer")
mirror = bool_str(p.get("mirror", True))
out = [bash_header(self.title)]
out.append('log "Installing rustup + ' + ch + '..."')
out.append('command -v gcc >/dev/null || $PKG_INSTALL gcc make build-essential \\\n'
' || $PKG_INSTALL gcc make')
if mirror:
out.append('export RUSTUP_DIST_SERVER=https://rsproxy.cn')
out.append('export RUSTUP_UPDATE_ROOT=https://rsproxy.cn/rustup')
out.append('curl --proto =https --tlsv1.2 -sSf https://sh.rustup.rs | '
'sh -s -- -y --default-toolchain none --no-modify-path --prefix=' + d)
out.append('. ' + d + '/env')
out.append('rustup default ' + tool)
out.append('rustup toolchain install ' + ch)
for c in comps.split(','):
c = c.strip()
if c:
out.append('rustup component add ' + c + ' --toolchain ' + ch)
out.append('rustc --version')
out.append('cargo --version')
return "\n".join(out) + "\n"
# ========================== PostgreSQL ==========================
class PostgreSQL(Generator):
id = "postgresql"
title = "PostgreSQL 任意版本 (官方 apt/yum 源)"
category = "databases"
icon = "🐘"
tags = ["postgresql", "pg", "database"]
description = "从 PostgreSQL Global Development Group 官方源安装任意版本。"
fields = [
Field("version", "PG 版本", "select", default="16",
options=["12", "13", "14", "15", "16"]),
Field("port", "端口", "number", default="5432", min_=1, max_=65535),
Field("listen_addresses", "listen_addresses", "text", default="*"),
Field("admin_user", "超级用户", "text", default="postgres"),
Field("admin_password", "超级用户密码", "password", default="changeme"),
Field("data_dir", "数据目录", "text", default="/var/lib/pgsql/data"),
]
def render(self, p):
ver = p.get("version", "16")
port = str(p.get("port", "5432"))
listen = p.get("listen_addresses", "*")
user = p.get("admin_user", "postgres")
pwd = p.get("admin_password", "changeme")
out = [bash_header(self.title)]
out.append('log "Installing PostgreSQL ' + ver + '..."')
out.append('case "$PKG" in\n'
' apt-get)\n'
' $PKG_INSTALL wget gnupg lsb-release ca-certificates\n'
' curl -fsSL https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor -o /usr/share/keyrings/pgdg.gpg\n'
' echo "deb [signed-by=/usr.share/keyrings/pgdg.gpg] http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list\n'
' apt-get update\n'
' $PKG_INSTALL postgresql-' + ver + ' postgresql-client-' + ver + ' postgresql-contrib-' + ver + '\n'
' ;;\n'
' yum|dnf)\n'
' $PKG_INSTALL https://download.postgresql.org/pub/repos/yum/reporpms/EL-$(rpm -E %{rhel})-x86_64/pgdg-redhat-repo-latest.noarch.rpm\n'
' $PKG_INSTALL postgresql' + ver + '-server postgresql' + ver + '-contrib\n'
' /usr/pgsql-' + ver + '/bin/postgresql-' + ver + '-setup initdb\n'
' ;;\n'
'esac')
out.append('systemctl enable --now postgresql')
out.append('sleep 2')
out.append('sudo -u postgres psql -c "ALTER USER ' + user + ' WITH PASSWORD \'' + pwd + '\';"')
out.append('echo "host all all 0.0.0.0/0 md5" >> /etc/postgresql/' + ver + '/main/pg_hba.conf 2>/dev/null || true')
out.append('echo "host all all 0.0.0.0/0 md5" >> /var/lib/pgsql/data/pg_hba.conf 2>/dev/null || true')
out.append('sed -i "s/^#listen_addresses.*/listen_addresses = \'' + listen + '\'/" /etc/postgresql/' + ver + '/main/postgresql.conf 2>/dev/null || true')
out.append('sed -i "s/^#listen_addresses.*/listen_addresses = \'' + listen + '\'/" /var/lib/pgsql/data/postgresql.conf 2>/dev/null || true')
out.append('sed -i "s/^port.*/port = ' + port + '/" /etc/postgresql/' + ver + '/main/postgresql.conf 2>/dev/null || true')
out.append('sed -i "s/^port.*/port = ' + port + '/" /var/lib/pgsql/data/postgresql.conf 2>/dev/null || true')
out.append('systemctl restart postgresql')
return "\n".join(out) + "\n"
# ========================== MySQL ==========================
class MySQL(Generator):
id = "mysql"
title = "MySQL / MariaDB 任意版本"
category = "databases"
icon = "🐬"
tags = ["mysql", "mariadb", "database"]
description = "支持 MySQL 5.7/8.0/8.4 或 MariaDB 10.x,自动初始化 root 密码。"
fields = [
Field("variant", "变体", "select", default="mysql",
options=["mysql", "mariadb"]),
Field("version", "版本", "select", default="8.0",
options=["5.7", "8.0", "8.4", "10.11", "11.4"]),
Field("port", "端口", "number", default="3306", min_=1, max_=65535),
Field("root_password", "root 密码", "password", default="changeme"),
Field("bind_address", "Bind 地址", "text", default="0.0.0.0"),
]
def render(self, p):
var = p.get("variant", "mysql")
ver = p.get("version", "8.0")
port = str(p.get("port", "3306"))
pwd = p.get("root_password", "changeme")
bind = p.get("bind_address", "0.0.0.0")
out = [bash_header(self.title)]
if var == "mysql":
out.append('log "Installing MySQL ' + ver + '..."')
out.append('case "$PKG" in\n'
' apt-get)\n'
' $PKG_INSTALL wget gnupg lsb-release\n'
' wget -c https://dev.mysql.com/get/mysql-apt-config_0.8.29-1_all.deb\n'
' DEBIAN_FRONTEND=noninteractive dpkg -i mysql-apt-config_0.8.29-1_all.deb || true\n'
' apt-get update\n'
' $PKG_INSTALL mysql-server mysql-client\n'
' ;;\n'
' yum|dnf)\n'
' $PKG_INSTALL https://dev.mysql.com/get/mysql80-community-release-el$(rpm -E %{rhel})-1.noarch.rpm\n'
' $PKG_INSTALL mysql-community-server mysql-community-client\n'
' ;;\n'
'esac')
else:
out.append('log "Installing MariaDB ' + ver + '..."')
out.append('case "$PKG" in\n'
' apt-get) $PKG_INSTALL mariadb-server mariadb-client ;;\n'
' yum|dnf) $PKG_INSTALL mariadb-server mariadb ;;\n'
'esac')
out.append('systemctl enable --now mysql || systemctl enable --now mariadb')
out.append('sleep 3')
out.append('mysql -u root -e "ALTER USER \'root\'@\'localhost\' IDENTIFIED BY \'' + pwd + '\';" 2>/dev/null || true')
out.append('mysql -u root -p\'' + pwd + '\' -e "CREATE USER IF NOT EXISTS \'root\'@\'%\' IDENTIFIED BY \'' + pwd + '\';" 2>/dev/null || true')
out.append('mysql -u root -p\'' + pwd + '\' -e "GRANT ALL ON *.* TO \'root\'@\'%\' WITH GRANT OPTION; FLUSH PRIVILEGES;" 2>/dev/null || true')
out.append('sed -i "s/^bind-address.*/bind-address = ' + bind + '/" /etc/mysql/mysql.conf.d/mysqld.cnf 2>/dev/null || true')
out.append('sed -i "s/^bind-address.*/bind-address = ' + bind + '/" /etc/my.cnf 2>/dev/null || true')
out.append('sed -i "s/^port.*/port = ' + port + '/" /etc/mysql/mysql.conf.d/mysqld.cnf 2>/dev/null || true')
out.append('sed -i "s/^port.*/port = ' + port + '/" /etc/my.cnf 2>/dev/null || true')
out.append('systemctl restart mysql || systemctl restart mariadb')
return "\n".join(out) + "\n"
# ========================== MongoDB ==========================
class MongoDB(Generator):
id = "mongodb"
title = "MongoDB 任意版本"
category = "databases"
icon = "🍃"
tags = ["mongodb", "nosql", "document"]
description = "从 MongoDB 官方源安装任意版本,启用 replica set。"
fields = [
Field("version", "MongoDB 版本", "select", default="7.0",
options=["4.4", "5.0", "6.0", "7.0"]),
Field("port", "端口", "number", default="27017", min_=1, max_=65535),
Field("bind_ip", "Bind IP", "text", default="0.0.0.0"),
Field("enable_auth", "启用鉴权", "checkbox", default="yes"),
Field("root_user", "root 用户", "text", default="root"),
Field("root_password", "root 密码", "password", default="changeme"),
Field("repl_set", "副本集名 (留空=单点)", "text", default=""),
]
def render(self, p):
ver = p.get("version", "7.0")
port = str(p.get("port", "27017"))
bind = p.get("bind_ip", "0.0.0.0")
auth = bool_str(p.get("enable_auth", True))
user = p.get("root_user", "root")
pwd = p.get("root_password", "changeme")
repl = p.get("repl_set", "").strip()
out = [bash_header(self.title)]
out.append('log "Installing MongoDB ' + ver + '..."')
out.append('case "$PKG" in\n'
' apt-get)\n'
' $PKG_INSTALL wget gnupg curl\n'
' curl -fsSL https://www.mongodb.org/static/pgp/server-' + ver + '.asc | gpg --dearmor -o /usr/share/keyrings/mongodb.gpg\n'
' echo "deb [signed-by=/usr/share/keyrings/mongodb.gpg] https://repo.mongodb.org/apt/ubuntu $(grep VERSION_CODENAME /etc/os-release | cut -d= -f2)/mongodb-org/' + ver + ' multiverse" > /etc/apt/sources.list.d/mongodb-org-' + ver + '.list\n'
' apt-get update\n'
' $PKG_INSTALL mongodb-org\n'
' ;;\n'
' yum|dnf)\n'
' cat > /etc/yum.repos.d/mongodb-org-' + ver + '.repo <<REPO_EOF\n'
'[mongodb-org-' + ver + ']\n'
'name=MongoDB Repository\n'
'baseurl=https://repo.mongodb.org/yum/redhat/$releasever/mongodb-org/' + ver + '/x86_64/\n'
'gpgcheck=1\n'
'enabled=1\n'
'gpgkey=https://www.mongodb.org/static/pgp/server-' + ver + '.asc\n'
'REPO_EOF\n'
' $PKG_INSTALL mongodb-org\n'
' ;;\n'
'esac')
out.append('systemctl enable --now mongod')
out.append('sleep 3')
if auth:
out.append('log "Creating root user..."')
out.append('mongosh --quiet --eval \''
'db.getSiblingDB("admin").createUser({user:"' + user + '",pwd:"' + pwd + '",roles:[{role:"root",db:"admin"}]})\' || warn "auth may already be set"')
out.append('sed -i "s/^#security:/{ security: { authorization: \"enabled\" },/g" /etc/mongod.conf')
out.append('sed -i "s/^ bindIp:.*/ bindIp: ' + bind + '/" /etc/mongod.conf')
out.append('grep -q "^ port:" /etc/mongod.conf || sed -i "/^ bindIp:/a\\ port: ' + port + '" /etc/mongod.conf')
if repl:
out.append('grep -q "^replication:" /etc/mongod.conf || cat >> /etc/mongod.conf <<EOF\\nreplication:\\n replSetName: ' + repl + '\\nEOF')
out.append('systemctl restart mongod')
return "\n".join(out) + "\n"
# Register all
for _g in [Python, NodeJS, GCC, Make, CMake, GoLang, Java, PHP, Ruby, RustLang,
PostgreSQL, MySQL, MongoDB]:
register(_g())