filtron.sh 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642
  1. #!/usr/bin/env bash
  2. # SPDX-License-Identifier: AGPL-3.0-or-later
  3. # shellcheck disable=SC2001
  4. # shellcheck source=utils/lib.sh
  5. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  6. # shellcheck source=utils/lib_install.sh
  7. source "${REPO_ROOT}/utils/lib_install.sh"
  8. # ----------------------------------------------------------------------------
  9. # config
  10. # ----------------------------------------------------------------------------
  11. PUBLIC_HOST="${PUBLIC_HOST:-$(echo "$PUBLIC_URL" | sed -e 's/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/')}"
  12. FILTRON_URL_PATH="${FILTRON_URL_PATH:-$(echo "${PUBLIC_URL}" \
  13. | sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
  14. [[ "${FILTRON_URL_PATH}" == "${PUBLIC_URL}" ]] && FILTRON_URL_PATH=/
  15. FILTRON_ETC="/etc/filtron"
  16. FILTRON_RULES="$FILTRON_ETC/rules.json"
  17. FILTRON_RULES_TEMPLATE="${FILTRON_RULES_TEMPLATE:-${REPO_ROOT}/utils/templates/etc/filtron/rules.json}"
  18. FILTRON_API="${FILTRON_API:-127.0.0.1:4005}"
  19. FILTRON_LISTEN="${FILTRON_LISTEN:-127.0.0.1:4004}"
  20. # The filtron target is the SearXNG installation, listenning on server.port at
  21. # server.bind_address. The default of FILTRON_TARGET is taken from the YAML
  22. # configuration, do not change this value without reinstalling the entire
  23. # SearXNG suite including filtron & morty.
  24. FILTRON_TARGET="${SEARXNG_BIND_ADDRESS}:${SEARXNG_PORT}"
  25. SERVICE_NAME="filtron"
  26. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  27. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  28. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  29. SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
  30. # shellcheck disable=SC2034
  31. SERVICE_GROUP="${SERVICE_USER}"
  32. # shellcheck disable=SC2034
  33. SERVICE_GROUP="${SERVICE_USER}"
  34. GO_ENV="${SERVICE_HOME}/.go_env"
  35. GO_VERSION="go1.17.2"
  36. GO_PKG_URL="https://golang.org/dl/${GO_VERSION}.linux-amd64.tar.gz"
  37. GO_TAR=$(basename "$GO_PKG_URL")
  38. APACHE_FILTRON_SITE="searxng.conf"
  39. NGINX_FILTRON_SITE="searxng.conf"
  40. # shellcheck disable=SC2034
  41. CONFIG_FILES=(
  42. "${FILTRON_RULES}"
  43. "${SERVICE_SYSTEMD_UNIT}"
  44. )
  45. # ----------------------------------------------------------------------------
  46. usage() {
  47. # ----------------------------------------------------------------------------
  48. # shellcheck disable=SC1117
  49. cat <<EOF
  50. usage::
  51. $(basename "$0") shell
  52. $(basename "$0") install [all|user|rules]
  53. $(basename "$0") reinstall all
  54. $(basename "$0") update [filtron]
  55. $(basename "$0") remove [all]
  56. $(basename "$0") activate [service]
  57. $(basename "$0") deactivate [service]
  58. $(basename "$0") inspect [service]
  59. $(basename "$0") option [debug-on|debug-off]
  60. $(basename "$0") apache [install|remove]
  61. $(basename "$0") nginx [install|remove]
  62. shell
  63. start interactive shell from user ${SERVICE_USER}
  64. install / remove
  65. :all: complete setup of filtron service
  66. :user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  67. :rules: reinstall filtron rules $FILTRON_RULES
  68. install
  69. :check: check the filtron installation
  70. reinstall:
  71. :all: runs 'install/remove all'
  72. update filtron
  73. Update filtron installation ($SERVICE_HOME)
  74. activate service
  75. activate and start service daemon (systemd unit)
  76. deactivate service
  77. stop and deactivate service daemon (systemd unit)
  78. inspect service
  79. show service status and log
  80. option
  81. set one of the available options
  82. apache (${PUBLIC_URL})
  83. :install: apache site with a reverse proxy (ProxyPass)
  84. :remove: apache site ${APACHE_FILTRON_SITE}
  85. nginx (${PUBLIC_URL})
  86. :install: nginx site with a reverse proxy (ProxyPass)
  87. :remove: nginx site ${NGINX_FILTRON_SITE}
  88. filtron rules: ${FILTRON_RULES_TEMPLATE}
  89. ---- sourced ${DOT_CONFIG} :
  90. SERVICE_USER : ${SERVICE_USER}
  91. SERVICE_HOME : ${SERVICE_HOME}
  92. FILTRON_TARGET : ${FILTRON_TARGET}
  93. FILTRON_API : ${FILTRON_API}
  94. FILTRON_LISTEN : ${FILTRON_LISTEN}
  95. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  96. EOF
  97. install_log_searx_instance
  98. [[ -n ${1} ]] && err_msg "$1"
  99. }
  100. main() {
  101. required_commands \
  102. sudo install git wget curl \
  103. || exit
  104. local _usage="unknown or missing $1 command $2"
  105. case $1 in
  106. --getenv) var="$2"; echo "${!var}"; exit 0;;
  107. -h|--help) usage; exit 0;;
  108. shell)
  109. sudo_or_exit
  110. interactive_shell "${SERVICE_USER}"
  111. ;;
  112. inspect)
  113. case $2 in
  114. service)
  115. sudo_or_exit
  116. inspect_service
  117. ;;
  118. *) usage "$_usage"; exit 42;;
  119. esac ;;
  120. reinstall)
  121. rst_title "re-install $SERVICE_NAME" part
  122. sudo_or_exit
  123. case $2 in
  124. all)
  125. remove_all
  126. install_all
  127. ;;
  128. *) usage "$_usage"; exit 42;;
  129. esac ;;
  130. install)
  131. rst_title "$SERVICE_NAME" part
  132. sudo_or_exit
  133. case $2 in
  134. check)
  135. rst_title "Check filtron installation" part
  136. install_check
  137. ;;
  138. all) install_all ;;
  139. user) assert_user ;;
  140. rules)
  141. install_rules
  142. systemd_restart_service "${SERVICE_NAME}"
  143. ;;
  144. *) usage "$_usage"; exit 42;;
  145. esac ;;
  146. update)
  147. sudo_or_exit
  148. case $2 in
  149. filtron) update_filtron ;;
  150. *) usage "$_usage"; exit 42;;
  151. esac ;;
  152. remove)
  153. sudo_or_exit
  154. case $2 in
  155. all) remove_all;;
  156. user) drop_service_account "${SERVICE_USER}" ;;
  157. *) usage "$_usage"; exit 42;;
  158. esac ;;
  159. activate)
  160. sudo_or_exit
  161. case $2 in
  162. service) systemd_activate_service "${SERVICE_NAME}" ;;
  163. *) usage "$_usage"; exit 42;;
  164. esac ;;
  165. deactivate)
  166. sudo_or_exit
  167. case $2 in
  168. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  169. *) usage "$_usage"; exit 42;;
  170. esac ;;
  171. apache)
  172. sudo_or_exit
  173. case $2 in
  174. install) install_apache_site ;;
  175. remove) remove_apache_site ;;
  176. *) usage "$_usage"; exit 42;;
  177. esac ;;
  178. nginx)
  179. sudo_or_exit
  180. case $2 in
  181. install) install_nginx_site ;;
  182. remove) remove_nginx_site ;;
  183. *) usage "$_usage"; exit 42;;
  184. esac ;;
  185. option)
  186. sudo_or_exit
  187. case $2 in
  188. debug-on) echo; enable_debug ;;
  189. debug-off) echo; disable_debug ;;
  190. *) usage "$_usage"; exit 42;;
  191. esac ;;
  192. doc) rst-doc ;;
  193. *) usage "unknown or missing command $1"; exit 42;;
  194. esac
  195. }
  196. install_all() {
  197. rst_title "Install $SERVICE_NAME (service)"
  198. assert_user
  199. wait_key
  200. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  201. wait_key
  202. install_filtron
  203. install_rules
  204. wait_key
  205. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  206. wait_key
  207. echo
  208. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  209. err_msg "Filtron is not listening on: http://${FILTRON_LISTEN}"
  210. fi
  211. if apache_is_installed; then
  212. info_msg "Apache is installed on this host."
  213. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  214. install_apache_site
  215. fi
  216. elif nginx_is_installed; then
  217. info_msg "nginx is installed on this host."
  218. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  219. install_nginx_site
  220. fi
  221. fi
  222. if ask_yn "Do you want to inspect the installation?" Ny; then
  223. inspect_service
  224. fi
  225. }
  226. install_check() {
  227. if service_account_is_available "$SERVICE_USER"; then
  228. info_msg "service account $SERVICE_USER available."
  229. else
  230. err_msg "service account $SERVICE_USER not available!"
  231. fi
  232. if go_is_available "$SERVICE_USER"; then
  233. info_msg "~$SERVICE_USER: go is installed"
  234. else
  235. err_msg "~$SERVICE_USER: go is not installed"
  236. fi
  237. if filtron_is_installed; then
  238. info_msg "~$SERVICE_USER: filtron app is installed"
  239. else
  240. err_msg "~$SERVICE_USER: filtron app is not installed!"
  241. fi
  242. if ! service_is_available "http://${FILTRON_API}"; then
  243. err_msg "API not available at: http://${FILTRON_API}"
  244. fi
  245. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  246. err_msg "Filtron is not listening on: http://${FILTRON_LISTEN}"
  247. fi
  248. if service_is_available "http://${FILTRON_TARGET}" ; then
  249. info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
  250. fi
  251. if ! service_is_available "${PUBLIC_URL}"; then
  252. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  253. if ! in_container; then
  254. warn_msg "Check if public name is correct and routed or use the public IP from above."
  255. fi
  256. fi
  257. if [[ "${GO_VERSION}" > "$(go_version)" ]]; then
  258. warn_msg "golang ($(go_version)) needs to be $GO_VERSION at least"
  259. warn_msg "you need to reinstall $SERVICE_USER --> $0 reinstall all"
  260. else
  261. info_msg "golang $(go_version) is installed (min needed is: $GO_VERSION)"
  262. fi
  263. if [ -f "${APACHE_SITES_AVAILABLE}/searx.conf" ]; then
  264. warn_msg "old searx.conf apache site exists"
  265. fi
  266. if [ -f "${NGINX_APPS_AVAILABLE}/searx.conf" ]; then
  267. warn_msg "old searx.conf nginx site exists"
  268. fi
  269. }
  270. go_version(){
  271. sudo -i -u "$SERVICE_USER" <<EOF
  272. go version | cut -d' ' -f 3
  273. EOF
  274. }
  275. remove_all() {
  276. rst_title "De-Install $SERVICE_NAME (service)"
  277. rst_para "\
  278. It goes without saying that this script can only be used to remove
  279. installations that were installed with this script."
  280. if ! systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  281. return 42
  282. fi
  283. drop_service_account "${SERVICE_USER}"
  284. rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
  285. if service_is_available "${PUBLIC_URL}"; then
  286. MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  287. fi
  288. }
  289. assert_user() {
  290. rst_title "user $SERVICE_USER" section
  291. echo
  292. tee_stderr 1 <<EOF | bash | prefix_stdout
  293. useradd --shell /bin/bash --system \
  294. --home-dir "$SERVICE_HOME" \
  295. --comment 'Reverse HTTP proxy to filter requests' $SERVICE_USER
  296. mkdir "$SERVICE_HOME"
  297. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  298. groups $SERVICE_USER
  299. EOF
  300. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  301. export SERVICE_HOME
  302. echo "export SERVICE_HOME=$SERVICE_HOME"
  303. cat > "$GO_ENV" <<EOF
  304. export GOPATH=\$HOME/go-apps
  305. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  306. EOF
  307. echo "Environment $GO_ENV has been setup."
  308. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  309. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  310. EOF
  311. }
  312. filtron_is_installed() {
  313. [[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
  314. }
  315. _svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
  316. install_filtron() {
  317. rst_title "Install filtron in user's ~/go-apps" section
  318. echo
  319. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  320. go get -v -u github.com/asciimoo/filtron
  321. EOF
  322. }
  323. update_filtron() {
  324. rst_title "Update filtron" section
  325. echo
  326. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  327. go get -v -u github.com/asciimoo/filtron
  328. EOF
  329. }
  330. install_rules() {
  331. rst_title "Install filtron rules"
  332. echo
  333. if [[ ! -f "${FILTRON_RULES}" ]]; then
  334. info_msg "install rules ${FILTRON_RULES_TEMPLATE}"
  335. info_msg " --> ${FILTRON_RULES}"
  336. mkdir -p "$(dirname "${FILTRON_RULES}")"
  337. cp "${FILTRON_RULES_TEMPLATE}" "${FILTRON_RULES}"
  338. return
  339. fi
  340. if cmp --silent "${FILTRON_RULES}" "${FILTRON_RULES_TEMPLATE}"; then
  341. info_msg "${FILTRON_RULES} is up to date with"
  342. info_msg "${FILTRON_RULES_TEMPLATE}"
  343. return
  344. fi
  345. rst_para "Diff between origin's rules file (+) and current (-):"
  346. echo "${FILTRON_RULES}" "${FILTRON_RULES_TEMPLATE}"
  347. $DIFF_CMD "${FILTRON_RULES}" "${FILTRON_RULES_TEMPLATE}"
  348. local action
  349. choose_one action "What should happen to the rules file? " \
  350. "keep configuration unchanged" \
  351. "use origin rules" \
  352. "start interactive shell"
  353. case $action in
  354. "keep configuration unchanged")
  355. info_msg "leave rules file unchanged"
  356. ;;
  357. "use origin rules")
  358. backup_file "${FILTRON_RULES}"
  359. info_msg "install origin rules"
  360. cp "${FILTRON_RULES_TEMPLATE}" "${FILTRON_RULES}"
  361. ;;
  362. "start interactive shell")
  363. backup_file "${FILTRON_RULES}"
  364. echo -e "// exit with [${_BCyan}CTRL-D${_creset}]"
  365. sudo -H -i
  366. rst_para 'Diff between new rules file (-) and current (+):'
  367. echo
  368. $DIFF_CMD "${FILTRON_RULES_TEMPLATE}" "${FILTRON_RULES}"
  369. wait_key
  370. ;;
  371. esac
  372. }
  373. inspect_service() {
  374. rst_title "service status & log"
  375. cat <<EOF
  376. sourced ${DOT_CONFIG} :
  377. SERVICE_USER : ${SERVICE_USER}
  378. SERVICE_HOME : ${SERVICE_HOME}
  379. FILTRON_TARGET : ${FILTRON_TARGET}
  380. FILTRON_API : ${FILTRON_API}
  381. FILTRON_LISTEN : ${FILTRON_LISTEN}
  382. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  383. EOF
  384. install_log_searx_instance
  385. install_check
  386. if in_container; then
  387. lxc_suite_info
  388. else
  389. info_msg "public URL --> ${PUBLIC_URL}"
  390. info_msg "internal URL --> http://${FILTRON_LISTEN}"
  391. fi
  392. local _debug_on
  393. if ask_yn "Enable filtron debug mode?"; then
  394. enable_debug
  395. _debug_on=1
  396. fi
  397. echo
  398. systemctl --no-pager -l status "${SERVICE_NAME}"
  399. echo
  400. info_msg "public URL --> ${PUBLIC_URL}"
  401. # shellcheck disable=SC2059
  402. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  403. read -r -s -n1 -t 5
  404. echo
  405. while true; do
  406. trap break 2
  407. journalctl -f -u "${SERVICE_NAME}"
  408. done
  409. if [[ $_debug_on == 1 ]]; then
  410. disable_debug
  411. fi
  412. return 0
  413. }
  414. enable_debug() {
  415. info_msg "try to enable debug mode ..."
  416. python <<EOF
  417. import sys, json
  418. debug = {
  419. u'name': u'debug request'
  420. , u'filters': []
  421. , u'interval': 0
  422. , u'limit': 0
  423. , u'actions': [{u'name': u'log'}]
  424. }
  425. with open('$FILTRON_RULES') as rules:
  426. j = json.load(rules)
  427. pos = None
  428. for i in range(len(j)):
  429. if j[i].get('name') == 'debug request':
  430. pos = i
  431. break
  432. if pos is not None:
  433. j[pos] = debug
  434. else:
  435. j.append(debug)
  436. with open('$FILTRON_RULES', 'w') as rules:
  437. json.dump(j, rules, indent=2, sort_keys=True)
  438. EOF
  439. systemctl restart "${SERVICE_NAME}.service"
  440. }
  441. disable_debug() {
  442. info_msg "try to disable debug mode ..."
  443. python <<EOF
  444. import sys, json
  445. with open('$FILTRON_RULES') as rules:
  446. j = json.load(rules)
  447. pos = None
  448. for i in range(len(j)):
  449. if j[i].get('name') == 'debug request':
  450. pos = i
  451. break
  452. if pos is not None:
  453. del j[pos]
  454. with open('$FILTRON_RULES', 'w') as rules:
  455. json.dump(j, rules, indent=2, sort_keys=True)
  456. EOF
  457. systemctl restart "${SERVICE_NAME}.service"
  458. }
  459. install_apache_site() {
  460. rst_title "Install Apache site $APACHE_FILTRON_SITE"
  461. rst_para "\
  462. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_FILTRON_SITE})"
  463. ! apache_is_installed && info_msg "Apache is not installed."
  464. if ! ask_yn "Do you really want to continue?" Yn; then
  465. return
  466. else
  467. install_apache
  468. fi
  469. "${REPO_ROOT}/utils/searx.sh" install uwsgi
  470. apache_install_site --variant=filtron "${APACHE_FILTRON_SITE}"
  471. info_msg "testing public url .."
  472. if ! service_is_available "${PUBLIC_URL}"; then
  473. err_msg "Public service at ${PUBLIC_URL} is not available!"
  474. fi
  475. }
  476. remove_apache_site() {
  477. rst_title "Remove Apache site $APACHE_FILTRON_SITE"
  478. rst_para "\
  479. This removes apache site ${APACHE_FILTRON_SITE}."
  480. ! apache_is_installed && err_msg "Apache is not installed."
  481. if ! ask_yn "Do you really want to continue?" Yn; then
  482. return
  483. fi
  484. apache_remove_site "$APACHE_FILTRON_SITE"
  485. }
  486. install_nginx_site() {
  487. rst_title "Install nginx site $NGINX_FILTRON_SITE"
  488. rst_para "\
  489. This installs a reverse proxy (ProxyPass) into nginx site (${NGINX_FILTRON_SITE})"
  490. ! nginx_is_installed && info_msg "nginx is not installed."
  491. if ! ask_yn "Do you really want to continue?" Yn; then
  492. return
  493. else
  494. install_nginx
  495. fi
  496. "${REPO_ROOT}/utils/searx.sh" install uwsgi
  497. # shellcheck disable=SC2034
  498. SEARX_SRC=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARX_SRC)
  499. # shellcheck disable=SC2034
  500. SEARXNG_URL_PATH=$("${REPO_ROOT}/utils/searx.sh" --getenv SEARXNG_URL_PATH)
  501. nginx_install_app --variant=filtron "${NGINX_FILTRON_SITE}"
  502. info_msg "testing public url .."
  503. if ! service_is_available "${PUBLIC_URL}"; then
  504. err_msg "Public service at ${PUBLIC_URL} is not available!"
  505. fi
  506. }
  507. remove_nginx_site() {
  508. rst_title "Remove nginx site $NGINX_FILTRON_SITE"
  509. rst_para "\
  510. This removes nginx site ${NGINX_FILTRON_SITE}."
  511. ! nginx_is_installed && err_msg "nginx is not installed."
  512. if ! ask_yn "Do you really want to continue?" Yn; then
  513. return
  514. fi
  515. nginx_remove_site "$FILTRON_FILTRON_SITE"
  516. }
  517. rst-doc() {
  518. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/filtron.rst")\""
  519. echo -e "\n.. START install systemd unit"
  520. cat <<EOF
  521. .. tabs::
  522. .. group-tab:: systemd
  523. .. code:: bash
  524. EOF
  525. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  526. echo -e "\n.. END install systemd unit"
  527. # for DIST_NAME in ubuntu-20.04 arch fedora centos; do
  528. # (
  529. # DIST_ID=${DIST_NAME%-*}
  530. # DIST_VERS=${DIST_NAME#*-}
  531. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  532. # # ...
  533. # )
  534. # done
  535. }
  536. # ----------------------------------------------------------------------------
  537. main "$@"
  538. # ----------------------------------------------------------------------------