├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── docs └── USAGE.md ├── scripts ├── gen-mirror.py └── template-instantiate.py ├── src ├── bootstrap.sh ├── cli.sh ├── config.cfg ├── core.sh ├── help.sh ├── interact.sh ├── main.sh ├── mirrors │ ├── alpine.sh │ ├── anolis.sh │ ├── archlinux.sh │ ├── archlinuxcn.sh │ ├── blackarch.sh │ ├── crates.sh │ ├── debian.sh │ ├── deepin.sh │ ├── kali.sh │ ├── linuxmint.sh │ ├── ohmyzsh.sh │ ├── openeuler.sh │ ├── openkylin.sh │ ├── pypi.sh │ ├── rustup.sh │ └── ubuntu.sh └── utils.sh └── tests ├── .gitignore ├── inside ├── arch.sh ├── debian.sh ├── deepin.sh ├── kali.sh ├── openeuler.sh ├── openkylin.sh ├── run_test.sh └── ubuntu.sh ├── outside ├── arch.sh ├── debian.sh ├── deepin.sh ├── kali.sh ├── openeuler.sh ├── openkylin.sh └── ubuntu.sh ├── test.sh └── utils.sh /.gitignore: -------------------------------------------------------------------------------- 1 | # Build and Release Folders 2 | bin-debug/ 3 | bin-release/ 4 | [Oo]bj/ 5 | [Bb]in/ 6 | 7 | # Other files and folders 8 | .settings/ 9 | 10 | # Executables 11 | *.swf 12 | *.air 13 | *.ipa 14 | *.apk 15 | 16 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties` 17 | # should NOT be excluded as they contain compiler settings and other important 18 | # information for Eclipse / Flash Builder. 19 | 20 | output/ 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Dongliang Mu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean dump test 2 | .DEFAULT_GOAL := all 3 | 4 | SRC_DIR := src 5 | INCLUDE_FILES := $(wildcard $(SRC_DIR)/*.sh) 6 | MIRROR_DIR := $(SRC_DIR)/mirrors 7 | TEMPLATE_FILE := $(SRC_DIR)/main.sh 8 | MIRROR_FILES := $(wildcard $(MIRROR_DIR)/*) 9 | OTHER_FILES := $(SRC_DIR)/config.cfg 10 | OUT_DIR := output 11 | OUT_FILE := $(OUT_DIR)/hustmirror-cli 12 | OUT_MIRROR_DIR := $(OUT_DIR)/mirrors 13 | OUT_MIRROR_FILES := $(patsubst $(MIRROR_DIR)/%,$(OUT_MIRROR_DIR)/%,$(MIRROR_FILES)) 14 | PREFIX := /usr/local 15 | DPREFIX := $(DESTDIR)$(PREFIX) 16 | INSTALL_DIR := $(DPREFIX)/bin/ 17 | 18 | all: $(OUT_FILE) 19 | @echo "Done, object script is $(OUT_FILE)." 20 | 21 | test: $(OUT_FILE) 22 | @tests/test.sh 23 | 24 | install: $(OUT_FILE) 25 | @mkdir -p $(INSTALL_DIR) 26 | @cp $(OUT_FILE) $(INSTALL_DIR) 27 | 28 | $(OUT_FILE): $(TEMPLATE_FILE) $(OUT_MIRROR_FILES) $(INCLUDE_FILES) $(OTHER_FILES) 29 | @mkdir -p $(OUT_DIR) 30 | @echo "Process $<" 31 | @scripts/template-instantiate.py $< > $@.tmp 32 | @grep -E -v "vim:.+:" $@.tmp > $@ 33 | @rm $@.tmp 34 | @chmod +x $@ 35 | 36 | $(OUT_MIRROR_FILES): $(OUT_MIRROR_DIR)/%: $(MIRROR_DIR)/% 37 | @echo "Process $<" 38 | @mkdir -p $(OUT_MIRROR_DIR) 39 | @scripts/gen-mirror.py $< > $@.tmp 40 | @mv $@.tmp $@ 41 | 42 | clean: 43 | @rm -rf $(OUT_DIR) 44 | @echo "Cleaned." 45 | 46 | clean-test-log: 47 | @rm -rf tests/log 48 | @echo "Cleaned." 49 | 50 | # used for debug Makefile 51 | dump: 52 | $(foreach v, \ 53 | $(shell echo "$(filter-out .VARIABLES,$(.VARIABLES))" | tr ' ' '\n' | sort), \ 54 | $(info $(shell printf "%-20s" "$(v)")= $(value $(v))) \ 55 | ) 56 | 57 | # vim: set noexpandtab ts=4 sw=4 ft=make: 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # hustmirror-cli 2 | 3 | ## Introduction 4 | 5 | `hustmirror-cli` is a CLI posix shell script to replace system repository mirror to HUST Mirror. 6 | 7 | ## Supported Linux Distributions and Software 8 | 9 | - [x] Alpine Linux 10 | - [x] Anolis OS 11 | - [x] Arch Linux 12 | - [x] Black Arch 13 | - [x] crates 14 | - [x] Debian 15 | - [x] Deepin 16 | - [x] Kali 17 | - [x] LinuxMint 18 | - [x] openEuler 19 | - [x] openKylin 20 | - [x] pypi 21 | - [x] Rustup 22 | - [x] Ubuntu 23 | - [x] Oh My Zsh 24 | 25 | If you would to request supports of new Linux distributions or software, please [submit an issue](https://github.com/hust-open-atom-club/hustmirror-cli/issues/new/choose). 26 | 27 | ## Usage 28 | 29 | ``` 30 | curl -s https://mirrors.hust.edu.cn/get | sh -s -- autodeploy 31 | ``` 32 | 33 | See details about hustmirror-cli usage in the [USAGE.md](docs/USAGE.md). 34 | 35 | ## Build 36 | 37 | Use `GNU make` to process all files and generate them 38 | into a single executable bash. 39 | 40 | ```shell 41 | make 42 | ``` 43 | 44 | The output script will be placed in `./output/hustmirror-cli` 45 | 46 | ## Test 47 | 48 | ```shell 49 | make test 50 | ``` 51 | 52 | ## Contract 53 | 54 | ### Styles 55 | 56 | - Syntax of scripts is supposed to POSIX shell compatible. 57 | - Use 4 character tab indent. 58 | - We suppose that user only install `GNU coreutils` or `busybox`. 59 | So prerequisite check is supposed to be made when use other 60 | utils like `gcc` or `make`. 61 | 62 | ### Directories 63 | 64 | - src: scripts would packaging into output scripts. 65 | - src/mirrors: scripts subject to mirror script contract. 66 | - src/main.sh.template: template shell file. 67 | - src/checkfile.sh: check file. 68 | - scripts: store scripts used for packaging. 69 | 70 | ### Template 71 | 72 | Template file supports following directives: 73 | - `@include file`: include other files. 74 | - `@var(shell code)`: get a string from build process. 75 | - `@mirrors`: include all processed mirror scripts. 76 | 77 | ### Mirror script contract 78 | 79 | All files in mirror should implement following functions. 80 | - `check`: (optional) check if target machine is satisfied to replace mirror. 81 | - `install`: install mirror. 82 | - `is_deployed`: (optional) check whether is deployed. 83 | - `can_recover`: (optional) check whether can be recovered. 84 | - `uninstall`: (optional) recover installation. 85 | -------------------------------------------------------------------------------- /docs/USAGE.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | The command-line tool [hustmirror-cli](https://github.com/hust-open-atom-club/hustmirror-cli) is a small utility that helps you quickly switch software sources. Refer to details in our [help documentation at HUST Mirror Site](https://mirrors.hust.edu.cn/docs/). 4 | 5 | It has the following features: 6 | - One-click replacement of software sources 7 | - Restoration of replaced software sources 8 | - Online updates 9 | 10 | > [!NOTE] 11 | > About Bash and POSIX Shell 12 | > This command-line tool is written in POSIX shell-compatible syntax. 13 | > The declared interpreter is `sh` from the `PATH`, and it has been tested in both the dash and bash interpreters. 14 | > 15 | > Bash and POSIX Shell mentioned in this document are shell environments for running and downloading online. 16 | > 17 | > When using it online, since the POSIX Shell method uses pipes that occupy stdin and cannot receive user input, it is recommended to use the Bash method. 18 | 19 | ## Automatic Deployment 20 | 21 | The tool detects whether there are deployable systems/software sources. If deployable sources are found, it proceeds with automatic deployment. 22 | 23 | Add `-y` option to skip confirmation, using default settings. 24 | 25 | ```sh 26 | hustmirror-cli autodeploy # or use 'ad' 27 | ``` 28 | 29 | ## Running in Interactive Mode 30 | 31 | ```sh 32 | hustmirror-cli -i 33 | ``` 34 | 35 | ## Restore origin configurations 36 | 37 | ```sh 38 | hustmirror-cli recover 39 | ``` 40 | 41 | ## Installing / Updating 42 | 43 | After installing the tool via a command, you can use the `hustmirror-cli` command to replace/restore mirror sources at any time. 44 | This command can also be used for manual online updates of the installed tool. 45 | 46 | ```sh 47 | hustmirror-cli install 48 | ``` 49 | 50 | ## Getting Detailed Help 51 | 52 | Besides above, this cli tool support other features 53 | such as deploy/recover specific softwares. 54 | 55 | To view the basic help for the tool, you can use: 56 | 57 | ```sh 58 | hustmirror-cli help 59 | ``` 60 | 61 | For subcommands or specific topics like the `deploy` command, you can use: 62 | 63 | ```sh 64 | hustmirror-cli help deploy 65 | ``` 66 | 67 | [1] [hustmorror-cli help documentation](https://mirrors.hust.edu.cn/docs/) 68 | -------------------------------------------------------------------------------- /scripts/gen-mirror.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys, os, re 3 | 4 | file = sys.argv[1] 5 | dirname = os.path.dirname(file) 6 | mirrorname = os.path.splitext(os.path.basename(file))[0] 7 | output = sys.stdout 8 | 9 | def replace_function_name(str): 10 | exp = r'^(.+)\s*\(\)\s*\{\s*$' 11 | matches = re.match(exp, str) 12 | if matches: 13 | function_name = matches.group(1) 14 | if function_name in ['check', 'install', 'is_deployed', 'can_recover', 'uninstall']: 15 | return f'_{mirrorname}_{function_name}() {{\n' 16 | elif function_name.startswith('_' + mirrorname): 17 | return str 18 | else: 19 | print('[WARN] function name in mirrors are supposed to ' + 20 | 'be prefixed with "_MIRRORNAME": ' + function_name, 21 | file=sys.stderr) 22 | return str 23 | 24 | with open(file, 'r') as f: 25 | lines = f.readlines() 26 | for line in lines: 27 | line = replace_function_name(line) 28 | output.write(line) 29 | -------------------------------------------------------------------------------- /scripts/template-instantiate.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys, os, re, glob 3 | 4 | output = sys.stdout; 5 | 6 | def replace_include(str): 7 | exp = r'''@include\s+(.*)'''; 8 | matches = re.match(exp, str) 9 | if matches: 10 | with open(dirname + '/' + matches.group(1), 'r') as f: 11 | return f.read() 12 | else: 13 | return str 14 | 15 | def replace_var(str): 16 | exp = r'@var\s*\(\s*(.+)\s*\)' 17 | matches = re.finditer(exp, str) 18 | for match in matches: 19 | shell_code = match.group(1) 20 | output = os.popen(shell_code).read() 21 | if output.endswith('\n'): 22 | output = output[:-1] 23 | str = str.replace(match.group(0), output) 24 | return str 25 | 26 | def replace_mirrors(str): 27 | if str.strip() == '@mirrors': 28 | files = glob.glob('output/mirrors/*') 29 | str = '# BEGIN MIRRORS\n' 30 | for file in files: 31 | with open(file, 'r') as f: 32 | str += f.read() 33 | str += '\n' 34 | str += '# END MIRRORS\n' 35 | return str 36 | 37 | file = sys.argv[1] 38 | dirname = os.path.dirname(file) 39 | 40 | with open(file, 'r') as f: 41 | lines = f.readlines() 42 | for line in lines: 43 | line = replace_include(line) 44 | line = replace_var(line) 45 | line = replace_mirrors(line) 46 | output.write(line) 47 | -------------------------------------------------------------------------------- /src/bootstrap.sh: -------------------------------------------------------------------------------- 1 | # bootstrap 2 | print_logo 3 | # parse arguments 4 | case "$1" in 5 | '') # no arguments 6 | display_help $@ 7 | exit 0 8 | ;; 9 | -V | --version) 10 | exit 0 11 | ;; 12 | -h | --help | help) # print help 13 | shift 1 14 | display_help $@ 15 | exit 0 16 | ;; 17 | -i) # Enter interact mode 18 | load_config 19 | interact_main 20 | ;; 21 | *) # Pass arguments to cli 22 | load_config 23 | cli_main $@ 24 | esac 25 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 26 | -------------------------------------------------------------------------------- /src/cli.sh: -------------------------------------------------------------------------------- 1 | cli_deploy() { 2 | if [ $# -eq 0 ]; then 3 | print_warning "Nothing to deploy." 4 | fi 5 | for item in $@ 6 | do 7 | deploy $item || print_error "Failed to deploy $item. Ignoring..." 8 | done 9 | } 10 | 11 | cli_recover() { 12 | if [ $# -eq 0 ]; then 13 | print_warning "Nothing to recover." 14 | fi 15 | for item in $@ 16 | do 17 | recover $item || print_error "Failed to recover $item. Ignoring..." 18 | done 19 | } 20 | 21 | cli_autorecover() { 22 | set_mirror_recover_list no 23 | for item in $ready_to_uninstall 24 | do 25 | recover $item || print_error "Failed to recover $item. Ignoring..." 26 | done 27 | } 28 | 29 | cli_main() { 30 | # parse arguments 31 | case "$1" in 32 | autodeploy | ad) 33 | [ "$2" = "-y" ] && silent_input="y" 34 | set_mirror_list no 35 | cli_deploy $ready_to_install 36 | unset silent_input 37 | ;; 38 | deploy | d) 39 | shift 1 40 | cli_deploy $@ 41 | ;; 42 | list | l) 43 | set_mirror_list no 44 | ;; 45 | recover | r) 46 | shift 1 47 | cli_recover $@ 48 | ;; 49 | install | i | update | up) 50 | install 51 | ;; 52 | autorecover | ar) 53 | cli_autorecover 54 | ;; 55 | *) 56 | print_error "Unknown argument $1, exit." 57 | ;; 58 | esac 59 | } 60 | 61 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 62 | -------------------------------------------------------------------------------- /src/config.cfg: -------------------------------------------------------------------------------- 1 | script_version="v1.1.5" 2 | 3 | domains="mirrors.hust.edu.cn" 4 | 5 | gen_tag="Generated by hustmirror-cli" 6 | -------------------------------------------------------------------------------- /src/core.sh: -------------------------------------------------------------------------------- 1 | source_config() { 2 | hustmirror_config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/hustmirror" 3 | hustmirror_config="${hustmirror_config_dir}/hustmirror.conf" 4 | if [ -f "${hustmirror_config}" ]; then 5 | . "${hustmirror_config}" || { 6 | print_error "Failed to read configuration file: ${hustmirror_config}" 7 | return 1 8 | } 9 | else 10 | return 1 11 | fi 12 | unset _flag 13 | for edomain in $domains; do 14 | if [ "$domain" = "$edomain" ]; then 15 | _flag=1 16 | fi 17 | done 18 | if [ -z "$_flag" ]; then 19 | print_error "Domains has been update, your configuration file need regenerate." 20 | set_default_domain $domains 21 | return 1 22 | fi 23 | } 24 | 25 | save_config() { 26 | hustmirror_config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/hustmirror" 27 | hustmirror_config="${hustmirror_config_dir}/hustmirror.conf" 28 | mkdir -p "${hustmirror_config_dir}" 29 | cat <"${hustmirror_config}" 30 | # ${gen_tag} 31 | domain="${domain}" 32 | http="${http}" 33 | EOF 34 | } 35 | 36 | regist_config() { 37 | print_warning "No configuration file found." 38 | if ! is_tty; then 39 | return 0 40 | fi 41 | if confirm_y "Do you want to autogenerate a default configuration file?"; then 42 | save_config 43 | else 44 | select_from_menu "Choose your prefer domain" $domains 45 | domain=$result 46 | http=https 47 | confirm_y "Do you want to use https rather than http?" || 48 | http=http 49 | confirm_y "Do you want to save the configuration?" && 50 | save_config 51 | fi 52 | } 53 | 54 | load_config() { 55 | print_status "Reading configuration file..." 56 | source_config || regist_config 57 | [ -n "$HM_HTTP" ] && http=$HM_HTTP 58 | [ -n "$HM_DOMAIN" ] && domain=$HM_DOMAIN 59 | true 60 | } 61 | 62 | # $1 disable output when is not zero string 63 | set_mirror_list() { 64 | print_status "Checking the environment and mirrors to install..." 65 | for software in $supported_softwares; do 66 | # check if the software is ready to deploy 67 | if has_command _${software}_check && _${software}_check; then 68 | if has_command _${software}_is_deployed && _${software}_is_deployed; then 69 | continue 70 | fi 71 | ready_to_install="$ready_to_install ${software}" 72 | elif ! has_command _${software}_check; then 73 | unsure_to_install="$unsure_to_install ${software}" 74 | fi 75 | done 76 | 77 | # direct return to disable output 78 | if [ -n "$1" ]; then return 0; fi 79 | 80 | if [ -z "$ready_to_install" ] && [ -z "$unsure_to_install" ]; then 81 | print_warning "No software is ready to install." 82 | print_supported 83 | confirm "Do you want to continue to use other function?" || exit 0 84 | fi 85 | 86 | if [ -n "$ready_to_install" ]; then 87 | print_info "The following software(s) are available to install:" 88 | echo " $ready_to_install" 89 | fi 90 | 91 | if [ -n "$unsure_to_install" ]; then 92 | print_info "The following software(s) are not suggested to install:" 93 | echo " $unsure_to_install" 94 | fi 95 | } 96 | 97 | # $1 disable output when is not zero string 98 | set_mirror_recover_list() { 99 | ready_to_uninstall="" 100 | for software in $supported_softwares; do 101 | # check if the software is ready to recover 102 | if has_command _${software}_check && _${software}_check &&\ 103 | has_command _${software}_can_recover && _${software}_can_recover 104 | then 105 | ready_to_uninstall="$ready_to_uninstall ${software}" 106 | fi 107 | done 108 | 109 | if [ -z "$ready_to_uninstall" ]; then 110 | print_warning "No software is ready to recover." 111 | confirm "Do you want to continue to use other function?" || exit 0 112 | fi 113 | 114 | if [ -n "$1" ]; then return 0; fi 115 | 116 | if [ -n "$ready_to_uninstall" ]; then 117 | print_info "The following software(s) are ready to recover:" 118 | echo " $ready_to_uninstall" 119 | fi 120 | } 121 | 122 | # install hust-mirror 123 | install() { 124 | install_path="/usr/local/bin" 125 | if ! is_root; then 126 | print_warning "Install hust-mirror to /usr/local/bin need root permission." 127 | fi 128 | install_target="$install_path/hustmirror-cli" 129 | set_sudo 130 | if [ ! -d "$install_path" ]; then 131 | print_status "Creating directory: $install_path" 132 | $sudo mkdir -p "$install_path" 133 | fi 134 | has_command curl || { 135 | print_error "curl is required." 136 | exit 1 137 | } 138 | print_status "Downloading latest hust-mirror..." 139 | $sudo curl -sSfL "${http}://${domain}/get" -o "$install_target" || { 140 | print_error "Failed to download hustmirror-cli." 141 | exit 1 142 | } 143 | $sudo chmod +x "$install_target" 144 | print_success "Successfully install hustmirror-cli." 145 | $sudo ln -sf $install_target "$install_path/hustmirror" # make link for legacy name 146 | has_command hustmirror-cli || print_warning "It seems /usr/local/bin is not in your path, try to add it to your PATH in ~/.bashrc or ~/.zshrc." 147 | print_success "Now, you can use \`hustmirror-cli\` in your command line" 148 | } 149 | 150 | # $1 software to recover 151 | recover() { 152 | software=$1 153 | 154 | eval synonyms="\$_synonyms_${software}" 155 | 156 | if [ -n "${synonyms}" ]; then 157 | print_question "${software} is not supported, do you mean ${synonyms}?" 158 | # not return to avoid synonyms get occupied by mirrors 159 | fi 160 | 161 | if has_command _${software}_check && ! _${software}_check; then 162 | print_error "${software} is suitable here." 163 | return 164 | fi 165 | 166 | if has_command _${software}_can_recover && ! _${software}_can_recover; then 167 | print_error "${software} can not be recoverd." 168 | return 1 169 | fi 170 | 171 | if has_command _${software}_uninstall; then 172 | print_status "recover ${software}..." 173 | result=0 174 | _${software}_uninstall || result=$? 175 | if [ $result -eq 0 ]; then 176 | print_success "Successfully uninstalled ${software}." 177 | else 178 | print_error "Failed to uninstall ${software}." 179 | return 1 180 | fi 181 | else 182 | print_error "No uninstallation method for ${software}." 183 | fi 184 | } 185 | 186 | # $1 software to deploy 187 | deploy() { 188 | software=$1 189 | 190 | eval synonyms="\$_synonyms_${software}" 191 | 192 | if [ -n "${synonyms}" ]; then 193 | print_question "${software} is not supported, do you mean ${synonyms}?" 194 | # not return to avoid synonyms get occupied by mirrors 195 | fi 196 | 197 | # check if the software is ready to deploy 198 | if has_command _${software}_check && ! _${software}_check; then 199 | print_error "${software} is suitable here." 200 | return 201 | fi 202 | 203 | if has_command _${software}_is_deployed && _${software}_is_deployed; then 204 | print_error "${software} has been deployed." 205 | return 206 | fi 207 | 208 | if has_command _${software}_install; then 209 | print_status "Deploying ${software}..." 210 | result=0 211 | _${software}_install || result=$? 212 | if [ $result -eq 0 ]; then 213 | print_success "Successfully deployed ${software}." 214 | else 215 | print_error "Failed to deploy ${software}." 216 | return 1 217 | fi 218 | else 219 | print_error "No installation method for ${software}." 220 | fi 221 | } 222 | 223 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 224 | -------------------------------------------------------------------------------- /src/help.sh: -------------------------------------------------------------------------------- 1 | # help bootstrap 2 | if [ "$0" = "sh" ] || [ "$0" = "bash" ]; then 3 | program="hust-mirror.sh" 4 | else 5 | program=$(basename "$0") 6 | fi 7 | 8 | # help text, define _help_(topic) variable 9 | _help_basic="A CLI posix shell script to generate a configuration file for software 10 | repository on different distributions. 11 | 12 | Usage: $program [options...] 13 | $program [command] [targets...] 14 | 15 | Options: 16 | -h, --help Display this help message 17 | -i Enter interact mode 18 | 19 | Commands: (use \`$program help [command]\` to get more information) 20 | help Display help message 21 | deploy Deploy the configuration file 22 | autodeploy Deploy suggested configuration file 23 | recover Recover the configuration file 24 | autorecover Recover deployed and recoverable configuration file 25 | install Install this script to user's local bin 26 | 27 | Commands alias: 28 | h help 29 | d deploy 30 | ad autodeploy 31 | r recover 32 | ar autorecover 33 | i|u|update install 34 | 35 | Examples: 36 | - Enter interact mode 37 | $program -i 38 | - Deploy some configuration file 39 | $program deploy openeuler 40 | - Get command help 41 | $program help ad 42 | 43 | Environments: (optional) 44 | HM_HTTP protoal (http/https), default is http 45 | HM_DOMAIN domain name 46 | 47 | " 48 | 49 | _help_help="Get help of a command or a target topic. 50 | 51 | Usage: $program help [command|topic] 52 | $program h [command|topic] (alias) 53 | 54 | Examples: 55 | - Get help of a command 56 | $program help deploy 57 | - Get help of a topic 58 | $program help debian 59 | 60 | " 61 | 62 | _help_deploy=" 63 | Deploy the configuration file. 64 | 65 | Usage: $program deploy [targets...] 66 | $program d [targets...] (alias) 67 | 68 | Examples: 69 | - Deploy the configuration file for openeuler and pypi 70 | $program deploy openeuler pypi 71 | 72 | " 73 | 74 | _help_autodeploy=" 75 | Check the system and deploy suggested configuration file. 76 | 77 | Usage: $program autodeploy 78 | $program ad (alias) 79 | 80 | Options: (optional) 81 | -y Answer default option to all questions 82 | 83 | " 84 | 85 | _help_recover="Recover the configuration file. 86 | 87 | Usage: $program recover [targets...] 88 | $program r [targets...] (alias) 89 | 90 | " 91 | 92 | _help_install="Install (Update) this script online to user's local bin. 93 | 94 | Usage: $program install 95 | $program i | u | update (alias) 96 | 97 | Note: This command will install the script to ~/.local/bin, and add it to 98 | PATH in ~/.bashrc or ~/.zshrc. 99 | 100 | " 101 | 102 | _help_autorecover="Recover deployed and recoverable configuration file. 103 | 104 | Usage: $program autorecover 105 | $program ar (alias) 106 | 107 | Note: This command will only recover the configuration file that can be recovered, 108 | if you don't use this tool to deploy or have deployed some configurations not 109 | support to recover, you can't recover it. 110 | 111 | " 112 | 113 | _help_d=${_help_deploy} 114 | _help_ad=${_help_autodeploy} 115 | _help_r=${_help_recover} 116 | _help_ar=${_help_autorecover} 117 | _help_i=${_help_install} 118 | _help_u=${_help_install} 119 | _help_h=${_help_help} 120 | _help_update=${_help_install} 121 | 122 | _help_debian="Debian mirror configuration. 123 | 124 | Environments: 125 | DEBIAN_USE_SID Use unstable instead of testing. 126 | 127 | " 128 | 129 | display_help() { 130 | echo 131 | 132 | if [ -z "$1" ]; then 133 | r_echo "$_help_basic" 134 | return 135 | fi 136 | 137 | eval help_text=\"\${_help_${1}}\" 138 | 139 | if [ -z "$help_text" ]; then 140 | print_error "No help information for $1" 141 | else 142 | r_echo "$help_text" 143 | fi 144 | } 145 | 146 | # expand tab for help text 147 | # code style is noexpandtab 148 | # vim: set filetype=sh ts=4 sw=4 expandtab: 149 | -------------------------------------------------------------------------------- /src/interact.sh: -------------------------------------------------------------------------------- 1 | interact_recover() { 2 | set_mirror_recover_list 3 | 4 | get_input "What do you want to uninstall? 5 | for specific softwares, use space to separate multiple softwares." 6 | 7 | uninstall_things="$input" 8 | 9 | # uninstall 10 | for software in $uninstall_things; do 11 | recover $software || confirm "Do you want to continue?" || exit 1 12 | done 13 | } 14 | 15 | interact_deploy() { 16 | for item in $@ 17 | do 18 | deploy $item || confirm "Do you want to continue?" || exit 1 19 | done 20 | } 21 | 22 | interact_main() { 23 | if ! is_tty; then 24 | print_error "Interactive mode must be run in a tty. Arguments is required to enable cli mode, try '-h' to get more information about how to use cli mode." 25 | exit 1 26 | fi 27 | 28 | set_mirror_list 29 | 30 | install_things="" 31 | while true; do 32 | input="" 33 | get_input "What do you want to install? [all] 34 | (a)ll for ready, all! (a!) for all software(s), including unsure ones. 35 | for specific softwares, use space to separate multiple softwares. 36 | (l)ist for forcely list all softwares, even is not supported here. 37 | 38 | Other options: 39 | (r)ecover for uninstall software mirror. 40 | (i)nstall or update hust-mirror locally 41 | (q)uit for exit." 42 | 43 | # parse input 44 | if [ -z "$input" ]; then 45 | input="all" 46 | fi 47 | 48 | case "$input" in 49 | a | all) 50 | interact_deploy $ready_to_install 51 | break 52 | ;; 53 | a! | all!) 54 | interact_deploy $ready_to_install $unsure_to_install 55 | break 56 | ;; 57 | l | list) 58 | print_supported 59 | ;; 60 | q | quit) 61 | exit 0 62 | ;; 63 | r | recover) 64 | interact_recover 65 | break 66 | ;; 67 | i | install) 68 | install 69 | break 70 | ;; 71 | *) 72 | interact_deploy $input 73 | break 74 | ;; 75 | esac 76 | done 77 | 78 | } 79 | 80 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 81 | -------------------------------------------------------------------------------- /src/main.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # httpmirror-cli - a CLI posix shell script to replace softwares' registry mirror 3 | 4 | @var(sed "s/^/# /" LICENSE) 5 | 6 | set -e 7 | 8 | @include config.cfg 9 | 10 | build_time="@var(date -u +'%Y-%m-%d %H:%M:%S UTC')" 11 | 12 | @include utils.sh 13 | @include help.sh 14 | 15 | set_default_domain $domains 16 | http="https" 17 | 18 | # Not only to replace distributions but also softwares like pypi, 19 | # npm registry, dockerhub, etc. 20 | supported_softwares="@var(ls -1 src/mirrors/* | sed -E 's/^.+\/(.+)\.[^.]*$/\1/')" 21 | 22 | @mirrors 23 | 24 | @include core.sh 25 | @include cli.sh 26 | @include interact.sh 27 | @include bootstrap.sh 28 | 29 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 30 | -------------------------------------------------------------------------------- /src/mirrors/alpine.sh: -------------------------------------------------------------------------------- 1 | _alpine_config_file="/etc/apk/repositories" 2 | 3 | check() { 4 | source_os_release 5 | [ "$NAME" = "Alpine Linux" ] 6 | } 7 | 8 | install() { 9 | config_file=$_alpine_config_file 10 | set_sudo 11 | 12 | $sudo cp ${config_file} ${config_file}.bak || { 13 | print_error "Failed to backup ${config_file}" 14 | return 1 15 | } 16 | 17 | { 18 | sed -i "1i # ${gen_tag}" ${config_file} 19 | } && { 20 | sed -i "s|https://dl-cdn.alpinelinux.org|${http}://${domain}|g" ${config_file} 21 | } || { 22 | print_error "Failed to add mirror to ${config_file}" 23 | return 1 24 | } 25 | 26 | } 27 | 28 | is_deployed() { 29 | config_file=$_alpine_config_file 30 | pattern="^[^#]*${http}://${domain}/*" 31 | grep -qE "${pattern}" ${config_file} 32 | } 33 | 34 | can_recover() { 35 | bak_file=${_alpine_config_file}.bak 36 | result=0 37 | test -f $bak_file || result=$? 38 | return $result 39 | } 40 | 41 | uninstall() { 42 | config_file=$_alpine_config_file 43 | set_sudo 44 | $sudo mv ${config_file}.bak ${config_file} || { 45 | print_error "Failed to recover ${config_file}" 46 | return 1 47 | } 48 | } 49 | 50 | # vim: set filetype=sh ts=4 sw=4 noexpandtab:x 51 | -------------------------------------------------------------------------------- /src/mirrors/anolis.sh: -------------------------------------------------------------------------------- 1 | _anolis_config_dir="/etc/yum.repos.d" 2 | 3 | check() { 4 | source_os_release 5 | [ "$NAME" = "Anolis OS" ] 6 | } 7 | 8 | install() { 9 | set_sudo 10 | 11 | for config_file in ${_anolis_config_dir}/*.repo; do 12 | [ -f "$config_file" ] || continue 13 | $sudo cp ${config_file} ${config_file}.bak || { 14 | print_error "Failed to backup ${config_file}" 15 | return 1 16 | } 17 | 18 | new_file=$(sed -E "s|https?://([^/]+)|${http}://${domain}|" $config_file) 19 | { 20 | cat << EOF | $sudo tee ${config_file} > /dev/null 21 | # ${gen_tag} 22 | ${new_file} 23 | EOF 24 | } || { 25 | print_error "Failed to add mirror to ${config_file}" 26 | return 1 27 | } 28 | done 29 | } 30 | 31 | is_deployed() { 32 | 33 | for config_file in ${_anolis_config_dir}/*.repo; do 34 | [ -f "$config_file" ] || continue 35 | if $sudo grep -q "${gen_tag}" "${config_file}"; then 36 | return 0 37 | fi 38 | done 39 | 40 | return 1 41 | } 42 | 43 | can_recover() { 44 | 45 | for config_file in ${_anolis_config_dir}/*.repo; do 46 | [ -f "$config_file" ] || continue 47 | if ! test -f "${config_file}.bak"; then 48 | return 1 49 | fi 50 | done 51 | 52 | return 0 53 | } 54 | 55 | uninstall() { 56 | set_sudo 57 | 58 | for config_file in ${_anolis_config_dir}/*.repo; do 59 | [ -f "$config_file" ] || continue 60 | $sudo mv ${config_file}.bak ${config_file} || { 61 | print_error "Failed to recover ${config_file}" 62 | return 1 63 | } 64 | done 65 | 66 | return 0 67 | } 68 | 69 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 70 | -------------------------------------------------------------------------------- /src/mirrors/archlinux.sh: -------------------------------------------------------------------------------- 1 | _synonyms_arch="archlinux" 2 | _archlinux_config_file="/etc/pacman.d/mirrorlist" 3 | 4 | check() { 5 | source_os_release 6 | [ "$NAME" = "Arch Linux" ] 7 | } 8 | 9 | install() { 10 | config_file=$_archlinux_config_file 11 | set_sudo 12 | 13 | $sudo cp ${config_file} ${config_file}.bak || { 14 | print_error "Failed to backup ${config_file}" 15 | return 1 16 | } 17 | 18 | old_config=$(cat ${config_file}) 19 | { 20 | cat << EOF | $sudo tee ${config_file} > /dev/null 21 | # ${gen_tag} 22 | Server = ${http}://${domain}/archlinux/\$repo/os/\$arch 23 | ${old_config} 24 | EOF 25 | } || { 26 | print_error "Failed to add mirror to ${config_file}" 27 | return 1 28 | } 29 | } 30 | 31 | is_deployed() { 32 | config_file=$_archlinux_config_file 33 | pattern="^[^#]*Server\s*=\s*${http}://${domain}/archlinux/\\\$repo/os/\\\$arch" 34 | grep -qE "${pattern}" ${config_file} 35 | } 36 | 37 | can_recover() { 38 | bak_file=${_archlinux_config_file}.bak 39 | result=0 40 | test -f $bak_file || result=$? 41 | return $result 42 | } 43 | 44 | uninstall() { 45 | config_file=$_archlinux_config_file 46 | set_sudo 47 | $sudo mv ${config_file}.bak ${config_file} || { 48 | print_error "Failed to recover ${config_file}" 49 | return 1 50 | } 51 | } 52 | 53 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 54 | -------------------------------------------------------------------------------- /src/mirrors/archlinuxcn.sh: -------------------------------------------------------------------------------- 1 | _synonyms_arch="archlinuxcn" 2 | _archlinuxcn_config_file="/etc/pacman.conf" 3 | 4 | check() { 5 | source_os_release 6 | [ "$NAME" = "Arch Linux" ] 7 | } 8 | 9 | install() { 10 | config_file=$_archlinuxcn_config_file 11 | set_sudo 12 | 13 | $sudo cp ${config_file} ${config_file}.bak || { 14 | print_error "Failed to backup ${config_file}" 15 | return 1 16 | } 17 | 18 | old_config=$(cat ${config_file}) 19 | { 20 | cat << EOF | $sudo tee ${config_file} > /dev/null 21 | ${old_config} 22 | # ${gen_tag} 23 | [archlinuxcn] 24 | Server = ${http}://${domain}/archlinuxcn/\$arch 25 | EOF 26 | } || { 27 | print_error "Failed to add mirror to ${config_file}" 28 | return 1 29 | } 30 | } 31 | 32 | is_deployed() { 33 | config_file=$_archlinuxcn_config_file 34 | pattern="^[^#]*Server\s*=\s*${http}://${domain}/archlinuxcn/\\\$arch" 35 | grep -qE "${pattern}" ${config_file} 36 | } 37 | 38 | can_recover() { 39 | bak_file=${_archlinuxcn_config_file}.bak 40 | result=0 41 | test -f $bak_file || result=$? 42 | return $result 43 | } 44 | 45 | uninstall() { 46 | config_file=$_archlinuxcn_config_file 47 | set_sudo 48 | $sudo mv ${config_file}.bak ${config_file} || { 49 | print_error "Failed to recover ${config_file}" 50 | return 1 51 | } 52 | } 53 | 54 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 55 | -------------------------------------------------------------------------------- /src/mirrors/blackarch.sh: -------------------------------------------------------------------------------- 1 | _blackarch_config_file="/etc/pacman.d/blackarch-mirrorlist" 2 | 3 | check() { 4 | source_os_release 5 | [ "$NAME" = "Arch Linux" ] 6 | } 7 | 8 | install() { 9 | config_file=$_blackarch_config_file 10 | set_sudo 11 | 12 | $sudo cp ${config_file} ${config_file}.bak || { 13 | print_error "Failed to backup ${config_file}" 14 | return 1 15 | } 16 | 17 | old_config=$(cat ${config_file}) 18 | { 19 | cat << EOF | $sudo tee ${config_file} > /dev/null 20 | # ${gen_tag} 21 | Server = ${http}://${domain}/blackarch/\$repo/os/\$arch 22 | ${old_config} 23 | EOF 24 | } || { 25 | print_error "Failed to add mirror to ${config_file}" 26 | return 1 27 | } 28 | } 29 | 30 | is_deployed() { 31 | config_file=$_blackarch_config_file 32 | pattern="^[^#]*Server\s*=\s*${http}://${domain}/blackarch/\\\$repo/os/\\\$arch" 33 | grep -qE "${pattern}" ${config_file} 34 | } 35 | 36 | can_recover() { 37 | bak_file=${_blackarch_config_file}.bak 38 | result=0 39 | test -f $bak_file || result=$? 40 | return $result 41 | } 42 | 43 | uninstall() { 44 | config_file=$_blackarch_config_file 45 | set_sudo 46 | $sudo mv ${config_file}.bak ${config_file} || { 47 | print_error "Failed to recover ${config_file}" 48 | return 1 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/mirrors/crates.sh: -------------------------------------------------------------------------------- 1 | _crates_cargo_home="${HOME}/.cargo" 2 | 3 | _crates_support_sparse() { 4 | version=$(cargo --version 2>/dev/null | cut -f 2 -d " ") 5 | [ -n "$version" ] && \ 6 | [ $(echo "$version" | cut -f 1 -d ".") -ge 1 ] && \ 7 | [ $(echo "$version" | cut -f 2 -d ".") -ge 68 ] 8 | } 9 | 10 | check() { 11 | cargo --version >/dev/null 2>&1 12 | } 13 | 14 | is_deployed() { 15 | [ -f "${_crates_cargo_home}/config.toml" ] && \ 16 | grep -qE "${gen_tag}" "${_crates_cargo_home}/config.toml" 17 | } 18 | 19 | install() { 20 | mkdir -p "${_crates_cargo_home}" 21 | 22 | if [ -f "${_crates_cargo_home}/config.toml" ] || \ 23 | [ -f "${_crates_cargo_home}/config" ]; then 24 | confirm "You already have a config.toml file in your cargo home, do you want to continue?" || \ 25 | return 1 26 | if [ -f "${_crates_cargo_home}/config" ]; then 27 | mv "${_crates_cargo_home}/config" "${_crates_cargo_home}/config.bak" 28 | else 29 | mv "${_crates_cargo_home}/config.toml" "${_crates_cargo_home}/config.bak" 30 | fi 31 | else 32 | touch "${_crates_cargo_home}/config.bak" 33 | fi 34 | 35 | if _crates_support_sparse; then 36 | _crates_mirror="sparse+${http}://${domain}/crates.io-index/" 37 | else 38 | _crates_mirror="${http}://${domain}/git/crates.io-index/" 39 | fi 40 | 41 | cat >"${_crates_cargo_home}/config.toml" < /dev/null && { 20 | if [ "$HM_DEBIAN_SID" = "true" ]; then 21 | codename="sid" 22 | else 23 | print_warning "hustmirror-cli cannot distinguish sid or testing" 24 | get_input "Please input codename (sid/testing): " "testing" 25 | codename="$input" 26 | fi 27 | } 28 | 29 | set_sudo 30 | 31 | if [ -f $config_file ]; then 32 | $sudo cp ${config_file} ${config_file}.bak || { 33 | print_error "Failed to backup ${config_file}" 34 | return 1 35 | } 36 | else 37 | print_warning "No ${config_file} found, creating new one" 38 | fi 39 | 40 | secure_url="${http}://${domain}/debian-security/" 41 | confirm_y "Use official secure source? (Strongly recommended)" && \ 42 | secure_url="${http}://security.debian.org/debian-security" 43 | 44 | src_prefix="# " 45 | confirm "Use source code?" && \ 46 | src_prefix="" 47 | 48 | 49 | security_appendix='-security' 50 | [ "$codename" = "buster" ] && security_appendix='/updates' 51 | 52 | NFW='' 53 | if [ "$codename" = "bookworm" ] || [ "$codename" = "sid" ] || [ "$codename" = "testing" ]; then 54 | NFW=' non-free-firmware' 55 | fi 56 | 57 | if [ "$codename" = "sid" ]; then 58 | sid_prefix="# " 59 | fi 60 | 61 | 62 | $sudo sh -e -c "cat << EOF > ${config_file} 63 | # ${gen_tag} 64 | deb ${http}://${domain}/debian ${codename} main contrib non-free${NFW} 65 | ${src_prefix}deb-src ${http}://${domain}/debian ${codename} main contrib non-free${NFW} 66 | 67 | ${sid_prefix}deb ${http}://${domain}/debian ${codename}-updates main contrib non-free${NFW} 68 | ${sid_prefix}${src_prefix}deb-src ${http}://${domain}/debian ${codename}-updates main contrib non-free${NFW} 69 | 70 | ${sid_prefix}deb ${http}://${domain}/debian ${codename}-backports main contrib non-free${NFW} 71 | ${sid_prefix}${src_prefix}deb-src ${http}://${domain}/debian ${codename}-backports main contrib non-free${NFW} 72 | 73 | ${sid_prefix}deb ${secure_url} ${codename}${security_appendix} main contrib non-free${NFW} 74 | ${sid_prefix}${src_prefix}deb-src ${http}://security.debian.org/debian-security ${codename}${security_appendix} main contrib non-free${NFW} 75 | 76 | EOF" || { 77 | print_error "Failed to add mirror to ${config_file}" 78 | return 1 79 | } 80 | 81 | confirm_y "Do you want to apt update?" && { 82 | $sudo apt update || { 83 | print_error "apt update failed" 84 | return 1 85 | } 86 | } 87 | 88 | true 89 | } 90 | 91 | uninstall() { 92 | _debian_set_config_file 93 | set_sudo 94 | $sudo sh -c "rm ${config_file}; mv ${old_file}.bak ${old_file}" || { 95 | print_error "Failed to recover ${old_file}" 96 | return 1 97 | } 98 | } 99 | 100 | is_deployed() { 101 | _debian_set_config_file 102 | $sudo grep -q "${gen_tag}" ${config_file} 103 | } 104 | 105 | can_recover() { 106 | _debian_set_config_file 107 | bak_file="$old_file.bak" 108 | test -f $bak_file 109 | } 110 | 111 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 112 | -------------------------------------------------------------------------------- /src/mirrors/deepin.sh: -------------------------------------------------------------------------------- 1 | check() { 2 | source_os_release 3 | [ "$NAME" = "Deepin" ] 4 | } 5 | 6 | install() { 7 | config_file="/etc/apt/sources.list" 8 | source_os_release 9 | 10 | if [ -z "$VERSION_CODENAME" ]; then 11 | print_error "Unsupported Deepin version" 12 | return 1 13 | fi 14 | 15 | codename=${VERSION_CODENAME} 16 | set_sudo 17 | 18 | $sudo cp ${config_file} ${config_file}.bak || { 19 | print_error "Failed to backup ${config_file}" 20 | return 1 21 | } 22 | 23 | new_file=$(sed -E -e "s|https?://([^/]+)/deepin|${http}://${domain}/deepin|" -e "s|https?://([^/]+)/${codename}|${http}://${domain}/deepin/${codename}|" $config_file) 24 | { 25 | cat << EOF | $sudo tee ${config_file} > /dev/null 26 | # ${gen_tag} 27 | ${new_file} 28 | EOF 29 | } || { 30 | print_error "Failed to add mirror to ${config_file}" 31 | return 1 32 | } 33 | 34 | confirm_y "Do you want to apt update?" && { 35 | $sudo apt update || { 36 | print_error "apt update failed" 37 | return 1 38 | } 39 | } 40 | 41 | true 42 | } 43 | 44 | uninstall() { 45 | config_file="/etc/apt/sources.list" 46 | set_sudo 47 | $sudo mv ${config_file}.bak ${config_file} || { 48 | print_error "Failed to recover ${config_file}" 49 | return 1 50 | } 51 | } 52 | 53 | is_deployed() { 54 | config_file="/etc/apt/sources.list" 55 | result=0 56 | $sudo grep -q "${gen_tag}" ${config_file} || result=$? 57 | return $result 58 | } 59 | 60 | can_recover() { 61 | bak_file="/etc/apt/sources.list.bak" 62 | result=0 63 | test -f $bak_file || result=$? 64 | return $result 65 | } 66 | 67 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 68 | -------------------------------------------------------------------------------- /src/mirrors/kali.sh: -------------------------------------------------------------------------------- 1 | check() { 2 | source_os_release 3 | [ "$NAME" = "Kali GNU/Linux" ] 4 | } 5 | 6 | install() { 7 | config_file="/etc/apt/sources.list" 8 | source_os_release 9 | 10 | codename=${VERSION_CODENAME} 11 | set_sudo 12 | 13 | $sudo cp ${config_file} ${config_file}.bak || { 14 | print_error "Failed to backup ${config_file}" 15 | return 1 16 | } 17 | 18 | new_file=$(sed -E -e "s|https?://([^/]+)/kali|${http}://${domain}/kali|" $config_file) 19 | { 20 | cat << EOF | $sudo tee ${config_file} > /dev/null 21 | # ${gen_tag} 22 | ${new_file} 23 | EOF 24 | } || { 25 | print_error "Failed to add mirror to ${config_file}" 26 | return 1 27 | } 28 | 29 | confirm_y "Do you want to apt update?" && { 30 | $sudo apt update || { 31 | print_error "apt update failed" 32 | return 1 33 | } 34 | } 35 | 36 | true 37 | } 38 | 39 | uninstall() { 40 | config_file="/etc/apt/sources.list" 41 | set_sudo 42 | $sudo mv ${config_file}.bak ${config_file} || { 43 | print_error "Failed to recover ${config_file}" 44 | return 1 45 | } 46 | } 47 | 48 | is_deployed() { 49 | config_file="/etc/apt/sources.list" 50 | result=0 51 | $sudo grep -q "${gen_tag}" ${config_file} || result=$? 52 | return $result 53 | } 54 | 55 | can_recover() { 56 | bak_file="/etc/apt/sources.list.bak" 57 | result=0 58 | test -f $bak_file || result=$? 59 | return $result 60 | } 61 | 62 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 63 | -------------------------------------------------------------------------------- /src/mirrors/linuxmint.sh: -------------------------------------------------------------------------------- 1 | _linuxmint_config_file="/etc/apt/sources.list.d/official-package-repositories.list" 2 | 3 | check() { 4 | source_os_release 5 | [ "$NAME" = "Linux Mint" ] 6 | } 7 | 8 | install() { 9 | config_file=$_linuxmint_config_file 10 | source_os_release 11 | 12 | codename=${VERSION_CODENAME} 13 | ubuntu_codename=${UBUNTU_CODENAME} 14 | set_sudo 15 | 16 | $sudo cp ${config_file} ${config_file}.bak || { 17 | print_error "Failed to backup ${config_file}" 18 | return 1 19 | } 20 | 21 | # Replace linuxmint source, remove lines related to Ubuntu at the same time 22 | new_file=$(sed -E -e "s|https?://([^/]+)/linuxmint|${http}://${domain}/linuxmint|;s|https?://packages\.linuxmint\.com|${http}://${domain}/linuxmint|;/ubuntu/d" $config_file) 23 | { 24 | cat << EOF | $sudo tee ${config_file} > /dev/null 25 | # ${gen_tag} 26 | ${new_file} 27 | EOF 28 | } || { 29 | print_error "Failed to add mirror to ${config_file}" 30 | return 1 31 | } 32 | 33 | # Append Ubuntu source to the end of the file 34 | print_info "Adding Ubuntu mirror to ${config_file}:" 35 | secure_url="${http}://${domain}/ubuntu/" 36 | confirm_y "Use official secure source? (Strongly recommended)" && \ 37 | secure_url="http://security.ubuntu.com/ubuntu/" 38 | 39 | propoesd_prefix="# " 40 | confirm "Use proposed source?" && \ 41 | propoesd_prefix="" 42 | 43 | src_prefix="# " 44 | confirm "Use source code?" && \ 45 | src_prefix="" 46 | 47 | $sudo sh -e -c "cat <> ${config_file} 48 | # ${gen_tag} 49 | deb ${http}://${domain}/ubuntu/ ${ubuntu_codename} main restricted universe multiverse 50 | ${src_prefix}deb-src ${http}://${domain}/ubuntu/ ${ubuntu_codename} main restricted universe multiverse 51 | deb ${http}://${domain}/ubuntu/ ${ubuntu_codename}-updates main restricted universe multiverse 52 | ${src_prefix}deb-src ${http}://${domain}/ubuntu/ ${ubuntu_codename}-updates main restricted universe multiverse 53 | deb ${secure_url} ${ubuntu_codename}-security main restricted universe multiverse 54 | ${src_prefix}deb-src ${secure_url} ${ubuntu_codename}-security main restricted universe multiverse 55 | 56 | ${propoesd_prefix}deb ${http}://${domain}/ubuntu/ ${ubuntu_codename}-proposed main restricted universe multiverse 57 | ${propoesd_prefix}deb-src ${http}://${domain}/ubuntu/ ${ubuntu_codename}-proposed main restricted universe multiverse 58 | EOF" || { 59 | print_error "Failed to add Ubuntu mirror to ${config_file}" 60 | return 1 61 | } 62 | 63 | confirm_y "Do you want to apt update?" && { 64 | $sudo apt update || { 65 | print_error "apt update failed" 66 | return 1 67 | } 68 | } 69 | 70 | true 71 | } 72 | 73 | uninstall() { 74 | config_file=$_linuxmint_config_file 75 | 76 | set_sudo 77 | $sudo mv ${config_file}.bak ${config_file} || { 78 | print_error "Failed to recover ${config_file}" 79 | return 1 80 | } 81 | } 82 | 83 | is_deployed() { 84 | config_file=$_linuxmint_config_file 85 | result=0 86 | $sudo grep -q "${gen_tag}" ${config_file} || result=$? 87 | return $result 88 | } 89 | 90 | can_recover() { 91 | bak_file=${_linuxmint_config_file}.bak 92 | result=0 93 | test -f $bak_file || result=$? 94 | return $result 95 | } 96 | 97 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 98 | -------------------------------------------------------------------------------- /src/mirrors/ohmyzsh.sh: -------------------------------------------------------------------------------- 1 | check() { 2 | has_git || return 1 3 | git -C "${HOME}/.oh-my-zsh" remote -v >/dev/null 2>&1 4 | } 5 | 6 | install() { 7 | git -C $ZSH remote set-url origin ${http}://${domain}/git/ohmyzsh.git 8 | print_success "oh-my-zsh repo mirror has been set." 9 | } 10 | 11 | uninstall() { 12 | print_info "Recover oh-my-zsh mirror to official repo." 13 | git -C $ZSH remote set-url origin "https://github.com/ohmyzsh/ohmyzsh.git" 14 | } 15 | 16 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 17 | -------------------------------------------------------------------------------- /src/mirrors/openeuler.sh: -------------------------------------------------------------------------------- 1 | _openeuler_config_file="/etc/yum.repos.d/openEuler.repo" 2 | 3 | check() { 4 | source_os_release 5 | [ "$NAME" = "openEuler" ] 6 | } 7 | 8 | install() { 9 | config_file=$_openeuler_config_file 10 | set_sudo 11 | 12 | $sudo cp ${config_file} ${config_file}.bak || { 13 | print_error "Failed to backup ${config_file}" 14 | return 1 15 | } 16 | 17 | new_file=$(sed -E "s|https?://([^/]+)|${http}://${domain}/openeuler|" $config_file) 18 | { 19 | cat << EOF | $sudo tee ${config_file} > /dev/null 20 | # ${gen_tag} 21 | ${new_file} 22 | EOF 23 | } || { 24 | print_error "Failed to add mirror to ${config_file}" 25 | return 1 26 | } 27 | } 28 | 29 | is_deployed() { 30 | config_file=$_openeuler_config_file 31 | $sudo grep -q "${gen_tag}" ${config_file} 32 | } 33 | 34 | can_recover() { 35 | bak_file=${_openeuler_config_file}.bak 36 | test -f $bak_file 37 | } 38 | 39 | uninstall() { 40 | config_file=$_openeuler_config_file 41 | set_sudo 42 | $sudo mv ${config_file}.bak ${config_file} || { 43 | print_error "Failed to recover ${config_file}" 44 | return 1 45 | } 46 | } 47 | 48 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 49 | -------------------------------------------------------------------------------- /src/mirrors/openkylin.sh: -------------------------------------------------------------------------------- 1 | check() { 2 | source_os_release 3 | [ "$NAME" = "openKylin" ] 4 | } 5 | 6 | install() { 7 | config_file="/etc/apt/sources.list" 8 | source_os_release 9 | 10 | codename=${VERSION_CODENAME} 11 | set_sudo 12 | 13 | $sudo cp ${config_file} ${config_file}.bak || { 14 | print_error "Failed to backup ${config_file}" 15 | return 1 16 | } 17 | 18 | new_file=$(sed -E -e "s|https?://([^/]+)/openkylin|${http}://${domain}/openkylin|" $config_file) 19 | { 20 | cat << EOF | $sudo tee ${config_file} > /dev/null 21 | # ${gen_tag} 22 | ${new_file} 23 | EOF 24 | } || { 25 | print_error "Failed to add mirror to ${config_file}" 26 | return 1 27 | } 28 | 29 | confirm_y "Do you want to apt update?" && { 30 | $sudo apt update || { 31 | print_error "apt update failed" 32 | return 1 33 | } 34 | } 35 | 36 | true 37 | } 38 | 39 | uninstall() { 40 | config_file="/etc/apt/sources.list" 41 | set_sudo 42 | $sudo mv ${config_file}.bak ${config_file} || { 43 | print_error "Failed to recover ${config_file}" 44 | return 1 45 | } 46 | } 47 | 48 | is_deployed() { 49 | config_file="/etc/apt/sources.list" 50 | result=0 51 | $sudo grep -q "${gen_tag}" ${config_file} || result=$? 52 | return $result 53 | } 54 | 55 | can_recover() { 56 | bak_file="/etc/apt/sources.list.bak" 57 | result=0 58 | test -f $bak_file || result=$? 59 | return $result 60 | } 61 | 62 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 63 | -------------------------------------------------------------------------------- /src/mirrors/pypi.sh: -------------------------------------------------------------------------------- 1 | _synonyms_python="pypi" 2 | _synonyms_pip="pypi" 3 | _synonyms_pdm="pypi" 4 | 5 | _pypi_python="python" 6 | _pypi_backup_dir="${XDG_CONFIG_HOME:-$HOME/.config}/hustmirror/backup" 7 | _pypi_backup_pip="${_pypi_backup_dir}/pip.bak" 8 | _pypi_backup_pdm="${_pypi_backup_dir}/pdm.bak" 9 | 10 | _pypi_has_pip="" 11 | _pypi_has_pdm="" 12 | 13 | _pypi_isdeployed_pip="" 14 | _pypi_isdeployed_pdm="" 15 | 16 | _pypi_set_python() { 17 | if is_windows; then 18 | if ! has_command "python"; then 19 | _pypi_python=$(reg query HKCU\\Software\\Python //s //f ExecutablePath //e | 20 | grep ExecutablePath | head -n 1 | tr -s " " | cut -f 4 -d " ") 21 | fi 22 | fi 23 | } 24 | 25 | check() { 26 | _pypi_set_python 27 | has_command "$_pypi_python" && "$_pypi_python" -m pip --version >/dev/null 2>&1 && _pypi_has_pip=1 28 | has_command "$_pypi_python" && pdm --version >/dev/null 2>&1 && _pypi_has_pdm=1 29 | 30 | [ -n "$_pypi_has_pip" ] || [ -n "$_pypi_has_pdm" ] 31 | } 32 | 33 | is_deployed() { 34 | if [ -n "$_pypi_has_pip" ] && 35 | $_pypi_python -m pip config get global.index-url 2>/dev/null | grep -qE "$domain"; then 36 | _pypi_isdeployed_pip=1 37 | fi 38 | if [ -n "$_pypi_has_pdm" ] && 39 | pdm config pypi.url 2>/dev/null | grep -qE "$domain"; then 40 | _pypi_isdeployed_pdm=1 41 | fi 42 | [ -n "$_pypi_isdeployed_pip" ] && [ -n "$_pypi_isdeployed_pdm" ] 43 | } 44 | 45 | can_recover() { 46 | [ -f "$_pypi_backup_pip" ] || [ -f "$_pypi_backup_pdm" ] 47 | } 48 | 49 | install() { 50 | mkdir -p "$_pypi_backup_dir" 51 | if [ -n "$_pypi_has_pip" ]; then 52 | $_pypi_python -m pip config get global.index-url 2>/dev/null >"$_pypi_backup_pip" 53 | $_pypi_python -m pip config set global.index-url "${http}://${domain}/pypi/web/simple/" 54 | print_success "pip mirror has been set." 55 | fi 56 | if [ -n "$_pypi_has_pdm" ]; then 57 | pdm config pypi.url 2>/dev/null >"$_pypi_backup_pdm" 58 | pdm config pypi.url "${http}://${domain}/pypi/web/simple/" 59 | print_success "pdm mirror has been set." 60 | fi 61 | } 62 | 63 | uninstall() { 64 | if [ -n "$_pypi_has_pip" ]; then 65 | last_url=$(cat "$_pypi_backup_pip") 66 | if [ -z "$last_url" ]; then 67 | $_pypi_python -m pip config unset global.index-url 68 | else 69 | $_pypi_python -m pip config set global.index-url "$last_url" 70 | fi 71 | print_success "pip mirror has been recovered." 72 | fi 73 | if [ -n "$_pypi_has_pdm" ]; then 74 | last_url=$(cat "$_pypi_backup_pdm") 75 | if [ -z "$last_url" ]; then 76 | pdm config -d pypi.url 77 | else 78 | pdm config pypi.url "$last_url" 79 | fi 80 | print_success "pdm mirror has been recovered." 81 | fi 82 | } 83 | 84 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 85 | -------------------------------------------------------------------------------- /src/mirrors/rustup.sh: -------------------------------------------------------------------------------- 1 | _rustup_get_shell_rc() { 2 | sh=$(basename "$SHELL") 3 | case "$sh" in 4 | bash) 5 | _rustup_shell_rc="$HOME/.bashrc" 6 | ;; 7 | zsh) 8 | _rustup_shell_rc="$HOME/.zshrc" 9 | ;; 10 | fish) 11 | _rustup_shell_rc="" 12 | print_error "fish is not supported." 13 | ;; 14 | *) 15 | _rustup_shell_rc="" 16 | ;; 17 | esac 18 | } 19 | 20 | _rustup_gen_tag="${gen_tag}::rustup" 21 | 22 | check() { 23 | has_command rustup 24 | } 25 | 26 | is_deployed() { 27 | _rustup_get_shell_rc 28 | if [ -z "$_rustup_shell_rc" ]; then 29 | print_error "Can not find shell rc file." 30 | return 1 31 | fi 32 | grep -qE "${_rustup_gen_tag}" "$_rustup_shell_rc" 33 | } 34 | 35 | 36 | install() { 37 | _rustup_get_shell_rc 38 | if [ -z "$_rustup_shell_rc" ]; then 39 | print_error "Can not find shell rc file." 40 | return 1 41 | fi 42 | echo "export RUSTUP_DIST_SERVER=${http}://${domain}/rustup # ${_rustup_gen_tag}" \ 43 | >> "$_rustup_shell_rc" 44 | echo "export RUSTUP_UPDATE_ROOT=${http}://${domain}/rustup/rustup # ${_rustup_gen_tag}" \ 45 | >> "$_rustup_shell_rc" 46 | print_success "rustup mirror will take effect next time shell start." 47 | } 48 | 49 | can_recover() { 50 | _rustup_is_deployed 51 | } 52 | 53 | uninstall() { 54 | _rustup_get_shell_rc 55 | if [ -z "$_rustup_shell_rc" ]; then 56 | print_error "Can not find shell rc file." 57 | return 1 58 | fi 59 | # do not use -i, because it is not supported by all sed, such as macOS 60 | sed "/${_rustup_gen_tag}/d" "$_rustup_shell_rc" > "$_rustup_shell_rc.tmp" 61 | mv "$_rustup_shell_rc.tmp" "$_rustup_shell_rc" 62 | print_success "rustup mirror has been unset." 63 | } 64 | 65 | 66 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 67 | -------------------------------------------------------------------------------- /src/mirrors/ubuntu.sh: -------------------------------------------------------------------------------- 1 | check() { 2 | source_os_release 3 | [ "$NAME" = "Ubuntu" ] 4 | } 5 | 6 | _ubuntu_set_config_file() { 7 | config_file="/etc/apt/sources.list.d/ubuntu.sources" 8 | if ! [ -f $config_file ]; then # rule for ubuntu before 24.04 9 | config_file="/etc/apt/sources.list" 10 | fi 11 | } 12 | 13 | install() { 14 | _ubuntu_set_config_file 15 | source_os_release 16 | codename=${VERSION_CODENAME} 17 | set_sudo 18 | 19 | $sudo cp ${config_file} ${config_file}.bak || { 20 | print_error "Backup ${config_file} failed" 21 | return 1 22 | } 23 | 24 | secure_url="${http}://${domain}/ubuntu/" 25 | confirm_y "Use official secure source? (Strongly recommended)" && \ 26 | secure_url="http://security.ubuntu.com/ubuntu/" 27 | 28 | propoesd_prefix="# " 29 | confirm "Use proposed source?" && \ 30 | propoesd_prefix="" 31 | 32 | src_prefix="# " 33 | confirm "Use source code?" && \ 34 | src_prefix="" 35 | 36 | # 如果 config_file == /etc/apt/sources.list.d/ubuntu.sources 37 | if [ "$config_file" = "/etc/apt/sources.list.d/ubuntu.sources" ]; then 38 | $sudo sh -e -c "cat < ${config_file} 39 | # ${gen_tag} 40 | Types: deb 41 | URIs: ${http}://${domain}/ubuntu/ 42 | Suites: ${codename} ${codename}-updates ${codename}-backports 43 | Components: main universe restricted multiverse 44 | Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg 45 | 46 | ${src_prefix}Types: deb-src 47 | ${src_prefix}URIs: ${http}://${domain}/ubuntu/ 48 | ${src_prefix}Suites: ${codename} ${codename}-updates ${codename}-backports 49 | ${src_prefix}Components: main universe restricted multiverse 50 | ${src_prefix}Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg 51 | 52 | Types: deb 53 | URIs: ${secure_url} 54 | Suites: ${codename}-security 55 | Components: main universe restricted multiverse 56 | Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg 57 | 58 | ${src_prefix}Types: deb-src 59 | ${src_prefix}URIs: ${secure_url} 60 | ${src_prefix}Suites: ${codename}-security 61 | ${src_prefix}Components: main universe restricted multiverse 62 | ${src_prefix}Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg 63 | 64 | ${propoesd_prefix}Types: deb 65 | ${propoesd_prefix}URIs: ${http}://${domain}/ubuntu/ 66 | ${propoesd_prefix}Suites: ${codename}-proposed 67 | ${propoesd_prefix}Components: main universe restricted multiverse 68 | ${propoesd_prefix}Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg 69 | 70 | ${propoesd_prefix}Types: deb-src 71 | ${propoesd_prefix}URIs: ${http}://${domain}/ubuntu/ 72 | ${propoesd_prefix}Suites: ${codename}-proposed 73 | ${propoesd_prefix}Components: main universe restricted multiverse 74 | ${propoesd_prefix}Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg 75 | EOF" 76 | else 77 | $sudo sh -e -c "cat < ${config_file} 78 | # ${gen_tag} 79 | deb ${http}://${domain}/ubuntu/ ${codename} main restricted universe multiverse 80 | ${src_prefix}deb-src ${http}://${domain}/ubuntu/ ${codename} main restricted universe multiverse 81 | deb ${http}://${domain}/ubuntu/ ${codename}-updates main restricted universe multiverse 82 | ${src_prefix}deb-src ${http}://${domain}/ubuntu/ ${codename}-updates main restricted universe multiverse 83 | deb ${http}://${domain}/ubuntu/ ${codename}-backports main restricted universe multiverse 84 | ${src_prefix}deb-src ${http}://${domain}/ubuntu/ ${codename}-backports main restricted universe multiverse 85 | 86 | deb ${secure_url} ${codename}-security main restricted universe multiverse 87 | ${src_prefix}deb-src ${secure_url} ${codename}-security main restricted universe multiverse 88 | 89 | ${propoesd_prefix}deb ${http}://${domain}/ubuntu/ ${codename}-proposed main restricted universe multiverse 90 | ${propoesd_prefix}deb-src ${http}://${domain}/ubuntu/ ${codename}-proposed main restricted universe multiverse 91 | EOF" 92 | fi 93 | 94 | if [ $? -ne 0 ]; then 95 | print_error "Write ${config_file} failed" 96 | return 1 97 | fi 98 | 99 | confirm_y "Do you want to apt update?" && { 100 | $sudo apt update || { 101 | print_error "apt update failed" 102 | return 1 103 | } 104 | } 105 | 106 | true 107 | } 108 | 109 | uninstall() { 110 | _ubuntu_set_config_file 111 | set_sudo 112 | $sudo mv ${config_file}.bak ${config_file} || { 113 | print_error "Failed to recover ${config_file}" 114 | return 1 115 | } 116 | } 117 | 118 | is_deployed() { 119 | _ubuntu_set_config_file 120 | result=0 121 | $sudo grep -q "${gen_tag}" ${config_file} || result=$? 122 | return $result 123 | } 124 | 125 | can_recover() { 126 | _ubuntu_set_config_file 127 | bak_file="$config_file.bak" 128 | 129 | result=0 130 | test -f $bak_file || result=$? 131 | return $result 132 | } 133 | 134 | # vim: set filetype=sh ts=4 sw=4 noexpandtab: 135 | -------------------------------------------------------------------------------- /src/utils.sh: -------------------------------------------------------------------------------- 1 | print_logo() { 2 | r_echo ' _ _ _ _ ____ _____ __ __ ___ ____ ____ ___ ____ ' 3 | r_echo '| | | | | | / ___|_ _| \/ |_ _| _ \| _ \ / _ \| _ \ ' 4 | r_echo '| |_| | | | \___ \ | | | |\/| || || |_) | |_) | | | | |_) |' 5 | r_echo '| _ | |_| |___) || | | | | || || _ <| _ <| |_| | _ < ' 6 | r_echo '|_| |_|\___/|____/ |_| |_| |_|___|_| \_\_| \_\\___/|_| \_\' 7 | r_echo 8 | r_echo "hustmirror-cli ${script_version} build ${build_time}" 9 | } 10 | 11 | source_os_release() { 12 | # /etc/os-release does exist in most Linux distributions, and BSD variants 13 | test -e /etc/os-release && os_release='/etc/os-release' || os_release='/usr/lib/os-release' 14 | if [ -f "${os_release}" ]; then 15 | . "${os_release}" 16 | else 17 | NAME="Unknown" 18 | fi 19 | } 20 | 21 | is_root() { 22 | [ "$(id -u)" -eq 0 ] 23 | } 24 | 25 | is_windows() { 26 | uname -a | grep -qiE "cygwin|mingw|msys" 27 | } 28 | 29 | has_command() { 30 | command -v "${1}" >/dev/null 2>&1 31 | } 32 | 33 | has_sudo() { 34 | has_command sudo 35 | } 36 | 37 | has_curl() { 38 | has_command curl 39 | } 40 | 41 | has_git() { 42 | has_command git 43 | } 44 | 45 | has_sed() { 46 | has_command sed 47 | } 48 | 49 | is_tty() { 50 | # cache it to avoid too many forks 51 | [ -z "$IS_TTY" ] && { 52 | IS_TTY=0 53 | # check if stdout is a tty, if is, then check if /dev/tty is readable 54 | [ -t 1 ] && sh -c "exec < /dev/tty" >/dev/null 2>&1 || IS_TTY=1 55 | } 56 | return $IS_TTY 57 | } 58 | 59 | c_echo() { 60 | if has_command printf; then 61 | printf "$*\n" 62 | else 63 | echo "$*" 64 | fi 65 | } 66 | 67 | r_echo() { 68 | if has_command printf; then 69 | printf "%s\n" "$*" 70 | else 71 | echo "$*" 72 | fi 73 | } 74 | 75 | echo_red() { 76 | if is_tty; then 77 | c_echo "\033[0;31m${1}\033[0m" 78 | else 79 | c_echo "${1}" 80 | fi 81 | } 82 | 83 | echo_green() { 84 | if is_tty; then 85 | c_echo "\033[0;32m${1}\033[0m" 86 | else 87 | c_echo "${1}" 88 | fi 89 | } 90 | 91 | echo_yellow() { 92 | if is_tty; then 93 | c_echo "\033[0;33m${1}\033[0m" 94 | else 95 | c_echo "${1}" 96 | fi 97 | } 98 | 99 | echo_blue() { 100 | if is_tty; then 101 | c_echo "\033[0;34m${1}\033[0m" 102 | else 103 | c_echo "${1}" 104 | fi 105 | } 106 | 107 | print_error() { 108 | echo_red "[ERR] ${1}" 109 | } 110 | 111 | print_warning() { 112 | echo_yellow "[WARN] ${1}" 113 | } 114 | 115 | print_success() { 116 | echo_green "[+] ${1}" 117 | } 118 | 119 | print_info() { 120 | echo_green "[!] ${1}" 121 | } 122 | 123 | print_status() { 124 | echo_yellow "[*] ${1}" 125 | } 126 | 127 | print_question() { 128 | echo_yellow "[?] ${1}" 129 | } 130 | 131 | get_input() { 132 | if ! is_tty || [ "$silent_input" = "y" ]; then 133 | if [ -n "${2}" ]; then 134 | input="${2}" 135 | return 0 136 | fi 137 | return 1 138 | fi 139 | [ -n "${1}" ] && print_question "${1}" 140 | read -r -p "[>] " input origin.txt || true 20 | 21 | print_title "1. Running deploy" 22 | HM_HTTP=http /hustmirror/hustmirror-cli autodeploy 23 | cat $new_config_file > new.txt || true 24 | 25 | print_title "2. Running updates" 26 | eval $update_command 27 | 28 | print_title "3. Running recover" 29 | HM_HTTP=http /hustmirror/hustmirror-cli recover $recover_item 30 | cat $config_file > recover.txt || true 31 | 32 | print_title "4. Diff files" 33 | # no diff and cmp, use sha1sum to compare 34 | a=$(sha1sum origin.txt | cut -d ' ' -f 1) 35 | b=$(sha1sum recover.txt | cut -d ' ' -f 1) 36 | echo "origin.txt sum: $a" 37 | echo "recover.txt sum: $b" 38 | test "$a" = "$b" 39 | 40 | print_title "5. Running updates" 41 | eval $update_command 42 | 43 | # All is ok and create pass file 44 | touch pass 45 | -------------------------------------------------------------------------------- /tests/inside/ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | config_file="/etc/apt/sources.list" 5 | update_command="apt-get update" 6 | recover_item="ubuntu" 7 | 8 | source "$(realpath ${BASH_SOURCE%/*})/run_test.sh" 9 | -------------------------------------------------------------------------------- /tests/outside/arch.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | image="archlinux:latest" 7 | test_file="arch.sh" 8 | run_docker 9 | -------------------------------------------------------------------------------- /tests/outside/debian.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | images=" 7 | debian:12-slim 8 | debian:11-slim 9 | debian:10-slim 10 | debian:sid-slim 11 | debian:testing-slim 12 | " 13 | test_file="debian.sh" 14 | 15 | 16 | for image in $images 17 | do 18 | if echo $image | grep -q "sid"; then 19 | params="-e HM_DEBIAN_SID=true" 20 | else 21 | params="" 22 | fi 23 | run_docker 24 | done 25 | 26 | -------------------------------------------------------------------------------- /tests/outside/deepin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | images=" 7 | linuxdeepin/beige 8 | linuxdeepin/apricot 9 | " 10 | # http="http" 11 | test_file="deepin.sh" 12 | 13 | for image in $images 14 | do 15 | run_docker 16 | done 17 | 18 | -------------------------------------------------------------------------------- /tests/outside/kali.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | http="http" 7 | images="kalilinux/kali-rolling" 8 | test_file="kali.sh" 9 | 10 | for image in $images 11 | do 12 | run_docker 13 | done 14 | 15 | -------------------------------------------------------------------------------- /tests/outside/openeuler.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | images=" 7 | openeuler/openeuler:20.03 8 | openeuler/openeuler:22.03 9 | openeuler/openeuler:22.03-lts-sp1 10 | openeuler/openeuler:22.03-lts-sp2 11 | " 12 | 13 | test_file="openeuler.sh" 14 | 15 | for image in $images 16 | do 17 | run_docker 18 | done 19 | 20 | -------------------------------------------------------------------------------- /tests/outside/openkylin.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | images="openkylinux/yangtze" 7 | test_file="openkylin.sh" 8 | 9 | for image in $images 10 | do 11 | run_docker 12 | done 13 | 14 | -------------------------------------------------------------------------------- /tests/outside/ubuntu.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | 4 | source "$(realpath ${BASH_SOURCE%/*}/..)/utils.sh" 5 | 6 | images=" 7 | ubuntu:23.04 8 | ubuntu:22.04 9 | ubuntu:20.04 10 | " 11 | 12 | test_file="ubuntu.sh" 13 | 14 | for image in $images 15 | do 16 | run_docker 17 | done 18 | 19 | -------------------------------------------------------------------------------- /tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -e 3 | set -o pipefail 4 | 5 | dir=${BASH_SOURCE%/*} 6 | cd $dir/outside 7 | 8 | echo "HUSTMIRROR testing script" 9 | 10 | if ! command -v docker >/dev/null 2>&1; then 11 | echo "docker not found" 12 | exit 1 13 | fi 14 | 15 | for test_file in $(ls ./*) 16 | do 17 | if [ $test_file == "./test.sh" ]; then 18 | continue 19 | fi 20 | 21 | echo "RUNNING $test_file..." 22 | . $test_file 23 | done 24 | -------------------------------------------------------------------------------- /tests/utils.sh: -------------------------------------------------------------------------------- 1 | ROOT_DIR=$(realpath ${BASH_SOURCE[0]%/*}/../) 2 | 3 | # before call this function, you should set $image, $params - an array, $test_file 4 | run_docker() { 5 | printf "TESTING $image...\t" 6 | LDIR=$ROOT_DIR/tests/log/${image//[:\/]/_} 7 | rm -rf $LDIR 8 | mkdir -p $LDIR 9 | docker run -it --rm \ 10 | -v $ROOT_DIR/output:/hustmirror \ 11 | -v $ROOT_DIR/tests/inside:/hmtest \ 12 | -v $LDIR:/hmtest_log \ 13 | -w /hmtest_log \ 14 | ${params[@]} \ 15 | $image bash -c "bash /hmtest/$test_file >/hmtest_log/output.log 2>&1" \ 16 | > $LDIR/docker_output.log 2> $LDIR/docker_output.err || true 17 | 18 | if [ -f $LDIR/pass ]; then 19 | printf "PASS \n" 20 | else 21 | printf "\033[0;31m FAIL!!! \033[0m \n" 22 | fi 23 | } 24 | --------------------------------------------------------------------------------