From c0754cda8db92e7f49aafc9ceab8e522509540fe Mon Sep 17 00:00:00 2001 From: Robert Kaussow Date: Mon, 17 May 2021 13:40:25 +0200 Subject: [PATCH] ci: initial setup (#1) --- .chglog/CHANGELOG.tpl.md | 23 +++++ .chglog/config.yml | 25 ++++++ .drone.star | 126 ++++++++++++++++++++++++++ .github/settings.yml | 58 ++++++++++++ .gitignore | 2 + .renovaterc.json | 4 + LICENSE | 190 +++++++++++++++++++++++++++++++++++++++ README.md | 165 +++++++++++++++++++--------------- retry | 156 ++++++++++++++++---------------- 9 files changed, 598 insertions(+), 151 deletions(-) create mode 100755 .chglog/CHANGELOG.tpl.md create mode 100755 .chglog/config.yml create mode 100644 .drone.star create mode 100644 .github/settings.yml create mode 100644 .gitignore create mode 100644 .renovaterc.json create mode 100644 LICENSE diff --git a/.chglog/CHANGELOG.tpl.md b/.chglog/CHANGELOG.tpl.md new file mode 100755 index 0000000..95a8415 --- /dev/null +++ b/.chglog/CHANGELOG.tpl.md @@ -0,0 +1,23 @@ +# Changelog + +{{ range .Versions -}} +## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} ({{ datetime "2006-01-02" .Tag.Date }}) + +{{ range .CommitGroups -}} +### {{ .Title }} + +{{ range .Commits -}} +- {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} +{{ end }} +{{ end -}} + +{{- if .NoteGroups -}} +{{ range .NoteGroups -}} +### {{ .Title }} + +{{ range .Notes }} +{{ .Body }} +{{ end }} +{{ end -}} +{{ end -}} +{{ end -}} diff --git a/.chglog/config.yml b/.chglog/config.yml new file mode 100755 index 0000000..494a6ac --- /dev/null +++ b/.chglog/config.yml @@ -0,0 +1,25 @@ +style: github +template: CHANGELOG.tpl.md +info: + title: CHANGELOG + repository_url: https://github.com/owncloud-ci/retry +options: + commit_groups: + title_maps: + feat: Features + fix: Bug Fixes + perf: Performance Improvements + refactor: Code Refactoring + chore: Others + test: Testing + ci: CI Pipeline + docs: Documentation + header: + pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" + pattern_maps: + - Type + - Scope + - Subject + notes: + keywords: + - BREAKING CHANGE diff --git a/.drone.star b/.drone.star new file mode 100644 index 0000000..222aa8f --- /dev/null +++ b/.drone.star @@ -0,0 +1,126 @@ +def main(ctx): + before = testing(ctx) + + stages = [] + + after = release(ctx) + notification(ctx) + + for b in before: + for s in stages: + s["depends_on"].append(b["name"]) + + for s in stages: + for a in after: + a["depends_on"].append(s["name"]) + + return before + stages + after + +def testing(ctx): + return [{ + "kind": "pipeline", + "type": "docker", + "name": "testing", + "platform": { + "os": "linux", + "arch": "amd64", + }, + "steps": [ + { + "name": "lint", + "image": "koalaman/shellcheck-alpine:stable", + "commands": [ + "shellcheck ./retry", + ], + }, + ], + "trigger": { + "ref": [ + "refs/heads/master", + "refs/tags/**", + "refs/pull/**", + ], + }, + }] + +def release(ctx): + return [{ + "kind": "pipeline", + "type": "docker", + "name": "release", + "steps": [ + { + "name": "changelog", + "image": "thegeeklab/git-chglog", + "commands": [ + "git fetch -tq", + "git-chglog --no-color --no-emoji %s" % (ctx.build.ref.replace("refs/tags/", "") if ctx.build.event == "tag" else "--next-tag unreleased unreleased"), + "git-chglog --no-color --no-emoji -o CHANGELOG.md %s" % (ctx.build.ref.replace("refs/tags/", "") if ctx.build.event == "tag" else "--next-tag unreleased unreleased"), + ] + }, + { + "name": "release", + "image": "plugins/github-release", + "settings": { + "api_key": { + "from_secret": "github_token", + }, + "note": "CHANGELOG.md", + "overwrite": True, + "title": ctx.build.ref.replace("refs/tags/", ""), + "files": [ + "retry" + ], + }, + "when": { + "ref": [ + "refs/tags/**", + ], + }, + } + ], + "depends_on": [ + "testing", + ], + "trigger": { + "ref": [ + "refs/heads/master", + "refs/tags/**", + "refs/pull/**", + ], + }, + }] + +def notification(ctx): + return [{ + "kind": "pipeline", + "type": "docker", + "name": "notify", + "clone": { + "disable": True, + }, + "steps": [ + { + "name": "notify", + "image": "plugins/slack", + "settings": { + "webhook": { + "from_secret": "private_rocketchat", + }, + "channel": "builds", + }, + } + ], + "depends_on": [ + "release", + ], + "trigger": { + "ref": [ + "refs/heads/master", + "refs/tags/**", + ], + "status": [ + "success", + "failure", + ], + }, + }] diff --git a/.github/settings.yml b/.github/settings.yml new file mode 100644 index 0000000..5930fab --- /dev/null +++ b/.github/settings.yml @@ -0,0 +1,58 @@ +--- +repository: + name: retry + description: Retry any shell command + homepage: https://hub.docker.com/r/owncloudci/retry + topics: tools + + private: false + has_issues: true + has_projects: false + has_wiki: false + has_downloads: false + + default_branch: master + + allow_squash_merge: true + allow_merge_commit: true + allow_rebase_merge: true + +labels: + - name: bug + color: d73a4a + description: Something isn't working + - name: documentation + color: 0075ca + description: Improvements or additions to documentation + - name: duplicate + color: cfd3d7 + description: This issue or pull request already exists + - name: enhancement + color: a2eeef + description: New feature or request + - name: good first issue + color: 7057ff + description: Good for newcomers + - name: help wanted + color: 008672 + description: Extra attention is needed + - name: invalid + color: e4e669 + description: This doesn't seem right + - name: question + color: d876e3 + description: Further information is requested + - name: wontfix + color: ffffff + description: This will not be worked on + +branches: + - name: master + protection: + required_pull_request_reviews: null + required_status_checks: + strict: true + contexts: + - continuous-integration/drone/pr + enforce_admins: null + restrictions: null diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..07ff1e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.drone.yml +CHANGELOG.md diff --git a/.renovaterc.json b/.renovaterc.json new file mode 100644 index 0000000..d7442ec --- /dev/null +++ b/.renovaterc.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["github>owncloud-ci/renovate-presets:docker"] +} diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..86a97ab --- /dev/null +++ b/LICENSE @@ -0,0 +1,190 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + Copyright 2021 ownCloud GmbH + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index e267122..e2a5610 100644 --- a/README.md +++ b/README.md @@ -1,115 +1,132 @@ -retry - The command line retry tool ------------------------------------------- +# retry + +[![Build Status](https://drone.owncloud.com/api/badges/owncloud-ci/retry/status.svg)](https://drone.owncloud.com/owncloud-ci/retry/) +[![Source: GitHub](https://img.shields.io/badge/source-github-blue.svg?logo=github&logoColor=white)](https://github.com/owncloud-ci/retry) +[![License: Apache-2.0](https://img.shields.io/github/license/owncloud-ci/retry)](https://github.com/owncloud-ci/retry/blob/main/LICENSE) Retry any shell command with exponential backoff or constant delay. -### Instructions +## Instructions Install: retry is a shell script, so drop it somewhere and make sure it's added to your $PATH. Or you can use the following one-liner: -```sh -sudo sh -c "curl https://raw.githubusercontent.com/owncloud-ops/retry/master/retry -o /usr/local/bin/retry && chmod +x /usr/local/bin/retry" +```Shell +curl -SsL -o /usr/local/bin/retry https://raw.githubusercontent.com/owncloud-ops/retry/master/retry && chmod +x /usr/local/bin/retry" ``` -### Usage +## Usage Help: -`retry -?` +```Shell +retry -? - Usage: retry [options] -- execute command - -h, -?, --help - -v, --verbose Verbose output - -t, --tries=# Set max retries: Default 10 - -s, --sleep=secs Constant sleep amount (seconds) - -m, --min=secs Exponential Backoff: minimum sleep amount (seconds): Default 0.3 - -x, --max=secs Exponential Backoff: maximum sleep amount (seconds): Default 60 - -f, --fail="script +cmds" Fail Script: run in case of final failure +Usage: retry [options] -- execute command + -h, -?, --help + -v, --verbose Verbose output + -t, --tries=# Set max retries: Default 10 + -s, --sleep=secs Constant sleep amount (seconds) + -m, --min=secs Exponential Backoff: minimum sleep amount (seconds): Default 0.3 + -x, --max=secs Exponential Backoff: maximum sleep amount (seconds): Default 60 + -f, --fail="script +cmds" Fail Script: run in case of final failure +``` -### Examples +## Examples No problem: -`retry echo u work good` +```Shell +retry echo u work good - u work good +u work good +``` Test functionality: -`retry 'echo "y u no work"; false'` +```Shell +retry 'echo "y u no work"; false' - y u no work - Before retry #1: sleeping 0.3 seconds - y u no work - Before retry #2: sleeping 0.6 seconds - y u no work - Before retry #3: sleeping 1.2 seconds - y u no work - Before retry #4: sleeping 2.4 seconds - y u no work - Before retry #5: sleeping 4.8 seconds - y u no work - Before retry #6: sleeping 9.6 seconds - y u no work - Before retry #7: sleeping 19.2 seconds - y u no work - Before retry #8: sleeping 38.4 seconds - y u no work - Before retry #9: sleeping 60.0 seconds - y u no work - Before retry #10: sleeping 60.0 seconds - y u no work - etc.. +y u no work +Before retry #1: sleeping 0.3 seconds +y u no work +Before retry #2: sleeping 0.6 seconds +y u no work +Before retry #3: sleeping 1.2 seconds +y u no work +Before retry #4: sleeping 2.4 seconds +y u no work +Before retry #5: sleeping 4.8 seconds +y u no work +Before retry #6: sleeping 9.6 seconds +y u no work +Before retry #7: sleeping 19.2 seconds +y u no work +Before retry #8: sleeping 38.4 seconds +y u no work +Before retry #9: sleeping 60.0 seconds +y u no work +Before retry #10: sleeping 60.0 seconds +y u no work +etc.. +``` Limit retries: -`retry -t 4 'echo "y u no work"; false'` +```Shell +retry -t 4 'echo "y u no work"; false' - y u no work - Before retry #1: sleeping 0.3 seconds - y u no work - Before retry #2: sleeping 0.6 seconds - y u no work - Before retry #3: sleeping 1.2 seconds - y u no work - Before retry #4: sleeping 2.4 seconds - y u no work - Retries exhausted +y u no work +Before retry #1: sleeping 0.3 seconds +y u no work +Before retry #2: sleeping 0.6 seconds +y u no work +Before retry #3: sleeping 1.2 seconds +y u no work +Before retry #4: sleeping 2.4 seconds +y u no work +Retries exhausted +``` Bad command: -`retry poop` +```Shell +retry poop - bash: poop: command not found +bash: poop: command not found +``` Fail command: -`retry -t 3 -f 'echo "oh poopsickles"' 'echo "y u no work"; false'` +```Shell +retry -t 3 -f 'echo "oh poopsickles"' 'echo "y u no work"; false' - y u no work - Before retry #1: sleeping 0.3 seconds - y u no work - Before retry #2: sleeping 0.6 seconds - y u no work - Before retry #3: sleeping 1.2 seconds - y u no work - Retries exhausted, running fail script - oh poopsickles +y u no work +Before retry #1: sleeping 0.3 seconds +y u no work +Before retry #2: sleeping 0.6 seconds +y u no work +Before retry #3: sleeping 1.2 seconds +y u no work +Retries exhausted, running fail script +oh poopsickles +``` Last attempt passed: -`retry -t 3 -- 'if [ $RETRY_ATTEMPT -eq 3 ]; then echo Passed at attempt $RETRY_ATTEMPT; true; else echo Failed at attempt $RETRY_ATTEMPT; false; fi;'` +```Shell +retry -t 3 -- 'if [ $RETRY_ATTEMPT -eq 3 ]; then echo Passed at attempt $RETRY_ATTEMPT; true; else echo Failed at attempt $RETRY_ATTEMPT; false; fi;' - Failed at attempt 0 - Before retry #1: sleeping 0.3 seconds - Failed at attempt 1 - Before retry #2: sleeping 0.6 seconds - Failed at attempt 2 - Before retry #3: sleeping 1.2 seconds - Passed at attempt 3 +Failed at attempt 0 +Before retry #1: sleeping 0.3 seconds +Failed at attempt 1 +Before retry #2: sleeping 0.6 seconds +Failed at attempt 2 +Before retry #3: sleeping 1.2 seconds +Passed at attempt 3 +``` -### License +## License -Apache 2.0 - go nuts +This project is licensed under the Apache 2.0 License - see the [LICENSE](https://github.com/owncloud-ci/retry/blob/master/LICENSE) file for details. diff --git a/retry b/retry index d56e89c..dc89a3b 100755 --- a/retry +++ b/retry @@ -1,4 +1,5 @@ #!/usr/bin/env sh + GETOPT_BIN=$IN_GETOPT_BIN GETOPT_BIN=${GETOPT_BIN:-getopt} @@ -8,7 +9,7 @@ __sleep_amount() { else #TODO: check for awk #TODO: check if user would rather use one of the other possible dependencies: python, ruby, bc, dc - sleep_time=$(awk "BEGIN {t = $min_sleep * $(( (1<<(attempts -1)) )); print (t > $max_sleep ? $max_sleep : t)}") + sleep_time=$(awk "BEGIN {t = $min_sleep * $(((1 << (_retry_attempts - 1)))); print (t > $max_sleep ? $max_sleep : t)}") fi } @@ -17,65 +18,66 @@ __log_out() { } # Parameters: max_tries min_sleep max_sleep constant_sleep fail_script EXECUTION_COMMAND -retry() -{ - local max_tries="$1"; shift - local min_sleep="$1"; shift - local max_sleep="$1"; shift - local constant_sleep="$1"; shift - local fail_script="$1"; shift +retry() { + _retry_max_tries="$1" + shift + _retry_min_sleep="$1" + shift + _retry_max_sleep="$1" + shift + _retry_constant_sleep="$1" + shift + _retry_fail_script="$1" + shift if [ -n "$VERBOSE" ]; then - __log_out "Retry Parameters: max_tries=$max_tries min_sleep=$min_sleep max_sleep=$max_sleep constant_sleep=$constant_sleep" - if [ -n "$fail_script" ]; then __log_out "Fail script: $fail_script"; fi + __log_out "Retry Parameters: max_tries=$_retry_max_tries min_sleep=$_retry_min_sleep max_sleep=$_retry_max_sleep constant_sleep=$_retry_constant_sleep" + if [ -n "$_retry_fail_script" ]; then __log_out "Fail script: $_retry_fail_script"; fi __log_out "" __log_out "Execution Command: $*" __log_out "" fi - local attempts=0 - local return_code=1 + _retry_attempts=0 + _retry_return_code=1 - - while [ "$return_code" -ne 0 ] && [ "$attempts" -le "$max_tries" ]; do - if [ $attempts -gt 0 ]; then + while [ "$_retry_return_code" -ne 0 ] && [ "$_retry_attempts" -le "$_retry_max_tries" ]; do + if [ $_retry_attempts -gt 0 ]; then __sleep_amount - __log_out "Before retry #$attempts: sleeping $sleep_time seconds" + __log_out "Before retry #$_retry_attempts: sleeping $sleep_time seconds" sleep "$sleep_time" fi P="$1" #for param in "${@:2}"; do P="$P '$param'"; done #TODO: replace single quotes in each arg with '"'"' ? - export RETRY_ATTEMPT=$attempts + export RETRY_ATTEMPT=$_retry_attempts sh -c "$P" - return_code=$? - #__log_out "Process returned $return_code on attempt $attempts" - if [ $return_code -eq 127 ]; then + _retry_return_code=$? + #__log_out "Process returned $_retry_return_code on attempt $_retry_attempts" + if [ $_retry_return_code -eq 127 ]; then # command not found - exit $return_code - elif [ $return_code -ne 0 ]; then - attempts=$((attempts +1)) + exit $_retry_return_code + elif [ $_retry_return_code -ne 0 ]; then + _retry_attempts=$((_retry_attempts + 1)) fi done - if [ "$attempts" -gt "$max_tries" ]; then - if [ -n "$fail_script" ]; then + if [ "$_retry_attempts" -gt "$_retry_max_tries" ]; then + if [ -n "$_retry_fail_script" ]; then __log_out "Retries exhausted, running fail script" - eval "$fail_script" + eval "$_retry_fail_script" else __log_out "Retries exhausted" fi fi - exit $return_code + exit $_retry_return_code } - -help() -{ -local retry=$(basename "$0") -cat < /dev/null +$GETOPT_BIN --test >/dev/null if [ $? -ne 4 ]; then - echo "I’m sorry, 'getopt --test' failed in this environment. Please load GNU getopt." - exit 1 + echo "I’m sorry, 'getopt --test' failed in this environment. Please load GNU getopt." + exit 1 fi OPTIONS=vt:s:m:x:f: LONGOPTIONS=verbose,tries:,sleep:,min:,max:,fail: PARSED=$($GETOPT_BIN --options="$OPTIONS" --longoptions="$LONGOPTIONS" --name "$0" -- "$@") +# shellcheck disable=SC2181 if [ $? -ne 0 ]; then -# e.g. $? == 1 -# then getopt has complained about wrong arguments to stdout -exit 2 + # e.g. $? == 1 + # then getopt has complained about wrong arguments to stdout + exit 2 fi # read getopt’s output this way to handle the quoting right: eval set -- "$PARSED" @@ -119,40 +121,40 @@ fail_script= # now enjoy the options in order and nicely split until we see -- while true; do - case "$1" in - -v|--verbose) - VERBOSE=true - shift - ;; - -t|--tries) - max_tries="$2" - shift 2 - ;; - -s|--sleep) - constant_sleep="$2" - shift 2 - ;; - -m|--min) - min_sleep="$2" - shift 2 - ;; - -x|--max) - max_sleep="$2" - shift 2 - ;; - -f|--fail) - fail_script="$2" - shift 2 - ;; - --) - shift - break - ;; - *) - echo "Programming error" - exit 3 - ;; - esac + case "$1" in + -v | --verbose) + VERBOSE=true + shift + ;; + -t | --tries) + max_tries="$2" + shift 2 + ;; + -s | --sleep) + constant_sleep="$2" + shift 2 + ;; + -m | --min) + min_sleep="$2" + shift 2 + ;; + -x | --max) + max_sleep="$2" + shift 2 + ;; + -f | --fail) + fail_script="$2" + shift 2 + ;; + --) + shift + break + ;; + *) + echo "Programming error" + exit 3 + ;; + esac done retry "$max_tries" "$min_sleep" "$max_sleep" "$constant_sleep" "$fail_script" "$@"