diff --git a/Dockerfile b/Dockerfile index 849811a..69ee818 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,105 +1,51 @@ -# Ver: 1.0 by Endial Fang (endial@126.com) +# Ver: 1.2 by Endial Fang (endial@126.com) # -FROM debian:buster-slim +FROM colovu/dbuilder as builder -# ARG参数使用"--build-arg"指定,如 "--build-arg apt_source=tencent" # sources.list 可使用版本:default / tencent / ustc / aliyun / huawei -ARG apt_source=default +ARG apt_source=tencent -# 编译镜像时指定本地服务器地址,如 "--build-arg local_url=http://172.29.14.108/dist-files/" +# 编译镜像时指定用于加速的本地服务器地址 ARG local_url="" -ARG gosu_ver=1.12 +WORKDIR /usr/local -LABEL \ - "Version"="v10" \ +RUN set -eux; \ + appVersion=1.12; \ + appName=gosu-"$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ + appKeys="0xB42F6819007F00F88E364FD4036A9C25BF357DD4"; \ + appUrls=" \ + ${local_url}/gosu \ + https://github.com/tianon/gosu/releases/download/${appVersion} \ + "; \ + download_pkg install ${appName} "${appUrls}" -g "${appKeys}"; \ + chmod +x /usr/local/bin/${appName}; \ +# 验证安装的应用软件是否正常 + ${appName} nobody true; + +# 镜像生成 ======================================================================== +FROM debian:buster-slim +ARG apt_source=default + +LABEL "Version"="v10" \ "Description"="Docker image for Debian 10(Buster)." \ "Dockerfile"="https://github.com/colovu/docker-debian" \ "Vendor"="Endial Fang (endial@126.com)" -COPY sources/* /etc/apt/ - -# 镜像内相应应用及依赖软件包的安装脚本;以下脚本可按照不同需求拆分为多个段,但需要注意各个段在结束前需要清空缓存 -RUN \ -# 设置程序使用静默安装,而非交互模式;默认情况下,类似 tzdata/gnupg/ca-certificates 等程序配置需要交互 - export DEBIAN_FRONTEND=noninteractive; \ - \ -# 设置 shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行) - set -eux; \ - \ -# 更改源为当次编译指定的源 - cp /etc/apt/sources.list.${apt_source} /etc/apt/sources.list; \ - \ - apt-get update; \ - apt-get upgrade -y; \ - apt-get install -y --no-install-recommends locales apt-utils; \ - savedAptMark="$(apt-mark showmanual)"; \ - \ -# 配置系统默认编码为 en_US.UTF-8 编码 +COPY prebuilds / +RUN select_source ${apt_source} +RUN install_pkg locales apt-utils tini libnss-wrapper +RUN set -eux; \ sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen; \ update-locale LC_ALL=en_US.UTF-8 LANG=en_US.UTF-8 LANGUAGE=en_US.UTF-8 LC_MESSAGES=POSIX; \ dpkg-reconfigure -f noninteractive locales; \ \ -# 配置系统默认 TimeZone 信息为 中国/上海 ln -fs /usr/share/zoneinfo/Asia/Shanghai /etc/localtime; \ - dpkg-reconfigure -f noninteractive tzdata; \ - \ - fetchDeps=" \ - ca-certificates \ - wget \ - \ - gnupg \ - dirmngr \ - \ - binutils \ - "; \ - apt-get install -y --no-install-recommends ${fetchDeps}; \ - \ - dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; \ - if [ -n "${local_url}" ]; then \ - wget -O /usr/local/bin/gosu "${local_url}/gosu-${dpkgArch}"; \ - wget -O /usr/local/bin/gosu.asc "${local_url}/gosu-${dpkgArch}.asc"; \ - else \ - wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${gosu_ver}/gosu-$dpkgArch"; \ - wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/${gosu_ver}/gosu-$dpkgArch.asc"; \ - fi; \ - \ -# 安装软件包需要使用的GPG证书,并验证软件 - export GPG_KEYS="0xB42F6819007F00F88E364FD4036A9C25BF357DD4"; \ - export GNUPGHOME="$(mktemp -d)"; \ - for key in ${GPG_KEYS}; do \ - gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "${key}"|| \ - gpg --batch --keyserver pgp.mit.edu --recv-keys "${key}" || \ - gpg --batch --keyserver keys.gnupg.net --recv-keys "${key}" || \ - gpg --batch --keyserver keyserver.pgp.com --recv-keys "${key}"; \ - done; \ - gpg --batch --verify "/usr/local/bin/gosu.asc" "/usr/local/bin/gosu"; \ - command -v gpgconf > /dev/null && gpgconf --kill all; \ - rm -rf "${GNUPGHOME}"; \ - \ - strip /usr/local/bin/gosu; \ - chmod +x /usr/local/bin/gosu; \ - rm -rf /usr/local/bin/gosu.asc; \ - \ -# 查找新安装的应用及应用依赖软件包,并标识为'manual',防止后续自动清理时被删除 - apt-mark auto '.*' > /dev/null; \ - { [ -z "$savedAptMark" ] || apt-mark manual $savedAptMark; }; \ - find /usr/local -type f -executable -exec ldd '{}' ';' \ - | awk '/=>/ { print $(NF-1) }' \ - | sort -u \ - | xargs -r dpkg-query --search \ - | cut -d: -f1 \ - | sort -u \ - | xargs -r apt-mark manual; \ - \ -# 删除安装的临时依赖软件包,清理缓存 - apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false ${fetchDeps}; \ - apt-get autoclean -y; \ - rm -rf /var/lib/apt/lists/*; \ - \ -# 验证新安装的软件是否工作正常,正常情况下放置在镜像制作最后 - gosu --version; - :; + dpkg-reconfigure -f noninteractive tzdata; + +COPY --from=builder /usr/local/bin/gosu-amd64 /usr/local/bin/gosu + +WORKDIR / ENV LANG=en_US.UTF-8 \ LANGUAGE=en_US.UTF-8 \ diff --git a/Makefile b/Makefile index 3a128fb..7018075 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,13 @@ -# Ver: 1.2 by Endial Fang (endial@126.com) +# Ver: 1.4 by Endial Fang (endial@126.com) # # 当前 Docker 镜像的编译脚本 app_name := colovu/debian -# 生成镜像TAG,类似:<镜像名>:<分支名>- 或 <镜像名>:latest-<年月日>-<时分秒> +# 生成镜像TAG,类似: +# <镜像名>:<分支名>- # Git 仓库且无文件修改直接编译 +# <镜像名>:<分支名>-<年月日>-<时分秒> # Git 仓库有文件修改后的编译 +# <镜像名>:latest-<年月日>-<时分秒> # 非 Git 仓库编译 current_subversion:=$(shell if [[ -d .git ]]; then git rev-parse --short HEAD; else date +%y%m%d-%H%M%S; fi) current_tag:=$(shell if [[ -d .git ]]; then git rev-parse --abbrev-ref HEAD | sed -e 's/master/latest/'; else echo "latest"; fi)-$(current_subversion) @@ -13,9 +16,9 @@ build-arg:=--build-arg apt_source=tencent # 设置本地下载服务器路径,加速调试时的本地编译速度 local_ip:=`ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $$2}'|tr -d "addr:"` -build-arg+=--build-arg local_url=http://$(local_ip)/dist-files/ +build-arg+=--build-arg local_url=http://$(local_ip)/dist-files -.PHONY: build clean clearclean +.PHONY: build clean clearclean upgrade build: @echo "Build $(app_name):$(current_tag)" @@ -29,6 +32,12 @@ clean: @docker ps -a | grep "Exited" | awk '{print $$1}' | xargs docker rm @docker images | grep '' | awk '{print $$3}' | xargs docker rmi -f +# 为了防止删除前缀名相同的镜像,在过滤条件中加入一个空格进行过滤 clearclean: clean @echo "Clean all images for current application..." - @docker images | grep "$(app_name)" | awk '{print $$3}' | xargs docker rmi -f + @docker images | grep "$(app_name) " | awk '{print $$3}' | xargs docker rmi -f + +# 更新所有 colovu 仓库的镜像 +upgrade: + @echo "Upgrade all images..." + @docker images | grep 'colovu' | grep -v '' | grep -v "latest-" | awk '{print $$1":"$$2}' | xargs -L 1 docker pull diff --git a/README.md b/README.md index 40925f8..5e0c3a0 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,38 @@ -# 简介 +# Debian [Debian 系统](https://www.debian.org/)的基础 Docker 镜像。基于官方 [Debian LTS 版本 slim](https://hub.docker.com/_/debian) 镜像。 **版本信息:** -- 10、10-buster、latest -- 9、9-stretch +- 10、latest **镜像信息:** * 镜像地址:colovu/debian:latest - * 依赖镜像:debian:TAG-slim + * 依赖镜像:debian:buster-slim **与官方镜像差异:** - 增加 `default、tencent、ustc、aliyun、huawei` 源配置文件,可在编译时通过 `ARG` 变量`apt_source`进行选择 +- 增加常用 Shell 脚本文件 - 更新已安装的软件包 - 增加`locales`,并设置默认编码格式为`en_US.utf8` - 增加`gosu` - 设置默认时区信息为 `Asia/Shanghai` +- 默认增加 nss_wrapper 支持 + + +## **TL;DR** + +Docker 快速启动命令: + +```shell +$ docker run -it colovu/debian /bin/bash +``` + + + +--- @@ -27,7 +41,7 @@ **下载镜像:** ```shell -docker pull colovu/debian:latest +$ docker pull colovu/debian:latest ``` - latest:为镜像的TAG,可针对性选择不同的TAG进行下载 @@ -35,13 +49,13 @@ docker pull colovu/debian:latest **查看镜像:** ```shell -docker images +$ docker images ``` -**生成并运行容器:** +**命令行方式运行容器:** ```shell -docker run -it --rm colovu/debian:latest /bin/bash +$ docker run -it --rm colovu/debian:latest /bin/bash ``` - `-it`:使用交互式终端启动容器 @@ -49,6 +63,30 @@ docker run -it --rm colovu/debian:latest /bin/bash - `colovu/debian:latest`:包含版本信息的镜像名称 - `/bin/bash`:在容器中执行`/bin/bash`命令;如果不执行命令,容器会在启动后立即结束并退出。 +以该方式启动后,直接进入容器的命令行操作界面。如果需要退出,直接使用命令`exit`退出。 + +**后台方式运行容器:** + +```shell +$ docker run -d --name test colovu/debian:latest tail /dev/stderr +``` + +- `--name test`:命名容器为`test` +- `-d`:以后台进程方式启动容器 +- `colovu/debian:latest`:包含TAG信息的镜像名称 +- `tail /dev/stderr`:在容器中执行`tail /dev/stderr`命令,以防止容器直接退出 + + + +以该方式启动后,如果想进入容器,可以使用以下命令: + +```shell +$ docker exec -it test /bin/bash +``` + +- `-it`:使用交互式执行 +- `test`:之前启动的容器名 +- `/bin/bash`:执行的命令 ## 配置修改 @@ -92,6 +130,10 @@ $ export LC_ALL=zh_CN.UTF-8 LANG=zh_CN.UTF-8 LANGUAGE=zh_CN.UTF-8 更新成功后,可使用`locale`命令查看字符编码信息。 +## 更新记录 + +- 10、latest + ---- diff --git a/sources/sources.list.aliyun b/prebuilds/etc/apt/sources/sources.list.aliyun similarity index 100% rename from sources/sources.list.aliyun rename to prebuilds/etc/apt/sources/sources.list.aliyun diff --git a/sources/sources.list.default b/prebuilds/etc/apt/sources/sources.list.default similarity index 100% rename from sources/sources.list.default rename to prebuilds/etc/apt/sources/sources.list.default diff --git a/sources/sources.list.huawei b/prebuilds/etc/apt/sources/sources.list.huawei similarity index 100% rename from sources/sources.list.huawei rename to prebuilds/etc/apt/sources/sources.list.huawei diff --git a/sources/sources.list.tencent b/prebuilds/etc/apt/sources/sources.list.tencent similarity index 100% rename from sources/sources.list.tencent rename to prebuilds/etc/apt/sources/sources.list.tencent diff --git a/sources/sources.list.ustc b/prebuilds/etc/apt/sources/sources.list.ustc similarity index 100% rename from sources/sources.list.ustc rename to prebuilds/etc/apt/sources/sources.list.ustc diff --git a/prebuilds/usr/local/license/LICENSE b/prebuilds/usr/local/license/LICENSE new file mode 100644 index 0000000..80e3bb7 --- /dev/null +++ b/prebuilds/usr/local/license/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Endial Fang (endial@126.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/prebuilds/usr/local/scripts/functions b/prebuilds/usr/local/scripts/functions new file mode 100644 index 0000000..0f6807d --- /dev/null +++ b/prebuilds/usr/local/scripts/functions @@ -0,0 +1,106 @@ +#!/bin/bash +# Ver: 1.0 by Endial Fang (endial@126.com) + +[[ ${ENV_DEBUG:-false} = true ]] && set -x + +MODULE="$(basename "$0")" + +RESET='\033[0m' +BOLD='\033[1m' + +# 前景色 +BLACK='\033[38;5;0m' +RED='\033[38;5;1m' +GREEN='\033[38;5;2m' +YELLOW='\033[38;5;3m' +BLUE='\033[38;5;4m' +MAGENTA='\033[38;5;5m' +CYAN='\033[38;5;6m' +WHITE='\033[38;5;7m' + +# 背景色 +ON_BLACK='\033[48;5;0m' +ON_RED='\033[48;5;1m' +ON_GREEN='\033[48;5;2m' +ON_YELLOW='\033[48;5;3m' +ON_BLUE='\033[48;5;4m' +ON_MAGENTA='\033[48;5;5m' +ON_CYAN='\033[48;5;6m' +ON_WHITE='\033[48;5;7m' + +# 函数列表 + +# 打印输出到 STDERR 设备 +stderr_print() { + printf "%b\\n" "${*}" >&2 +} + +# 输出实际日志信息 +# 参数: +# $1 - 日志类型 +# $2 - 日志信息 +LOG() { + stderr_print "${ENV_DEBUG:+${CYAN}${MODULE:-} ${MAGENTA}$(date "+%T.%2N ")}${RESET}${*}" +} + +# 输出调试类日志信息,尽量少使用 +# 参数: +# $1 - 日志类型 +# $2 - 日志信息 +LOG_D() { + local -r bool="${ENV_DEBUG:-false}" + shopt -s nocasematch + if [[ "$bool" = 1 || "$bool" =~ ^(yes|true)$ ]]; then + LOG "${BLUE}DEBUG${RESET} ==> ${*}" + fi +} + +# 输出提示信息类日志信息 +# 参数: +# $1 - 日志类型 +# $2 - 日志信息 +LOG_I() { + LOG "${GREEN}INFO ${RESET} ==> ${*}" +} + +# 输出警告类日志信息至sterr +# 参数: +# $1 - 日志类型 +# $2 - 日志信息 +LOG_W() { + LOG "${YELLOW}WARN ${RESET} ==> ${*}" +} + +# 输出错误类日志信息至sterr,并退出脚本 +# 参数: +# $1 - 日志类型 +# $2 - 日志信息 +LOG_E() { + LOG "${RED}ERROR${RESET} ==> ${*}" +} + +# 打印包含包含Logo的欢迎信息 +# 全局变量: +# APP_NAME +print_image_welcome_page() { + [[ -n "${APP_NAME}" ]] && github_url="/docker-${APP_NAME}" + + LOG_I ' ____ _ ' + LOG_I ' / ___|___ | | _____ ___ _ ' + LOG_I '| | / _ \| |/ _ \ \ / / | | | '"Docker : ${BOLD}${APP_NAME:-undefined}${RESET}" + LOG_I '| |__| (_) | | (_) \ V /| |_| | '"Version: ${BOLD}${APP_VERSION:-0.0}${RESET}" + LOG_I ' \____\___/|_|\___/ \_/ \__,_| '"PowerBy: ${BOLD}Endial@126.com${RESET}" + LOG_D " Project Repo: https://github.com/colovu/${github_url}" + LOG_I "" + +} + +# 根据需要打印欢迎信息 +# 全局变量: +# ENV_DISABLE_WELCOME_MESSAGE +# APP_NAME +docker_print_welcome() { + if [[ "$(id -u)" = "0" ]]; then + print_image_welcome_page + fi +} \ No newline at end of file diff --git a/prebuilds/usr/local/scripts/helpers b/prebuilds/usr/local/scripts/helpers new file mode 100644 index 0000000..a4179aa --- /dev/null +++ b/prebuilds/usr/local/scripts/helpers @@ -0,0 +1,5 @@ +#!/bin/bash +# Ver: 1.0 by Endial Fang (endial@126.com) + +. /usr/local/scripts/functions + diff --git a/prebuilds/usr/sbin/download_pkg b/prebuilds/usr/sbin/download_pkg new file mode 100755 index 0000000..b6ceddc --- /dev/null +++ b/prebuilds/usr/sbin/download_pkg @@ -0,0 +1,157 @@ +#!/bin/bash +# shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行) +. /usr/local/scripts/functions + +print_usage() { + LOG "Usage: download_pkg \"\" [OPTIONS]" + LOG "" + LOG "Download and install Third-Part packages" + LOG "" + LOG "Commands:" + LOG " install Download and install a package." + LOG " unpack Download and unpack a package." + LOG "" + LOG "Options:" + LOG " -g, --checkpgp Package release bucket." + LOG " -s, --checksum SHA256 verification checksum." + LOG " -h, --help Show this help message and exit." + LOG "" + LOG "PACKAGE-NAME: Name with extern name" + LOG "URLS: String with URL list" + LOG "" + LOG "Examples:" + LOG " - Unpack package" + LOG " \$ download_pkg unpack redis-5.0.8.tar.gz \"http://download.redis.io/releases/\"" + LOG "" + LOG " - Verify and Install package" + LOG " \$ download_pkg install redis-5.0.8.tar.gz \"http://download.redis.io/releases/\" --checksum 42cf86a114d2a451b898fcda96acd4d01062a7dbaaad2801d9164a36f898f596" + LOG "" +} + +check_pgp() { + local name_asc=${1:?missing asc file name} + local name=${2:?missing file name} + local keys="${3:?missing key id}" + + GNUPGHOME="$(mktemp -d)" + if which gpg >/dev/null 2>&1; then + for key in $keys; do + gpg --batch --keyserver ha.pool.sks-keyservers.net --recv-keys "${key}" || + gpg --batch --keyserver pgp.mit.edu --recv-keys "${key}" || + gpg --batch --keyserver keys.gnupg.net --recv-keys "${key}" || + gpg --batch --keyserver keyserver.pgp.com --recv-keys "${key}"; + done + gpg --batch --verify "$name_asc" "$name" + command -v gpgconf > /dev/null && gpgconf --kill all + fi +} + +# 获取并解析参数 +ARGS=$(getopt -o g:s:h -l "checkpgp:,checksum:,help" -n "download-pkg" -- "$@") +if [ $? -ne 0 ]; +then + exit 1 +fi + +eval set -- "$ARGS"; +while true; do + case "$1" in + -g|--checkpgp) + shift + if [ -n "$1" ]; then + PACKAGE_KEYS=$1 + shift + fi + ;; + -s|--checksum) + shift + if [ -n "$1" ]; then + PACKAGE_SHA256=$1 + shift + fi + ;; + -h|--help) + print_usage + exit 0 + ;; + --) + shift + break + ;; + esac +done + +# 检测输入的命令是否合法 +case "$1" in + install|unpack) ;; + *) + error "Unrecognized command: $1" + print_usage + exit 1 + ;; +esac + +# 检测输入参数是否足够,需要至少提供软件包名称 及 下载路径 +if [ $# -lt 3 ]; then + print_usage + exit 1 +fi + +INSTALL_ROOT=/usr/local +CACHE_ROOT=/tmp + +PACKAGE="$2" +PACKAGE_URLS=$3 + +cd $INSTALL_ROOT + +LOG_I "Downloading $PACKAGE package" +for url in $PACKAGE_URLS; do + LOG_D "Try $url/$PACKAGE" + if wget -O "$CACHE_ROOT/$PACKAGE" "$url/$PACKAGE" && [ -s "$CACHE_ROOT/$PACKAGE" ]; then + if [ -n "$PACKAGE_KEYS" ]; then + wget -O "$CACHE_ROOT/$PACKAGE.asc" "$url/$PACKAGE.asc" + if [ ! -e "$CACHE_ROOT/$PACKAGE.asc" ]; then + wget -O "$CACHE_ROOT/$PACKAGE.asc" "$url/$PACKAGE.sig" + fi + fi + success=1 + break + fi +done + +if [ "$PACKAGE_SHA256" ]; then + LOG_I "Verifying package integrity" + echo "$PACKAGE_SHA256 *$CACHE_ROOT/$PACKAGE" | sha256sum -c - +fi + +if [ -e "$CACHE_ROOT/$PACKAGE.asc" ]; then + LOG_I "Verifying package with PGP" + check_pgp "$CACHE_ROOT/$PACKAGE.asc" "$CACHE_ROOT/$PACKAGE" "$PACKAGE_KEYS" +fi + +# If the tarball has too many files, it can trigger a bug +# in overlayfs when using tar. Install bsdtar in the container image +# to workaround it. As the overhead is too big (~40 MB), it is not added by +# default. Source: https://github.com/coreos/bugs/issues/1095 + + +# 安装或解压软件 +case "$1" in + install) + LOG_I "Installing $PACKAGE" + cp $CACHE_ROOT/$PACKAGE /usr/local/bin/ + ;; + unpack) + if ! tar tzf $CACHE_ROOT/$PACKAGE >/dev/null 2>&1; then + LOG_E "Invalid or corrupt '$PACKAGE' package." + exit 1 + fi + LOG_I "Unpacking $PACKAGE" + if which bsdtar >/dev/null 2>&1; then + bsdtar -xf $CACHE_ROOT/$PACKAGE + else + tar xzf $CACHE_ROOT/$PACKAGE + fi + ;; +esac diff --git a/prebuilds/usr/sbin/install_pkg b/prebuilds/usr/sbin/install_pkg new file mode 100755 index 0000000..eb02411 --- /dev/null +++ b/prebuilds/usr/sbin/install_pkg @@ -0,0 +1,55 @@ +#!/bin/bash +# shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行) +set -eux + +print_usage() { + LOG "Usage: install_pkg " + LOG "" + LOG "Download and install packages" + LOG "" + LOG "Options:" + LOG " -h, --help Show this help message and exit." + LOG "" + LOG "Examples:" + LOG " - Unpack package" + LOG " \$ install_pkg bash curl" + LOG "" +} + +if [ $# -lt 1 ]; then + print_usage + exit 1 +fi + +case "$1" in + -h|--help) + print_usage + exit 0 + ;; +esac + +retry=0 +max=2 +until [ $retry -gt $max ]; do + set +e + ( + apt-get update && + apt-get upgrade -y && + apt-get install -y --no-install-recommends "$@" + ) + CODE=$? + set -e + if [ $CODE -eq 0 ]; then + break + fi + if [ $retry -eq $max ]; then + exit $CODE + fi + echo "apt failed, retrying" + retry=$(($retry + 1)) +done + +apt-get purge -y --auto-remove +apt-get autoclean -y + +rm -r /var/lib/apt/lists /var/cache/apt/archives || : diff --git a/prebuilds/usr/sbin/select_source b/prebuilds/usr/sbin/select_source new file mode 100755 index 0000000..d7525fa --- /dev/null +++ b/prebuilds/usr/sbin/select_source @@ -0,0 +1,6 @@ +#!/bin/bash +# Ver: 1.0 by Endial Fang (endial@126.com) +# +# shell 执行参数,分别为 -e(命令执行错误则退出脚本) -u(变量未定义则报错) -x(打印实际待执行的命令行) +set -eux +cp /etc/apt/sources/sources.list.${1:-default} /etc/apt/sources.list