├── .editorconfig ├── .gitignore ├── .travis.yml ├── Dockerfile ├── EXAMPLES.md ├── LICENSE.md ├── Makefile ├── README.md ├── REGEX_CONTRIBUTIONS.md ├── bin ├── file-cr ├── file-crlf ├── file-empty ├── file-nullbyte-char ├── file-trailing-newline ├── file-trailing-single-newline ├── file-trailing-space ├── file-utf8 ├── file-utf8-bom ├── git-conflicts ├── git-ignored ├── inline-css ├── inline-js ├── regex-grep ├── regex-grep-negative ├── regex-perl ├── syntax-bash ├── syntax-css ├── syntax-js ├── syntax-json ├── syntax-markdown ├── syntax-perl ├── syntax-php ├── syntax-python ├── syntax-ruby ├── syntax-scss └── syntax-sh ├── composer.json ├── configure ├── dependencies ├── README.md └── aci-trailing-newline ├── etc └── awesome-ci.conf └── test ├── README.md ├── err ├── file-cr_err ├── file-crlf_err ├── file-empty_err ├── file-nullbyte-char_err.bin ├── file-trailing-newline_err ├── file-trailing-single-newline_err ├── file-trailing-space_err ├── file-utf8-bom_err ├── file-utf8_err ├── git-conflicts_err ├── inline-css_err.html ├── inline-js_err.html ├── syntax-bash_err.bash ├── syntax-css_err.css ├── syntax-js_err.js ├── syntax-json_err.json ├── syntax-markdown_err.md ├── syntax-perl_err.pl ├── syntax-php_err.php ├── syntax-python_err.py ├── syntax-ruby_err.rb ├── syntax-scss_err.scss └── syntax-sh_err.sh ├── ok ├── file-crlf_ok ├── file-empty_ok ├── file-nullbyte-char_ok.bin ├── file-trailing-newline_ok ├── file-trailing-single-newline_ok ├── file-trailing-space_ok ├── file-utf8-bom_ok ├── file-utf8_ok ├── git-conflicts_ok ├── inline-css_ok.html ├── inline-js_ok.html ├── syntax-bash_ok.bash ├── syntax-css_ok.css ├── syntax-js_ok.js ├── syntax-json_ok.json ├── syntax-markdown_ok.md ├── syntax-perl_ok.pl ├── syntax-php_ok.php ├── syntax-python_ok.py ├── syntax-ruby_ok.rb ├── syntax-scss_ok.scss └── syntax-sh_ok.sh ├── test.sh └── test_single.sh /.editorconfig: -------------------------------------------------------------------------------- 1 | # @see http://editorconfig.org/ 2 | # @version 1.0 3 | # @date 2016-03-10 4 | # @author Patrick Plocke 5 | 6 | # This is the top-most .editorconfig file; do not search in parent directories. 7 | root = true 8 | 9 | # All files. 10 | [*] 11 | charset = utf-8 12 | end_of_line = LF 13 | indent_style = tab 14 | indent_size = 4 15 | trim_trailing_whitespace = true 16 | insert_final_newline = true 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ###################################### 2 | # CUSTOM 3 | ###################################### 4 | 5 | configure.in 6 | Makefile.in 7 | 8 | ###################################### 9 | # GENERIC 10 | ###################################### 11 | 12 | ###### std ###### 13 | .lock 14 | *.log 15 | 16 | ###### patches/diffs ###### 17 | *.patch 18 | *.diff 19 | *.orig 20 | *.rej 21 | 22 | ###### python ###### 23 | *.pyc 24 | 25 | ###################################### 26 | # Operating Systems 27 | ###################################### 28 | 29 | ###### OSX ###### 30 | ._* 31 | .DS* 32 | .Spotlight-V100 33 | .Trashes 34 | 35 | ###### Windows ###### 36 | Thumbs.db 37 | ehthumbs.db 38 | Desktop.ini 39 | $RECYCLE.BIN/ 40 | *.lnk 41 | 42 | 43 | ###################################### 44 | # Editors 45 | ###################################### 46 | 47 | ###### Sublime ###### 48 | *.sublime-workspace 49 | *.sublime-project 50 | 51 | ###### Eclipse ###### 52 | .classpath 53 | .buildpath 54 | .project 55 | .settings/ 56 | 57 | ###### Netbeans ###### 58 | nbproject/private/ 59 | 60 | ###### Intellij IDE ###### 61 | .idea/ 62 | .idea_modules/ 63 | 64 | ###### vim ###### 65 | *.swp 66 | *.swo 67 | *~ 68 | 69 | ###### TextMate ###### 70 | .tm_properties 71 | *.tmproj 72 | 73 | ###### BBEdit ###### 74 | *.bbprojectd 75 | *.bbproject 76 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | ### 2 | ### Choose OS 3 | ### 4 | sudo: required 5 | dist: trusty 6 | 7 | 8 | ### 9 | ### Choose Environment 10 | ### 11 | language: ruby 12 | rvm: 2.5.0 13 | services: docker 14 | 15 | 16 | ### 17 | ### Env variables 18 | ### 19 | env: 20 | global: 21 | - image=cytopia/awesome-ci 22 | # travis encrypt DOCKER_USERNAME=user 23 | # travis encrypt DOCKER_PASSWORD=pass 24 | # Must be regenerated when repository name/owner changes 25 | # DOCKER_USERNAME 26 | - secure: "UUqp9snjT3BpAaFt7c6Q7xelG6YowlmlPep9/6xmKIFL0ezjAAb9caRO1lu511Z/f17RXq7RQJtvrmjstBYh3MndR5EYavva4V4O09jg2SPdPMJcez6aB9Hsl/uOL8bdsbra0jJdtftWfNaVOeVPGac0bmTIbLga17FCu/A6lxRhREnnOJcnHOpWnlufU1U/ccY/SvS9j+gHxV4Tj0/yDNi589yhrFMxCg4FpNdc3EEuf8GtHx3gtYUqkBfdKniHIab4SUyP4ZRydjb2WBQ5lnwSGRAuXvBEV3Zlo9bMKAgAr5q/9qW4FKbnETo/LzdwbUW1MC8EesT2+j5fsYJf0DE9yyvIaJbAfAf8YMkQp6f7H1negSbj/Fa0mMC53IRrO3uu/X957/jWrxwzGPZC/Eq4H+axiZ/7nQIHN9uoXpCWbGcbe2PHO9ohyCBQ60CHc/eA2Z/DwB8HsB15QU6Lr0rDAsZ8YpNBFAFgAuirleSXffzHXIlVrJ8ro325EYA248u9+/8MgZ/9VbI7bPMIv36OFVvZcpKzAd25ih8j1oqv8iSHMfp7hUL5/H8ReZtVs2H0OsrsvZ/lc3Xx45R0/ZNHj46vz7FBoZ7yHvtr5m6X2p7THx2hLGb011yvpw2q1Rg3xAhuvdfkc+TwgPdrZXY6Ty3LU4+MwwLtGRauC4Y=" 27 | # DOCKER_PASSWORD 28 | - secure: "NRLUpUka7C3pHFJugilLzd+fpFOJ2Xv5x86ctyjwJkmWXDKXI6Bjo59AMbKilrUOTpfcFATPY4PX0NpJqCK1sRFcthjfjpA5FYigoiKOdlkohapnxaBghnYXippmDUrHorWd7WoFS0l5vgeOhAkhH7Gh8oac0BT7rbFygWNgFPtFmI4UaleF4w/46K/qiDyrjZFtb2kueEFZzt6iM5T1naJOq2/Werg0GJ10Z8TqPeG+0FjfUjFiV3+2nB4zO575qDoPayinhfjyBDZQuLtvdFugvLXeT2cX3DBW8A4wxgq/rrGtKXArjdoUHQeFQumFoGHkYdnUfIWIj6mcI3euUL7H1NzhAt3n969tgyz4mhrIVh0KVVlvs3eL3EaPDMu79OR2APN2vHK4/Mg0X3nu7FPOWxA7vpubbAqlQNYN3eJf/Q2rdkth3o4HXGVdHUFCbWfFcVvMfKF5PDCgmpiXuRnhoVrsRgizyrFcBxguHdCvEo89rnykmZ5zQZyBb9JNAc/Tdnxb0tLKsll8fFt+o3hl/FVLZiwfhLbV/bdbPLGY92epzOUDA6qGdYlYzB4H8XC168nR+chKyT1aF2cRfIoTk5uWoGFCQaT0fHwOKlaartNlqmCNGLv0Wr+hb6kB5Kpm77iHijRz0tpux5xiEwnlO4WyH1LBFPtbxaebO1o=" 29 | 30 | 31 | ### 32 | ### Install dependencies 33 | ### 34 | before_install: 35 | # Add more modern repos 36 | - max=100; i=0; while [ $i -lt $max ]; do if sudo apt-get update; then break; else i=$((i+1)); fi done 37 | - max=100; i=0; while [ $i -lt $max ]; do if sudo apt-get -y install python-software-properties; then break; else i=$((i+1)); fi done 38 | - sudo add-apt-repository -y ppa:brightbox/ruby-ng 39 | - sudo add-apt-repository -y "deb http://archive.ubuntu.com/ubuntu/ trusty-backports restricted main universe" 40 | 41 | # Install dependencies 42 | - max=100; i=0; while [ $i -lt $max ]; do if sudo apt-get update; then break; else i=$((i+1)); fi done 43 | - max=100; i=0; while [ $i -lt $max ]; do if sudo apt-get -y install 44 | gcc 45 | gcc-multilib 46 | make 47 | ruby2.5 48 | ruby2.5-dev 49 | ruby-switch 50 | moreutils 51 | shellcheck 52 | moreutils 53 | php5-cli 54 | dos2unix 55 | docker-ce; 56 | then break; else i=$((i+1)); fi done 57 | 58 | # Set ruby version 59 | - ruby-switch --list 60 | - sudo ruby-switch --set ruby2.5 61 | - ruby -v 62 | - gem -v 63 | # 64 | # - sudo gem update bundler 65 | # - sudo gem pristine executable-hooks --version 1.3.2 66 | # - sudo gem pristine gem-wrappers --version 1.3.2 67 | # - sudo gem pristine nokogiri --version 1.8.1 68 | # - sudo gem pristine ffi --version 1.9.25 69 | 70 | # Create custom source/bin directory 71 | - sudo mkdir -p /usr/local/bin 72 | - sudo mkdir -p /usr/local/src 73 | 74 | # NodeJS4 75 | - VERSION="$( curl -Lq https://nodejs.org 2>/dev/null | grep LTS | grep -Eo 'data-version.*.' | grep -oE 'v[0-9.]+' )" 76 | - sudo wget -P /usr/local/src https://nodejs.org/dist/${VERSION}/node-${VERSION}-linux-x64.tar.xz 77 | - sudo tar xvf /usr/local/src/node-${VERSION}-linux-x64.tar.xz -C /usr/local/src 78 | - sudo ln -s /usr/local/src/node-${VERSION}-linux-x64 /usr/local/node; 79 | - sudo ln -s /usr/local/node/bin/* /usr/local/bin/ 80 | 81 | - sudo npm install -g eslint 82 | - sudo npm install -g jsonlint 83 | - sudo npm install -g mdlint 84 | - sudo gem install scss_lint 85 | - sudo gem install mdl 86 | 87 | # Symlink node binaries 88 | - sudo ln -s /usr/local/node/bin/* /usr/local/bin/ 2>/dev/null || true 89 | 90 | 91 | ### 92 | ### Install Awesome-CI 93 | ### 94 | install: 95 | - ./configure 96 | - sudo make install 97 | 98 | 99 | ### 100 | ### Checks 101 | ### 102 | before_script: 103 | 104 | #------------------------------------------------------------ 105 | # 1.) Validate coding guidelines of self 106 | #------------------------------------------------------------ 107 | - shellcheck --exclude=SC1090,SC2001 --shell=bash bin/* 108 | 109 | #------------------------------------------------------------ 110 | # 2.) Test awesome-ci 111 | #------------------------------------------------------------ 112 | - make test 113 | 114 | #------------------------------------------------------------ 115 | # 3.) Build Docker image 116 | #------------------------------------------------------------ 117 | - make docker 118 | 119 | 120 | ### 121 | ### Deploy 122 | ### 123 | script: 124 | - if [ "${TRAVIS_PULL_REQUEST}" == "false" ]; then 125 | echo "${DOCKER_PASSWORD}" | docker login --username "${DOCKER_USERNAME}" --password-stdin && 126 | if [ "${TRAVIS_BRANCH}" == "master" ]; then 127 | docker push "${image}:latest"; 128 | elif [ -n "${TRAVIS_TAG}" ]; then 129 | docker tag "${image}:latest" "${image}:${TRAVIS_TAG}"; 130 | docker push "${image}:${TRAVIS_TAG}"; 131 | else 132 | echo "Skipping push to dockerhub on normal branches"; 133 | fi 134 | else 135 | echo "Skipping push to dockerhub on PR"; 136 | fi 137 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM debian:buster-slim 2 | 3 | ENV BUILD_DEPS \ 4 | curl \ 5 | gcc \ 6 | gcc-multilib \ 7 | make \ 8 | ruby-dev \ 9 | xz-utils 10 | 11 | ENV RUN_DEPS \ 12 | dos2unix \ 13 | file \ 14 | git \ 15 | moreutils \ 16 | php-cli \ 17 | python \ 18 | ruby \ 19 | shellcheck 20 | 21 | RUN set -x \ 22 | # Install apt packages 23 | && apt-get update \ 24 | && apt-get install --no-install-recommends --no-install-suggests -y \ 25 | ${BUILD_DEPS} \ 26 | ${RUN_DEPS} \ 27 | # Install Node/Npm 28 | && VERSION="$( curl https://nodejs.org/en/ 2>/dev/null | grep LTS | grep -Eo 'data-version="v?[.0-9]+"' | grep -Eo "v?[.0-9]+" )" \ 29 | && mkdir -p /usr/local/src \ 30 | && curl https://nodejs.org/dist/${VERSION}/node-${VERSION}-linux-x64.tar.xz > /usr/local/src/node.tar.xz \ 31 | && tar xvf /usr/local/src/node.tar.xz -C /usr/local/src \ 32 | && rm -rf /usr/local/src/node.tar.xz \ 33 | && rm -rf /usr/local/src/node-${VERSION}-linux-x64/etc \ 34 | && rm -rf /usr/local/src/node-${VERSION}-linux-x64/include \ 35 | && rm -rf /usr/local/src/node-${VERSION}-linux-x64/share \ 36 | && ln -sf /usr/local/src/node-${VERSION}-linux-x64 /usr/local/node \ 37 | && ln -sf /usr/local/node/bin/* /usr/local/bin/ \ 38 | # Install Npm modules 39 | && npm install -g eslint \ 40 | && npm install -g mdlint \ 41 | && npm install -g jsonlint \ 42 | && ln -sf /usr/local/node/bin/* /usr/local/bin/ \ 43 | # Install Gems 44 | && gem install scss_lint \ 45 | && gem install mdl \ 46 | # Clean-up 47 | && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false $fetchDeps \ 48 | ${BUILD_DEPS} \ 49 | && rm -rf /var/lib/apt/lists/* 50 | 51 | # Add Awesome-CI 52 | COPY ./bin /usr/bin 53 | COPY ./dependencies /usr/bin 54 | -------------------------------------------------------------------------------- /EXAMPLES.md: -------------------------------------------------------------------------------- 1 | # awesome-ci examples 2 | 3 | 4 | ### 1. Git analysis 5 | 6 | #### [git-conflicts](bin/git-conflicts) 7 | 8 | Scan files and check if they contain git conflicts. 9 | 10 | `git-conflicts --size --path=.` 11 | 12 | 13 | #### [git-ignored](bin/git-ignored) 14 | 15 | Scan git directory and see if ignored files are still in git cache. 16 | 17 | `git-ignored --path=.` 18 | 19 | 20 | ### 2. File analysis 21 | 22 | #### [file-crlf](bin/file-crlf) 23 | 24 | Scan files and check if they contain CRLF (Windows Line Feeds). 25 | 26 | `file-crlf --text --size --path=.` 27 | 28 | 29 | #### [file-empty](bin/file-empty) 30 | 31 | Scan files and check if they are empty (0 bytes). 32 | 33 | `file-empty --path=.` 34 | 35 | **(Do not use `--size` here, it will cancel the each other out)** 36 | 37 | 38 | #### [file-trailing-newline](bin/file-trailing-newline) 39 | 40 | Scan files and check if they contain a trailing newline. 41 | 42 | `file-trailing-newline --text --size --path=.` 43 | 44 | 45 | #### [file-trailing-single-newline](bin/file-trailing-single-newline) 46 | 47 | Scan files and check if they contain exactly one trailing newline. 48 | 49 | `file-trailing-single-newline --text --size --path=.` 50 | 51 | 52 | 53 | #### [file-trailing-space](bin/file-trailing-space) 54 | 55 | Scan files and check if they contain trailing whitespaces. 56 | 57 | `file-trailing-space --text --size --path=.` 58 | 59 | 60 | #### [file-utf8](bin/file-utf8) 61 | 62 | Scan files and check if they have a non UTF-8 encoding. 63 | 64 | `file-utf8 --text --size --path=.` 65 | 66 | 67 | #### [file-utf8-bom](bin/file-utf8-bom) 68 | 69 | Scan files and check if they contain BOM (Byte Order Mark): ``. 70 | 71 | `file-utf8-bom --text --size --path=.` 72 | 73 | 74 | ### 3. Syntax Error 75 | 76 | #### [syntax-bash](bin/syntax-bash) 77 | 78 | Scan shell files for bash syntax errors. 79 | 80 | ```bash 81 | # By extension 82 | $ syntax-bash --text --size --extension=sh,bash --path=. 83 | 84 | # By shebang 85 | $ syntax-bash --text --size --shebang=bash --path=. 86 | 87 | ``` 88 | 89 | 90 | #### [syntax-css](bin/syntax-css) 91 | 92 | Scan CSS files for CSS syntax errors. 93 | 94 | `syntax-css --text --size --extension=css --path=.` 95 | 96 | 97 | #### [syntax-js](bin/syntax-js) 98 | 99 | Scan JS files for JS syntax errors. 100 | 101 | `syntax-js --text --size --extension=js --path=.` 102 | 103 | 104 | #### [syntax-json](bin/syntax-json) 105 | 106 | Scan files for JSON syntax errors. 107 | 108 | `syntax-json --text --size --extension=json --path=.` 109 | 110 | 111 | #### [syntax-markdown](bin/syntax-markdown) 112 | 113 | Scan files for Markdown syntax errors. 114 | 115 | `syntax-markdown --text --size --extension=md --path=.` 116 | 117 | 118 | #### [syntax-perl](bin/syntax-perl) 119 | 120 | Scan Perl files for Perl syntax errors. 121 | 122 | ```bash 123 | # By extension 124 | $ syntax-perl --text --size --extension=pl --path=. 125 | 126 | # By shebang 127 | $ syntax-perl --text --size --shebang=perl --path=. 128 | ``` 129 | 130 | 131 | #### [syntax-php](bin/syntax-php) 132 | 133 | Scan files for PHP syntax errors. 134 | 135 | ```bash 136 | # By extension 137 | $ syntax-php --text --size --extension=php,inc --path=. 138 | 139 | # By shebang 140 | $ syntax-php --text --size --shebang=php --path=. 141 | ``` 142 | 143 | 144 | #### [syntax-python](bin/syntax-python) 145 | 146 | Scan Python files for Python syntax errors. 147 | 148 | ```bash 149 | # By extension 150 | $ syntax-python --text --size --extension=py --path=. 151 | 152 | # By shebang 153 | $ syntax-python --text --size --shebang=python --path=. 154 | ``` 155 | 156 | 157 | #### [syntax-ruby](bin/syntax-ruby) 158 | 159 | Scan Ruby files for Ruby syntax errors. 160 | 161 | ```bash 162 | # By extension 163 | $ syntax-ruby --text --size --extension=rb --path=. 164 | 165 | # By shebang 166 | $ syntax-ruby --text --size --shebang=ruby --path=. 167 | ``` 168 | 169 | 170 | #### [syntax-scss](bin/syntax-scss) 171 | 172 | Scan SCSS files for SCSS syntax errors. 173 | 174 | `syntax-scss --text --size --extension=scss --path=.` 175 | 176 | 177 | #### [syntax-sh](bin/syntax-sh) 178 | 179 | Scan shell files for /bin/sh syntax errors. 180 | 181 | ```bash 182 | # By extension 183 | $ syntax-sh --text --size --extension=sh,bash --path=. 184 | 185 | # By shebang 186 | $ syntax-sh --text --size --shebang=sh --path=. 187 | ``` 188 | 189 | 190 | 191 | ### 4. Code Conventions 192 | 193 | #### [inline-css](bin/inline-css) 194 | 195 | Scan files and check if they contain inline css code. 196 | 197 | `inline-css --text --size --extension=htm,html,php,tpl --path=.` 198 | 199 | 200 | #### [inline-js](bin/inline-js) 201 | 202 | Scan files and check if they contain inline javascript code. 203 | 204 | `inline-js --text --size --extension=htm,html,php,tpl --path=.` 205 | 206 | 207 | 208 | ### 5. Custom regex 209 | 210 | If none of the below tools fit your need, use one of these two custom regex tools. If you think your required regex is quite common, please drop me an issue and i will add it. 211 | 212 | **Note about escaping: (grep)** 213 | 214 | * Escape `'` (single quote) with `'\''` 215 | * Escape `"` (double quote) with `\\\"` 216 | 217 | **Note about escaping: (perl)** 218 | 219 | * Escape `'` (single quote) with `\x27` 220 | * Escape `"` (double quote) with `\x22` or `\"` 221 | * Escape `/` (forward slash) with `\/` 222 | 223 | **Note about escaping: (general)** 224 | 225 | Depending on your current shell (such as: Bash, ZSH, TCH, etc), you might have to escape special symbols so they are not interpretated on your shell. 226 | 227 | Escapes for Bash (and alike) 228 | 229 | * Escape `!` with `\!` 230 | 231 | 232 | #### [regex-grep](bin/regex-grep) 233 | 234 | `egrep` (`grep -E`) regex version to scan files for an occurance. 235 | 236 | `regex-grep --text --size --path=. --custom=""` 237 | 238 | #### [regex-perl](bin/regex-perl) 239 | 240 | `perl` regex version to scan files for an occurance. 241 | 242 | `regex-perl --text --size --path=. --custom=""` 243 | 244 | 245 | **Examples** 246 | 247 | 1 Check for css tags containing: `url('/` or `url("/` or `url(/` 248 | 249 | ```bash 250 | $ regex-grep --path=. --extension=css,scss --text --size --custom="url\([[:space:]]*['\''\\\"]?[[:space:]]*/" 251 | 252 | $ regex-perl --path=. --extension=css,scss --text --size --custom="url\([[:space:]]*[\x27\"]?[[:space:]]*\/" 253 | ``` 254 | 255 | 2 Check for css tags containing: `url('http[s]://` or `url("http[s]://` or `url(http[s]://` 256 | 257 | ```bash 258 | $ regex-grep --path=. --extension=css,scss --text --size --custom="url\([[:space:]]*['\''\\\"]?[[:space:]]*http[s]?://" 259 | 260 | $ regex-perl --path=. --extension=css,scss --text --size --custom="url\([[:space:]]*[\x27\"]?[[:space:]]*http[s]?:\/\/" 261 | ``` 262 | 263 | 3 Check common html file tpyes for `href="http[s]*://` 264 | 265 | ```bash 266 | $ regex-grep --path=. --extension=htm,html,php,tpl --text --size --custom="href=[[:space:]]*['\''\\\"]?http[s]?://" 267 | 268 | $ regex-perl --path=. --extension=htm,html,php,tpl --text --size --custom="href=[[:space:]]*[\x27\"]?http[s]?:\/\/" 269 | ``` 270 | 271 | 272 | **Examples via configuration file** 273 | 274 | 1 Check for css tags containing: `url('/` or `url("/` or `url(/` 275 | 276 | `.awesome-ci.conf` 277 | 278 | ```bash 279 | REGEX_GREP_LEAD_SLASH_EXTENSION="css,scss" 280 | REGEX_GREP_LEAD_SLASH_IGNORE="" 281 | REGEX_GREP_LEAD_SLASH_TEXT=1 282 | REGEX_GREP_LEAD_SLASH_SIZE=1 283 | REGEX_GREP_LEAD_SLASH_CUSTOM="url\([[:space:]]*['\''\\\"]?[[:space:]]*/" 284 | 285 | REGEX_PERL_LEAD_SLASH_EXTENSION="css,scss" 286 | REGEX_PERL_LEAD_SLASH_IGNORE="" 287 | REGEX_PERL_LEAD_SLASH_TEXT=1 288 | REGEX_PERL_LEAD_SLASH_SIZE=1 289 | REGEX_PERL_LEAD_SLASH_CUSTOM="url\([[:space:]]*[\x27\"]?[[:space:]]*\/" 290 | ``` 291 | 292 | ```bash 293 | $ regex-grep --config=.awesome-ci.conf --confpre=REGEX_GREP_LEAD_SLASH_ --path=. 294 | 295 | $ regex-perl --config=.awesome-ci.conf --confpre=REGEX_PERL_LEAD_SLASH_ --path=. 296 | ``` 297 | 298 | 2 Check for css tags containing: `url('http[s]://` or `url("http[s]://` or `url(http[s]://` 299 | 300 | `.awesome-ci.conf` 301 | 302 | ```bash 303 | REGEX_GREP_FQDN_EXTENSION="css,scss" 304 | REGEX_GREP_FQDN_IGNORE="" 305 | REGEX_GREP_FQDN_TEXT=1 306 | REGEX_GREP_FQDN_SIZE=1 307 | REGEX_GREP_FQDN_CUSTOM="url\([[:space:]]*['\''\\\"]?[[:space:]]*http[s]?://" 308 | 309 | REGEX_PERL_FQDN_EXTENSION="css,scss" 310 | REGEX_PERL_FQDN_IGNORE="" 311 | REGEX_PERL_FQDN_TEXT=1 312 | REGEX_PERL_FQDN_SIZE=1 313 | REGEX_PERL_FQDN_CUSTOM="url\([[:space:]]*[\x27\"]?[[:space:]]*http[s]?:\/\/" 314 | ``` 315 | 316 | ```bash 317 | $ regex-grep --config=.awesome-ci.conf --confpre=REGEX_GREP_FQDN_ --path=. 318 | 319 | $ regex-perl --config=.awesome-ci.conf --confpre=REGEX_PERL_FQDN_ --path=. 320 | ``` 321 | 322 | 323 | 3 Check common html file tpyes for `href="http[s]*://` 324 | 325 | `.awesome-ci.conf` 326 | 327 | ```bash 328 | REGEX_GREP_HREF_FQDN_EXTENSION="htm,html,php,tpl" 329 | REGEX_GREP_HREF_FQDN_IGNORE="" 330 | REGEX_GREP_HREF_FQDN_TEXT=1 331 | REGEX_GREP_HREF_FQDN_SIZE=1 332 | REGEX_GREP_HREF_FQDN_CUSTOM="href=[[:space:]]*['\''\\\"]?http[s]?://" 333 | 334 | REGEX_PERL_HREF_FQDN_EXTENSION="htm,html,php,tpl" 335 | REGEX_PERL_HREF_FQDN_IGNORE="" 336 | REGEX_PERL_HREF_FQDN_TEXT=1 337 | REGEX_PERL_HREF_FQDN_SIZE=1 338 | REGEX_PERL_HREF_FQDN_CUSTOM="href=[[:space:]]*[\x27\"]?http[s]?:\/\/" 339 | ``` 340 | 341 | ```bash 342 | $ regex-grep --config=.awesome-ci.conf --confpre=REGEX_GREP_HREF_FQDN_ --path=. 343 | 344 | $ regex-perl --config=.awesome-ci.conf --confpre=REGEX_PERL_HREF_FQDN_ --path=. 345 | ``` 346 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 cytopia 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 | ### 2 | ### Variables 3 | ### 4 | SHELL = /bin/sh 5 | 6 | MKDIR_P = mkdir -p 7 | 8 | # If ./configure has been run, include configure.in 9 | ifneq ("$(wildcard configure.in)","") 10 | include configure.in 11 | endif 12 | 13 | # 'test' directory exists, therefore force make to run test 14 | .PHONY: test 15 | 16 | 17 | ### 18 | ### Help 19 | ### 20 | help: 21 | @echo Options 22 | @echo " make test" 23 | @echo " Test awesome-ci scripts" 24 | @echo "" 25 | @echo " make install" 26 | @echo " Install everthing (requires sudo or root)" 27 | @echo "" 28 | @echo " make clean" 29 | @echo " Clean build" 30 | @echo "" 31 | @echo " make docker" 32 | @echo " Build docker image" 33 | @echo "" 34 | @echo " make help" 35 | @echo " Show this help screen" 36 | 37 | 38 | ### 39 | ### Install 40 | ### 41 | install: 42 | ifeq ("$(wildcard configure.in)","") 43 | $(error Not configured, run ./configure) 44 | false 45 | endif 46 | 47 | @echo "Installing files" 48 | @echo "" 49 | 50 | @# Create directories 51 | ${MKDIR_P} $(BINDIR) 52 | 53 | @# Install binary 54 | install -m 0755 dependencies/* $(BINDIR)/ 55 | install -m 0755 bin/* $(BINDIR)/ 56 | 57 | 58 | @echo "Installation complete:" 59 | @echo "----------------------------------------------------------------------" 60 | @echo "" 61 | 62 | 63 | ### 64 | ### Clean 65 | ### 66 | clean: 67 | rm -f configure.in 68 | 69 | 70 | ### 71 | ### Build docker image 72 | ### 73 | docker: 74 | docker build -t cytopia/awesome-ci . 75 | 76 | 77 | ### 78 | ### 79 | ### 80 | test: 81 | ./test/test.sh 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [awesome-ci](https://github.com/cytopia/awesome-ci) 2 | 3 | [![Build Status](https://travis-ci.org/cytopia/awesome-ci.svg?branch=master)](https://travis-ci.org/cytopia/awesome-ci) 4 | [![Latest Stable Version](https://poser.pugx.org/cytopia/awesome-ci/v/stable)](https://packagist.org/packages/cytopia/awesome-ci) 5 | [![Total Downloads](https://poser.pugx.org/cytopia/awesome-ci/downloads)](https://packagist.org/packages/cytopia/awesome-ci) 6 | [![Docker image](https://images.microbadger.com/badges/image/cytopia/awesome-ci.svg)](https://hub.docker.com/r/cytopia/awesome-ci) 7 | [![License](https://poser.pugx.org/cytopia/awesome-ci/license)](http://opensource.org/licenses/MIT) 8 | 9 | 10 | > ## :warning: DEPRECATION WARNING 11 | > 12 | > This repository is deprecated. Please use the following docker images below instead: 13 | > 14 | > #### All [#awesome-ci](https://github.com/topics/awesome-ci) Docker images 15 | > 16 | > [ansible-lint][alint-git-lnk] **•** 17 | > [ansible][ansible-git-lnk] **•** 18 | > [awesome-ci][aci-git-lnk] **•** 19 | > [bandit][bandit-git-lnk] **•** 20 | > [black][black-git-lnk] **•** 21 | > [checkmake][cm-git-lnk] **•** 22 | > [eslint][elint-git-lnk] **•** 23 | > [file-lint][flint-git-lnk] **•** 24 | > [gofmt][gfmt-git-lnk] **•** 25 | > [goimports][gimp-git-lnk] **•** 26 | > [golint][glint-git-lnk] **•** 27 | > [jsonlint][jlint-git-lnk] **•** 28 | > [kubeval][kubeval-git-lnk] **•** 29 | > [linkcheck][linkcheck-git-lnk] **•** 30 | > [mypy][mypy-git-lnk] **•** 31 | > [php-cs-fixer][pcsf-git-lnk] **•** 32 | > [phpcbf][pcbf-git-lnk] **•** 33 | > [phpcs][pcs-git-lnk] **•** 34 | > [phplint][plint-git-lnk] **•** 35 | > [pycodestyle][pycs-git-lnk] **•** 36 | > [pydocstyle][pyds-git-lnk] **•** 37 | > [pylint][pylint-git-lnk] **•** 38 | > [terraform-docs][tfdocs-git-lnk] **•** 39 | > [terragrunt-fmt][tgfmt-git-lnk] **•** 40 | > [terragrunt][tg-git-lnk] **•** 41 | > [yamlfmt][yfmt-git-lnk] **•** 42 | > [yamllint][ylint-git-lnk] 43 | > 44 | > #### Docker images 45 | > 46 | > Save yourself from installing lot's of dependencies and pick a dockerized version of your favourite 47 | > linter below for reproducible local or remote CI tests: 48 | > 49 | > | GitHub | DockerHub | Type | Description | 50 | > |--------|-----------|------|-------------| 51 | > | [awesome-ci][aci-git-lnk] | [![aci-hub-img]][aci-hub-lnk] | Basic | Tools for git, file and static source code analysis | 52 | > | [file-lint][flint-git-lnk] | [![flint-hub-img]][flint-hub-lnk] | Basic | Baisc source code analysis | 53 | > | [linkcheck][linkcheck-git-lnk] | [![linkcheck-hub-img]][flint-hub-lnk] | Basic | Search for URLs in files and validate their HTTP status code | 54 | > | [ansible][ansible-git-lnk] | [![ansible-hub-img]][ansible-hub-lnk] | Ansible | Multiple versions and flavours of Ansible | 55 | > | [ansible-lint][alint-git-lnk] | [![alint-hub-img]][alint-hub-lnk] | Ansible | Lint Ansible | 56 | > | [gofmt][gfmt-git-lnk] | [![gfmt-hub-img]][gfmt-hub-lnk] | Go | Format Go source code **[1]** | 57 | > | [goimports][gimp-git-lnk] | [![gimp-hub-img]][gimp-hub-lnk] | Go | Format Go source code **[1]** | 58 | > | [golint][glint-git-lnk] | [![glint-hub-img]][glint-hub-lnk] | Go | Lint Go code | 59 | > | [eslint][elint-git-lnk] | [![elint-hub-img]][elint-hub-lnk] | Javascript | Lint Javascript code | 60 | > | [jsonlint][jlint-git-lnk] | [![jlint-hub-img]][jlint-hub-lnk] | JSON | Lint JSON files **[1]** | 61 | > | [kubeval][kubeval-git-lnk] | [![kubeval-hub-img]][kubeval-hub-lnk] | K8s | Lint Kubernetes files | 62 | > | [checkmake][cm-git-lnk] | [![cm-hub-img]][cm-hub-lnk] | Make | Lint Makefiles | 63 | > | [phpcbf][pcbf-git-lnk] | [![pcbf-hub-img]][pcbf-hub-lnk] | PHP | PHP Code Beautifier and Fixer | 64 | > | [phpcs][pcs-git-lnk] | [![pcs-hub-img]][pcs-hub-lnk] | PHP | PHP Code Sniffer | 65 | > | [phplint][plint-git-lnk] | [![plint-hub-img]][plint-hub-lnk] | PHP | PHP Code Linter **[1]** | 66 | > | [php-cs-fixer][pcsf-git-lnk] | [![pcsf-hub-img]][pcsf-hub-lnk] | PHP | PHP Coding Standards Fixer | 67 | > | [bandit][bandit-git-lnk] | [![bandit-hub-img]][bandit-hub-lnk] | Python | A security linter from PyCQA 68 | > | [black][black-git-lnk] | [![black-hub-img]][black-hub-lnk] | Python | The uncompromising Python code formatter | 69 | > | [mypy][mypy-git-lnk] | [![mypy-hub-img]][mypy-hub-lnk] | Python | Static source code analysis | 70 | > | [pycodestyle][pycs-git-lnk] | [![pycs-hub-img]][pycs-hub-lnk] | Python | Python style guide checker | 71 | > | [pydocstyle][pyds-git-lnk] | [![pyds-hub-img]][pyds-hub-lnk] | Python | Python docstyle checker | 72 | > | [pylint][pylint-git-lnk] | [![pylint-hub-img]][pylint-hub-lnk] | Python | Python source code, bug and quality checker | 73 | > | [terraform-docs][tfdocs-git-lnk] | [![tfdocs-hub-img]][tfdocs-hub-lnk] | Terraform | Terraform doc generator (TF 0.12 ready) **[1]** | 74 | > | [terragrunt][tg-git-lnk] | [![tg-hub-img]][tg-hub-lnk] | Terraform | Terragrunt and Terraform | 75 | > | [terragrunt-fmt][tgfmt-git-lnk] | [![tgfmt-hub-img]][tgfmt-hub-lnk] | Terraform | `terraform fmt` for Terragrunt files **[1]** | 76 | > | [yamlfmt][yfmt-git-lnk] | [![yfmt-hub-img]][yfmt-hub-lnk] | Yaml | Format Yaml files **[1]** | 77 | > | [yamllint][ylint-git-lnk] | [![ylint-hub-img]][ylint-hub-lnk] | Yaml | Lint Yaml files | 78 | 79 | > **[1]** Uses a shell wrapper to add **enhanced functionality** not available by original project. 80 | 81 | [aci-git-lnk]: https://github.com/cytopia/awesome-ci 82 | [aci-hub-img]: https://img.shields.io/docker/pulls/cytopia/awesome-ci.svg 83 | [aci-hub-lnk]: https://hub.docker.com/r/cytopia/awesome-ci 84 | 85 | [flint-git-lnk]: https://github.com/cytopia/docker-file-lint 86 | [flint-hub-img]: https://img.shields.io/docker/pulls/cytopia/file-lint.svg 87 | [flint-hub-lnk]: https://hub.docker.com/r/cytopia/file-lint 88 | 89 | [linkcheck-git-lnk]: https://github.com/cytopia/docker-linkcheck 90 | [linkcheck-hub-img]: https://img.shields.io/docker/pulls/cytopia/linkcheck.svg 91 | [linkcheck-hub-lnk]: https://hub.docker.com/r/cytopia/linkcheck 92 | 93 | [jlint-git-lnk]: https://github.com/cytopia/docker-jsonlint 94 | [jlint-hub-img]: https://img.shields.io/docker/pulls/cytopia/jsonlint.svg 95 | [jlint-hub-lnk]: https://hub.docker.com/r/cytopia/jsonlint 96 | 97 | [ansible-git-lnk]: https://github.com/cytopia/docker-ansible 98 | [ansible-hub-img]: https://img.shields.io/docker/pulls/cytopia/ansible.svg 99 | [ansible-hub-lnk]: https://hub.docker.com/r/cytopia/ansible 100 | 101 | [alint-git-lnk]: https://github.com/cytopia/docker-ansible-lint 102 | [alint-hub-img]: https://img.shields.io/docker/pulls/cytopia/ansible-lint.svg 103 | [alint-hub-lnk]: https://hub.docker.com/r/cytopia/ansible-lint 104 | 105 | [kubeval-git-lnk]: https://github.com/cytopia/docker-kubeval 106 | [kubeval-hub-img]: https://img.shields.io/docker/pulls/cytopia/kubeval.svg 107 | [kubeval-hub-lnk]: https://hub.docker.com/r/cytopia/kubeval 108 | 109 | [gfmt-git-lnk]: https://github.com/cytopia/docker-gofmt 110 | [gfmt-hub-img]: https://img.shields.io/docker/pulls/cytopia/gofmt.svg 111 | [gfmt-hub-lnk]: https://hub.docker.com/r/cytopia/gofmt 112 | 113 | [gimp-git-lnk]: https://github.com/cytopia/docker-goimports 114 | [gimp-hub-img]: https://img.shields.io/docker/pulls/cytopia/goimports.svg 115 | [gimp-hub-lnk]: https://hub.docker.com/r/cytopia/goimports 116 | 117 | [glint-git-lnk]: https://github.com/cytopia/docker-golint 118 | [glint-hub-img]: https://img.shields.io/docker/pulls/cytopia/golint.svg 119 | [glint-hub-lnk]: https://hub.docker.com/r/cytopia/golint 120 | 121 | [elint-git-lnk]: https://github.com/cytopia/docker-eslint 122 | [elint-hub-img]: https://img.shields.io/docker/pulls/cytopia/eslint.svg 123 | [elint-hub-lnk]: https://hub.docker.com/r/cytopia/eslint 124 | 125 | [cm-git-lnk]: https://github.com/cytopia/docker-checkmake 126 | [cm-hub-img]: https://img.shields.io/docker/pulls/cytopia/checkmake.svg 127 | [cm-hub-lnk]: https://hub.docker.com/r/cytopia/checkmake 128 | 129 | [pcbf-git-lnk]: https://github.com/cytopia/docker-phpcbf 130 | [pcbf-hub-img]: https://img.shields.io/docker/pulls/cytopia/phpcbf.svg 131 | [pcbf-hub-lnk]: https://hub.docker.com/r/cytopia/phpcbf 132 | 133 | [pcs-git-lnk]: https://github.com/cytopia/docker-phpcs 134 | [pcs-hub-img]: https://img.shields.io/docker/pulls/cytopia/phpcs.svg 135 | [pcs-hub-lnk]: https://hub.docker.com/r/cytopia/phpcs 136 | 137 | [plint-git-lnk]: https://github.com/cytopia/docker-phplint 138 | [plint-hub-img]: https://img.shields.io/docker/pulls/cytopia/phplint.svg 139 | [plint-hub-lnk]: https://hub.docker.com/r/cytopia/phplint 140 | 141 | [pcsf-git-lnk]: https://github.com/cytopia/docker-php-cs-fixer 142 | [pcsf-hub-img]: https://img.shields.io/docker/pulls/cytopia/php-cs-fixer.svg 143 | [pcsf-hub-lnk]: https://hub.docker.com/r/cytopia/php-cs-fixer 144 | 145 | [bandit-git-lnk]: https://github.com/cytopia/docker-bandit 146 | [bandit-hub-img]: https://img.shields.io/docker/pulls/cytopia/bandit.svg 147 | [bandit-hub-lnk]: https://hub.docker.com/r/cytopia/bandit 148 | 149 | [black-git-lnk]: https://github.com/cytopia/docker-black 150 | [black-hub-img]: https://img.shields.io/docker/pulls/cytopia/black.svg 151 | [black-hub-lnk]: https://hub.docker.com/r/cytopia/black 152 | 153 | [mypy-git-lnk]: https://github.com/cytopia/docker-mypy 154 | [mypy-hub-img]: https://img.shields.io/docker/pulls/cytopia/mypy.svg 155 | [mypy-hub-lnk]: https://hub.docker.com/r/cytopia/mypy 156 | 157 | [pycs-git-lnk]: https://github.com/cytopia/docker-pycodestyle 158 | [pycs-hub-img]: https://img.shields.io/docker/pulls/cytopia/pycodestyle.svg 159 | [pycs-hub-lnk]: https://hub.docker.com/r/cytopia/pycodestyle 160 | 161 | [pyds-git-lnk]: https://github.com/cytopia/docker-pydocstyle 162 | [pyds-hub-img]: https://img.shields.io/docker/pulls/cytopia/pydocstyle.svg 163 | [pyds-hub-lnk]: https://hub.docker.com/r/cytopia/pydocstyle 164 | 165 | [pylint-git-lnk]: https://github.com/cytopia/docker-pylint 166 | [pylint-hub-img]: https://img.shields.io/docker/pulls/cytopia/pylint.svg 167 | [pylint-hub-lnk]: https://hub.docker.com/r/cytopia/pylint 168 | 169 | [tfdocs-git-lnk]: https://github.com/cytopia/docker-terraform-docs 170 | [tfdocs-hub-img]: https://img.shields.io/docker/pulls/cytopia/terraform-docs.svg 171 | [tfdocs-hub-lnk]: https://hub.docker.com/r/cytopia/terraform-docs 172 | 173 | [tg-git-lnk]: https://github.com/cytopia/docker-terragrunt 174 | [tg-hub-img]: https://img.shields.io/docker/pulls/cytopia/terragrunt.svg 175 | [tg-hub-lnk]: https://hub.docker.com/r/cytopia/terragrunt 176 | 177 | [tgfmt-git-lnk]: https://github.com/cytopia/docker-terragrunt-fmt 178 | [tgfmt-hub-img]: https://img.shields.io/docker/pulls/cytopia/terragrunt-fmt.svg 179 | [tgfmt-hub-lnk]: https://hub.docker.com/r/cytopia/terragrunt-fmt 180 | 181 | [yfmt-git-lnk]: https://github.com/cytopia/docker-yamlfmt 182 | [yfmt-hub-img]: https://img.shields.io/docker/pulls/cytopia/yamlfmt.svg 183 | [yfmt-hub-lnk]: https://hub.docker.com/r/cytopia/yamlfmt 184 | 185 | [ylint-git-lnk]: https://github.com/cytopia/docker-yamllint 186 | [ylint-hub-img]: https://img.shields.io/docker/pulls/cytopia/yamllint.svg 187 | [ylint-hub-lnk]: https://hub.docker.com/r/cytopia/yamllint 188 | 189 | 190 | --- 191 | 192 | 193 | [![Docker image](http://dockeri.co/image/cytopia/awesome-ci?&kill_cache=1)](https://hub.docker.com/r/cytopia/awesome-ci) 194 | 195 | **Runs on** 196 | 197 | [![Linux](https://raw.githubusercontent.com/cytopia/icons/master/64x64/linux.png)](https://www.kernel.org/) 198 | [![FreeBSD](https://raw.githubusercontent.com/cytopia/icons/master/64x64/freebsd.png)](https://www.freebsd.org) 199 | [![OSX](https://raw.githubusercontent.com/cytopia/icons/master/64x64/osx.png)](https://www.apple.com/osx) 200 | 201 | Continuous Integration command line tools for git repositories, file characteristics, syntax errors 202 | and static source code analysis. 203 | 204 | Awesome-CI is capable of finding various problems in your code repository as well as fixing them 205 | automatically. 206 | 207 | 208 | --- 209 | 210 | **Table of Contents** 211 | 212 | 1. [Tools](#tools) 213 | 2. [Learn / Validate](#learn--validate) 214 | 3. [Fix](#fix) 215 | 4. [Custom regex contributions](#custom-regex-contributions) 216 | 5. [General usage](#general-usage) 217 | 6. [Installation](i#installation) 218 | 1. [Requirements](#requirements) 219 | 2. [Install OSX](#install-osx) 220 | 3. [Install Linux/BSD](#install-linuxbsd) 221 | 7. [Awesome CI Docker image](#awesome-ci-docker-image) 222 | 8. [Documentation](#documentation) 223 | 9. [License](#license) 224 | 225 | 226 | ## Tools 227 | 228 | All checks have the option to only check by one or more file **extensions**, by **shebang** as well as to **exclude** one or more folders from the whole search. 229 | 230 | **Note:** Fixable options are currently in testing phase. Please report any bugs. 231 | 232 | 233 | | Type | Tool | Fixable | Description | 234 | |------|------|---------|-------------| 235 | | Git | [git-conflicts](bin/git-conflicts) | | Scan files and check if they contain git conflicts. | 236 | | Git | [git-ignored](bin/git-ignored) | | Scan git directory and see if ignored files are still in git cache. | 237 | | File | [file-cr](bin/file-cr) | ✓ | Scan files and check if they contain CR (Carriage Return only). | 238 | | File | [file-crlf](bin/file-crlf) | ✓ | Scan files and check if they contain CRLF (Windows Line Feeds). | 239 | | File | [file-empty](bin/file-empty) | | Scan files and check if they are empty (0 bytes). | 240 | | File | [file-nullbyte-char](bin/file-nullbyte-char) | ✓ | Scan files and check if they contain a null-byte character (\x00). | 241 | | File | [file-trailing-newline](bin/file-trailing-newline) | ✓ | Scan files and check if they contain a trailing newline. | 242 | | File | [file-trailing-single-newline](bin/file-trailing-single-newline) | ✓ | Scan files and check if they contain exactly one trailing newline. | 243 | | File | [file-trailing-space](bin/file-trailing-space) | ✓ | Scan files and check if they contain trailing whitespaces. | 244 | | File | [file-utf8](bin/file-utf8) | ✓ | Scan files and check if they have a non UTF-8 encoding. | 245 | | File | [file-utf8-bom](bin/file-utf8-bom) | ✓ | Scan files and check if they contain BOM (Byte Order Mark): ``. | 246 | | Syntax | [syntax-bash](bin/syntax-bash) | | Scan shell files for bash syntax errors. | 247 | | Syntax | [syntax-css](bin/syntax-css) | | Scan CSS files for CSS syntax errors. | 248 | | Syntax | [syntax-js](bin/syntax-js) | | Scan JS files for JS syntax errors. | 249 | | Syntax | [syntax-json](bin/syntax-json) | | Scan files for JSON syntax errors. | 250 | | Syntax | [syntax-markdown](bin/syntax-markdown) | | Scan files for Markdown syntax errors. | 251 | | Syntax | [syntax-perl](bin/syntax-perl) | | Scan Perl files for Perl syntax errors. | 252 | | Syntax | [syntax-php](bin/syntax-php) | | Scan files for PHP syntax errors. | 253 | | Syntax | [syntax-python](bin/syntax-python) | | Scan Python files for Python syntax errors. | 254 | | Syntax | [syntax-ruby](bin/syntax-ruby) | | Scan Ruby files for Ruby syntax errors. | 255 | | Syntax | [syntax-scss](bin/syntax-scss) | | Scan SCSS files for SCSS syntax errors. | 256 | | Syntax | [syntax-sh](bin/syntax-sh) | | Scan shell files for /bin/sh syntax errors. | 257 | | Code Conventions | [inline-css](bin/inline-css) | | Scan files and check if they contain inline css code. | 258 | | Code Conventions | [inline-js](bin/inline-js) | | Scan files and check if they contain inline javascript code. | 259 | | Regex | [regex-grep](bin/regex-grep) | | `egrep` (`grep -E`) regex version to scan files for an occurance. | 260 | | Regex | [regex-perl](bin/regex-perl) | | `perl` regex version to scan files for an occurance. | 261 | 262 | 263 | ## Learn / validate 264 | 265 | All of the above scripts offer the `--dry` option which will only show you the built command without actually executing it: 266 | ```bash 267 | $ regex-grep --path=. --ignore=".git,.svn" --shebang=sh --size --text \ 268 | --custom="if[[:space:]]*\[\[" --dry 269 | 270 | find . -type f -not \( -path "./.git*" -o -path "./.svn*" \) ! -size 0 -print0 | \ 271 | xargs -0 -P 8 -n1 grep -Il '' | \ 272 | tr '\n' '\0' | \ 273 | xargs -0 -P 8 -n1 awk '/^#!.*(\/sh|[[:space:]]+sh)/{print FILENAME}' | \ 274 | tr '\n' '\0' | \ 275 | xargs -0 -P 8 -n1 sh -c 'if [ -f "${1}" ]; then grep --color=always -inHE "if[[:space:]]*\[\[" "$1" || true; fi' -- 276 | ``` 277 | 278 | 279 | ## Fix 280 | 281 | Some of the above scripts offer the `--fix` option (see table above), with which you are actually able to fix the problem. 282 | You can also combine it with `--dry` to see how the actual fix command looks like: 283 | ```bash 284 | $ file-utf8 --path=dump.sql --fix --dry 285 | 286 | find dump.sql -type f -print0 | \ 287 | xargs -0 -P 8 -n1 sh -c 'if [ -f "${1}" ]; then isutf8 "$1" >/dev/null || (TERM=vt100 vi -u NONE -n -es -c "set fileencoding=utf8" -c "wq" "$1" > /dev/tty && echo "Fixing: $1" || echo "FAILED: $1"); fi' -- 288 | ``` 289 | 290 | 291 | ## Custom regex contributions 292 | 293 | `regex-grep` and `regex-perl` have a lot of potential for doing custom project validation. 294 | 295 | In order to give you an idea, have a look at the compiled [Regex Contributions](REGEX_CONTRIBUTIONS.md). 296 | 297 | Please use pull requests to add useful checks. 298 | 299 | 300 | ## General Usage 301 | 302 | * All tools share the same pattern (except `git-ignored`) and can be used with the same command line arguments. 303 | * Some tools have an additional option `--custom=""` to overwrite the command itself (this is explained and shown in detail in each command's `--help` option). 304 | 305 | **Options:** 306 | 307 | ```bash 308 | # Required: 309 | --path # Specify the path where to scan 310 | 311 | # Optional pattern (each option is logically and-ed): 312 | --fix # Fix the problems for the specified files (not every check) 313 | 314 | --text # Only scan non-binary files 315 | --size # Only scan non-empty files (greater 0 bytes) 316 | --shebang # Only scan files (shell scripts) that match a certain shebang 317 | --extension # Only scan files with these file extensions 318 | --ignore # Ignore files/folders 319 | 320 | # Optional misc: 321 | --config # Specify configuration file 322 | --confpre # Alter configuration directive prefix for this check 323 | --verbose # Show files and commands as being processed 324 | --debug # Show additional debug messages 325 | --list # Only show files that would be processed (no processing) 326 | --dry # Show command that would be executed (no processing) 327 | 328 | # System 329 | --help # Show help 330 | --info # Show version of required binaries 331 | --version # Show tool version 332 | ``` 333 | 334 | ## Installation 335 | 336 | ### Requirements 337 | 338 | Awesome-ci requires the following tools to be installed: 339 | 340 | * `dos2unix` 341 | * `eslint` 342 | * `file` 343 | * `git` 344 | * `jsonlint` 345 | * `mdl` 346 | * `perl` 347 | * `php` 348 | * `python` 349 | * `ruby` 350 | * `scss_lint` 351 | * `shellcheck` 352 | 353 | ### Install OSX 354 | 355 | ```bash 356 | brew tap cytopia/tap 357 | brew install awesome-ci 358 | ``` 359 | 360 | ### Install Linux/BSD 361 | 362 | ```bash 363 | # Install to /usr/bin 364 | ./configure 365 | make install 366 | 367 | # Instal to /usr/local/bin 368 | ./configure --prefix=/usr/local 369 | make install 370 | 371 | # Install to /opt/bin 372 | ./configure --prefix=/opt 373 | make install 374 | ``` 375 | 376 | ## Awesome CI Docker image 377 | 378 | [![Docker image](http://dockeri.co/image/cytopia/awesome-ci?&kill_cache=1)](https://hub.docker.com/r/cytopia/awesome-ci) 379 | 380 | Instead of installing awesome-ci and all its required dependencies locally on your computer, 381 | you can also use the bundled Docker image 382 | **[cytopia/awesome-ci](https://hub.docker.com/r/cytopia/awesome-ci/)** which has everything 383 | pre-installed and is built nightly by travis-ci. 384 | 385 | ```bash 386 | docker run -v ${PWD}:/ac cytopia/awesome-ci file-crlf --path=/ac 387 | ``` 388 | 389 | The above example is using `file-crlf` to scan the current directory for files containing 390 | Windows newlines: 391 | 392 | * `${PWD}` (the current host directory) is mounted into the container's `/ac` directoy 393 | * `file-crlf` path then points (inside the container) to `/ac` (which is the current host directory) 394 | * `/ac` can actually be named by whatever name you want 395 | 396 | If you use an awesome-ci configuration which is not inside the directory you want to check, you 397 | will also have to mount that into the container: 398 | ```bash 399 | docker run \ 400 | -v /host/path/to/awesome-ci.conf:/etc/awesome-ci.conf \ 401 | -v ${PWD}:/ac cytopia/awesome-ci file-crlf --path=/ac --config=/etc/awesome-ci.conf 402 | ``` 403 | 404 | ## Documentation 405 | 406 | To find out more about awesome-ci, have a look at the following links. 407 | 408 | * [Dependencies](dependencies/) 409 | * [Examples](EXAMPLES.md) 410 | * [Regex Contributions](REGEX_CONTRIBUTIONS.md) 411 | 412 | 413 | ## License 414 | 415 | [MIT License](LICENSE.md) 416 | 417 | Copyright (c) 2018 [cytopia](https://github.com/cytopia) 418 | -------------------------------------------------------------------------------- /REGEX_CONTRIBUTIONS.md: -------------------------------------------------------------------------------- 1 | # Regex Contributions (`regex-grep` and `regex-perl`) 2 | 3 | --- 4 | 5 | **Note about escaping: (grep)** 6 | 7 | * Escape `'` (single quote) with `'\''` 8 | * Escape `"` (double quote) with `\\\"` 9 | 10 | **Note about escaping: (perl)** 11 | 12 | * Escape `'` (single quote) with `\x27` 13 | * Escape `"` (double quote) with `\x22` or `\"` 14 | * Escape `/` (forward slash) with `\/` 15 | 16 | **Note about escaping: (general)** 17 | 18 | Depending on your current shell (such as: Bash, ZSH, TCH, etc), you might have to escape special symbols so they are not interpretated on your shell. 19 | 20 | Escapes for Bash (and alike) 21 | 22 | * Escape `!` with `\!` 23 | 24 | --- 25 | 26 | ## Table of Contents 27 | 28 | 1. [SCSS](https://github.com/cytopia/awesome-ci/blob/master/REGEX_CONTRIBUTIONS.md#scss) 29 | 2. [HTML](https://github.com/cytopia/awesome-ci/blob/master/REGEX_CONTRIBUTIONS.md#html) 30 | 31 | 32 | ## Checks 33 | 34 | 35 | ### SCSS 36 | 37 | 38 | Check `*url('');` for Leading slash (`/`) 39 | 40 | ```bash 41 | # This check makes sure that all URL values should not begin with a leading `/`, 42 | # because my projects default requirements are to use something like: 43 | # 44 | # * url('#{$webroot}/img/bg.png 45 | # * url('../other/bg.png') 46 | 47 | $ regex-grep --path=. --extension=scss --text --size --custom="url\([[:space:]]*['\''\\\"]?[[:space:]]*/" 48 | 49 | $ regex-perl --path=. --extension=scss --text --size --custom="url\([[:space:]]*[\x27\"]?[[:space:]]*\/" 50 | ``` 51 | 52 | Check `*url('');` for absolute URL 53 | 54 | ```bash 55 | # Check css tags containing: 56 | # 57 | # * url('http[s]:// 58 | # * url("http[s]:// 59 | # * url(http[s]:// 60 | 61 | $ regex-grep --path=. --extension=scss --text --size --custom="url\([[:space:]]*['\''\\\"]?[[:space:]]*http[s]?://" 62 | 63 | $ regex-perl --path=. --extension=scss --text --size --custom="url\([[:space:]]*[\x27\"]?[[:space:]]*http[s]?:\/\/" 64 | ``` 65 | 66 | 67 | ### HTML 68 | 69 | Check `href` for absolute URL 70 | 71 | ```bash 72 | # Check hrefs containing: 73 | # 74 | # * href="http[s]:// 75 | # * href='http[s]:// 76 | # * href=http[s]:// 77 | # 78 | $ regex-grep --path=. --extension=htm,html,php,tpl --text --size --custom="href=[[:space:]]*['\''\\\"]?http[s]?://" 79 | 80 | $ regex-perl --path=. --extension=htm,html,php,tpl --text --size --custom="href=[[:space:]]*[\x27\"]?http[s]?:\/\/" 81 | ``` 82 | 83 | 84 | Check HTML tags for hardcoded languages 85 | 86 | ```bash 87 | # Check lang for non-dynamic values (with hardcoded) tags containing 88 | # 89 | # * xml:lang="en" 90 | # * xml:lang='de' 91 | # * xml:lang=zh 92 | # * lang="ko" 93 | # * lang='ru' 94 | # * lang=pl 95 | # 96 | $ regex-grep --path=. --extension=htm,html,php,tpl --text --size --custom="(:|[[:space:]])lang=['\''\\\"]?[A-Za-z]{2}['\''\\\"]?(>|[[:space:]])" 97 | 98 | $ regex-perl --path=. --extension=htm,html,php,tpl --text --size --custom="(:|[[:space:]])lang=[\x27\"]?[A-Za-z]{2}[\x27\"]?(>|[[:space:]])" 99 | ``` 100 | -------------------------------------------------------------------------------- /bin/file-empty: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="file-empty" 10 | MY_DESC="Scans recursively for files that are empty." 11 | MY_FINISH_OK="No empty files found." 12 | MY_FINISH_ERR="Found empty files." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="FILE_EMPTY_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=0 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="test ! -s \"\$1\" && echo \"\$1: Empty file.\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="echo \"test is a built-in shell command\"" 49 | 50 | 51 | 52 | 53 | 54 | 55 | ############################################################ 56 | # Do not edit from here 57 | ############################################################ 58 | 59 | # 60 | # Version 61 | # 62 | MY_VERSION="0.15" 63 | MY_DATE="2018-04-09" 64 | 65 | # 66 | # Credits 67 | # 68 | MY_AUTHOR="cytopia" 69 | MY_EMAIL="cytopia@everythingcli.org" 70 | 71 | # 72 | # Required system binaries 73 | # 74 | REQUIRED_BINS="awk grep find sed tr xargs" 75 | 76 | # 77 | # Variables populated by cmd args or config file 78 | # 79 | MY_PATH= 80 | MY_SHE= 81 | MY_EXT=0 82 | MY_IGN= 83 | MY_TXT=0 84 | MY_SIZ=0 85 | MY_DRY=0 86 | MY_LST=0 87 | MY_VER=0 88 | MY_DEB=0 89 | MY_FIX=0 90 | MY_CFG= 91 | MY_CUS= 92 | 93 | CLR_SUC="\033[0;32m" 94 | CLR_ERR="\033[0;31m" 95 | CLR_CLS="\033[0m" 96 | 97 | ################################################################################ 98 | # 99 | # F U N C T I O N S 100 | # 101 | ################################################################################ 102 | 103 | 104 | 105 | print_usage() { 106 | 107 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 108 | _custom=" [--custom=\"opts\"]" 109 | else 110 | _custom="" 111 | fi 112 | 113 | if [ "${ENABLE_FIX}" = "1" ];then 114 | _fix=" [--fix]" 115 | else 116 | _fix="" 117 | fi 118 | 119 | echo "Usage: ${MY_NAME} [--text] [--size] [--shebang=php] [--extension=tpl,htm,html,php,...] [--ignore=dir1,dir2] [--config=conf] [--confpre=${MY_CONF_PRE}]${_custom}${_fix} [--verbose] [--debug] [--dry] [--list] --path=dir" 120 | echo " ${MY_NAME} --info" 121 | echo " ${MY_NAME} --help" 122 | echo " ${MY_NAME} --version" 123 | echo 124 | echo "${MY_DESC}" 125 | echo "Will return 1 on occurance, otherwise 0." 126 | echo 127 | echo "Required arguments:" 128 | echo 129 | echo " --path= Specify directory where to scan." 130 | echo 131 | echo 132 | echo "Optional run arguments:" 133 | if [ "${ENABLE_FIX}" = "1" ];then 134 | echo " --fix Fixable :-)" 135 | echo " Fix the problems for the specified files." 136 | echo " Note, all other options below also apply" 137 | echo 138 | fi 139 | echo " --text Limit search to text files only (non-binary)." 140 | echo " Can be narrowed further with '--extension'" 141 | echo 142 | echo " --size Limit search to files which are not empty (bigger than 0 bytes)." 143 | echo 144 | echo " --shebang= Only find files (shell scripts) with this specific shebang." 145 | echo " It is useful to combine this with --text and --size for faster searches." 146 | echo " Use with --dry to see how this search command is generated." 147 | echo " Example:" 148 | echo " --shebang=bash" 149 | echo " --shebang=php" 150 | echo " --shebang=sh" 151 | echo 152 | echo " --extension= Only find files matching those extensions." 153 | echo " Comma separated list of file extensions." 154 | echo " Only find files matching those extensions." 155 | echo " Defaults to all files if not specified or empty." 156 | echo " Example:" 157 | echo " --extension=html,php,inc" 158 | echo " --extension=php" 159 | echo 160 | echo " --ignore= Comma separated list of ignore paths." 161 | echo " Directories must be specified from the starting location of --path." 162 | echo " Example:" 163 | echo " ignore 'foor/bar' folder inside '/var/www' path:" 164 | echo " --path=/var/www --ignore=foo/bar" 165 | echo 166 | echo " --config= Load configuration file." 167 | echo " File must contain the following directives:" 168 | echo " ${MY_CONF_PRE}EXTENSION=\"\" # comma separated" 169 | echo " ${MY_CONF_PRE}IGNORE=\"\" # comma separated" 170 | echo " ${MY_CONF_PRE}TEXT=0|1 # 0 or 1" 171 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 172 | echo " ${MY_CONF_PRE}CUSTOM=\"\" # custom command" 173 | fi 174 | echo " Note that cmd arguments take precedence over" 175 | echo " config file settings." 176 | echo 177 | echo " --confpre= Set custom configuration directive prefix." 178 | echo " Current default ist: '${MY_CONF_PRE}'." 179 | echo " This is useful, when you want to define different defaults" 180 | echo " per check via configuration file." 181 | echo 182 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 183 | echo " --custom= Parse custom command line option to the check binary." 184 | echo " Note that when you want to add config files or other files" 185 | echo " you must use an absolute path." 186 | echo 187 | echo " Current custom command:" 188 | echo " --custom=\"${DEFAULT_CUST_OPS//\"/\\\"}\"" # \" -> \\\" 189 | echo 190 | echo " Overwrite example:" 191 | echo " --custom=\"--color --config /absoulte/path/conf.json\"" 192 | echo 193 | fi 194 | echo " --verbose Be verbose and print commands and files being checked." 195 | echo 196 | echo 197 | echo " --debug Print system messages." 198 | echo 199 | echo 200 | echo "Optional training arguments:" 201 | echo " --dry Don't do anything, just display the commands." 202 | echo 203 | echo " --list Instead of searching inside the files, just display the filenames" 204 | echo " that would be found by --path, --extension and --ignore" 205 | echo 206 | echo 207 | echo "System arguments:" 208 | echo " --info Show versions of required commands (useful for bugreports)." 209 | echo " --help Show help screen." 210 | echo " --version Show version information." 211 | echo 212 | echo 213 | echo "${MY_NAME} is part of the awesome-ci collection." 214 | echo "https://github.com/cytopia/awesome-ci" 215 | } 216 | 217 | print_version() { 218 | echo "tool: ${MY_NAME}" 219 | echo "version: v${MY_VERSION} (${MY_DATE})" 220 | echo "author: ${MY_AUTHOR}" 221 | echo "email: ${MY_EMAIL}" 222 | echo 223 | echo "${MY_NAME} is part of the awesome-ci collection." 224 | echo "https://github.com/cytopia/awesome-ci" 225 | } 226 | 227 | print_info() { 228 | 229 | # 230 | # Required binaries 231 | # 232 | 233 | if ! echo "${MY_INFO}" | grep -cqE "^bash"; then 234 | MY_CMD_VERSION="bash --version | grep -E '(([0-9]+)(\.))+'" 235 | echo "\$ ${MY_CMD_VERSION}" 236 | eval "${MY_CMD_VERSION}" 237 | echo 238 | fi 239 | if ! echo "${MY_INFO}" | grep -cqE "^\(awk"; then 240 | MY_CMD_VERSION="(awk -Wversion 2>/dev/null || awk --version) | grep -E '(([0-9]+)(\.))+'" 241 | echo "\$ ${MY_CMD_VERSION}" 242 | eval "${MY_CMD_VERSION}" 243 | echo 244 | fi 245 | if ! echo "${MY_INFO}" | grep -cqE "^grep"; then 246 | MY_CMD_VERSION="grep -V | grep -E '([0-9]+\.+)+'" 247 | echo "\$ ${MY_CMD_VERSION}" 248 | eval "${MY_CMD_VERSION}" 249 | echo 250 | fi 251 | if ! echo "${MY_INFO}" | grep -cqE "^\(find"; then 252 | MY_CMD_VERSION="(find --version >/dev/null 2>&1) && (find --version 2>&1 | head -1) || (echo 'find (BSD find)')" 253 | echo "\$ ${MY_CMD_VERSION}" 254 | eval "${MY_CMD_VERSION}" 255 | echo 256 | fi 257 | if ! echo "${MY_INFO}" | grep -cqE "^\(sed"; then 258 | MY_CMD_VERSION="(sed --version >/dev/null 2>&1) && (sed --version 2>&1 | head -1) || (echo 'sed (BSD sed)')" 259 | echo "\$ ${MY_CMD_VERSION}" 260 | eval "${MY_CMD_VERSION}" 261 | echo 262 | fi 263 | if ! echo "${MY_INFO}" | grep -cqE "^\(tr"; then 264 | MY_CMD_VERSION="(tr --version >/dev/null 2>&1) && (tr --version 2>&1 | head -1) || (echo 'tr (BSD tr)')" 265 | echo "\$ ${MY_CMD_VERSION}" 266 | eval "${MY_CMD_VERSION}" 267 | echo 268 | fi 269 | if ! echo "${MY_INFO}" | grep -cqE "^\(xargs"; then 270 | MY_CMD_VERSION="(xargs --version >/dev/null 2>&1) && (xargs --version 2>&1 | head -1) || (echo 'xargs (BSD xargs)')" 271 | echo "\$ ${MY_CMD_VERSION}" 272 | eval "${MY_CMD_VERSION}" 273 | echo 274 | fi 275 | 276 | # 277 | # Custom binary 278 | # 279 | if [ "${MY_INFO}" != "" ]; then 280 | echo "\$ ${MY_INFO}" 281 | eval "${MY_INFO}" 282 | echo 283 | fi 284 | 285 | # 286 | # --fix binary 287 | # 288 | if [ "${ENABLE_FIX}" = "1" ] && [ "${REQUIRED_FIX_BINS}" != "" ]; then 289 | _can_fix="1" 290 | for _bin in ${REQUIRED_FIX_BINS}; do 291 | if ! command -v "${_bin}" >/dev/null 2>&1; then 292 | echo "${_bin}: Not found." 293 | _can_fix="0}" 294 | fi 295 | done 296 | if [ "${_can_fix}" = "1" ]; then 297 | echo "\$ ${MY_FIX_INFO}" 298 | eval "${MY_FIX_INFO}" 299 | echo 300 | else 301 | echo "Unable to use --fix" 302 | echo 303 | return 0 304 | fi 305 | fi 306 | } 307 | 308 | 309 | check_requirements() { 310 | _debug="${1}" 311 | _ret1=0 312 | _ret2=0 313 | 314 | # System binaries 315 | for _bin in ${REQUIRED_BINS}; do 316 | if ! command -v "${_bin}" >/dev/null 2>&1; then 317 | echo "[ERR] Required sys binary '${_bin}' not found." 318 | _ret1=1 319 | else 320 | if [ "${_debug}" = "1" ]; then 321 | echo "[OK] Required system binary '${_bin}' found." 322 | fi 323 | fi 324 | done 325 | 326 | # Specific binaries for this check 327 | for _bin in ${REQUIRED_CUST_BINS}; do 328 | if ! command -v "${_bin}" >/dev/null 2>&1; then 329 | echo "[ERR] Required custom binary '${_bin}' not found." 330 | _ret2=1 331 | else 332 | if [ "${_debug}" = "1" ]; then 333 | echo "[OK] Required custom binary '${_bin}' found." 334 | fi 335 | fi 336 | done 337 | 338 | # Binaries required to fix 339 | if [ "${ENABLE_FIX}" = "1" ] && [ "${MY_FIX}" = "1" ]; then 340 | for _bin in ${REQUIRED_FIX_BINS}; do 341 | if ! command -v "${_bin}" >/dev/null 2>&1; then 342 | echo "[ERR] Required --fix binary '${_bin}' not found." 343 | _ret2=1 344 | else 345 | if [ "${_debug}" = "1" ]; then 346 | echo "[OK] Required --fix binary '${_bin}' found." 347 | fi 348 | fi 349 | done 350 | fi 351 | 352 | 353 | return $((_ret1 + _ret2)) 354 | } 355 | 356 | check_config_file() { 357 | _config="${1}" 358 | 359 | # Check config file 360 | if [ ! -f "${_config}" ]; then 361 | echo "[CONFIG] Config file not found: ${_config}" 362 | return 1 363 | fi 364 | 365 | # Check directives 366 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=" "${_config}"; then 367 | echo "[CONFIG] ${MY_CONF_PRE}IGNORE variable not found in config." 368 | return 1 369 | fi 370 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=[\"']{1}.*[\"']{1}$" "${_config}"; then 371 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}IGNORE variable." 372 | return 1 373 | fi 374 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=" "${_config}"; then 375 | echo "[CONFIG] ${MY_CONF_PRE}EXTENSION variable not found in config." 376 | return 1 377 | fi 378 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=[\"']{1}.*[\"']{1}$" "${_config}"; then 379 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}EXTENSION variable." 380 | return 1 381 | fi 382 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=" "${_config}"; then 383 | echo "[CONFIG] ${MY_CONF_PRE}TEXT variable not found in config." 384 | return 1 385 | fi 386 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=[\"']*[01]{1}[\"']*$" "${_config}"; then 387 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}TEXT variable." 388 | return 1 389 | fi 390 | 391 | # Check optional directives 392 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 393 | if ! grep -Eq "^${MY_CONF_PRE}CUSTOM=[\"']{1}.*[\"']{1}$" "${_config}"; then 394 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}CUSTOM variable." 395 | return 1 396 | fi 397 | fi 398 | 399 | } 400 | 401 | 402 | # 403 | # System independent method 404 | # to get number of CPU cores. 405 | # (defaults to 1 if impossible) 406 | # 407 | num_cpu() { 408 | if ! _num="$( getconf _NPROCESSORS_ONLN 2>/dev/null )"; then 409 | echo "1" 410 | else 411 | echo "${_num}" 412 | fi 413 | } 414 | 415 | 416 | # 417 | # sed wrapper that automatically escapes 418 | # regex literals 419 | # 420 | mysed() { 421 | _input="$1" 422 | _search="$2" 423 | _replace="$3" 424 | 425 | echo "${_input}" | sed "s/$(echo "${_search}" | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo "${_replace}" | sed -e 's/[\/&]/\\&/g')/g" 426 | } 427 | 428 | 429 | 430 | 431 | ################################################################################ 432 | # 433 | # M A I N E N T R Y P O I N T 434 | # 435 | ################################################################################ 436 | 437 | 438 | 439 | ############################################################ 440 | # Command Line arguments 441 | ############################################################ 442 | 443 | 444 | # 445 | # Read command line arguments 446 | # 447 | while [ $# -gt 0 ]; do 448 | case "${1}" in 449 | 450 | # ---------------------------------------- 451 | --path=*) 452 | MY_PATH="${1//--path=/}" 453 | ;; 454 | 455 | # ---------------------------------------- 456 | --shebang=*) 457 | MY_SHE="${1//--shebang=/}" 458 | ;; 459 | 460 | # ---------------------------------------- 461 | --extension=*) 462 | MY_EXT="${1//--extension=/}" 463 | ;; 464 | 465 | # ---------------------------------------- 466 | --ignore=*) 467 | MY_IGN="${1//--ignore=/}" 468 | ;; 469 | 470 | # ---------------------------------------- 471 | --config=*) 472 | MY_CFG="${1//--config=/}" 473 | ;; 474 | 475 | # ---------------------------------------- 476 | --confpre=*) 477 | MY_CONF_PRE="${1//--confpre=/}" 478 | ;; 479 | 480 | # ---------------------------------------- 481 | --custom=*) 482 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 483 | MY_CUS="${1//--custom=/}" 484 | else 485 | echo "Invalid argument: ${1}" 486 | echo "Type '${MY_NAME} --help' for available options." 487 | exit 1 488 | fi 489 | ;; 490 | 491 | # ---------------------------------------- 492 | --fix) 493 | if [ "${ENABLE_FIX}" = "1" ]; then 494 | MY_FIX=1 495 | else 496 | echo "Invalid argument: ${1}" 497 | echo "Type '${MY_NAME} --help' for available options." 498 | exit 1 499 | fi 500 | ;; 501 | 502 | 503 | # ---------------------------------------- 504 | --text) 505 | MY_TXT=1 506 | ;; 507 | 508 | # ---------------------------------------- 509 | --size) 510 | MY_SIZ=1 511 | ;; 512 | 513 | # ---------------------------------------- 514 | --dry) 515 | MY_DRY=1 516 | ;; 517 | 518 | # ---------------------------------------- 519 | --list) 520 | MY_LST=1 521 | ;; 522 | 523 | # ---------------------------------------- 524 | --verbose) 525 | MY_VER=1 526 | ;; 527 | 528 | # ---------------------------------------- 529 | --debug) 530 | MY_DEB=1 531 | ;; 532 | 533 | # ---------------------------------------- 534 | --info) 535 | if ! check_requirements "${MY_DEB}"; then 536 | exit 1 537 | fi 538 | 539 | if ! print_info; then 540 | exit 1 541 | fi 542 | 543 | exit 0 544 | ;; 545 | 546 | # ---------------------------------------- 547 | --help) 548 | print_usage 549 | exit 0 550 | ;; 551 | 552 | # ---------------------------------------- 553 | --version) 554 | print_version 555 | exit 0 556 | ;; 557 | 558 | # ---------------------------------------- 559 | *) 560 | echo "Invalid argument: ${1}" 561 | echo "Type '${MY_NAME} --help' for available options." 562 | exit 1 563 | ;; 564 | esac 565 | shift 566 | done 567 | 568 | 569 | 570 | ############################################################ 571 | # Sanity Checks 572 | ############################################################ 573 | 574 | # 575 | # Check general requirements 576 | # 577 | if ! check_requirements "${MY_DEB}"; then 578 | exit 1 579 | fi 580 | 581 | # 582 | # Check path 583 | # 584 | if [ "${MY_PATH}" = "" ]; then 585 | echo "--path not specified" 586 | echo "Type '${MY_NAME} --help' for available options." 587 | exit 1 588 | fi 589 | if [ ! -e "${MY_PATH}" ]; then 590 | echo "Specified path does not exist: '${MY_PATH}'." 591 | echo "Type '${MY_NAME} --help' for available options." 592 | exit 1 593 | fi 594 | 595 | 596 | # 597 | # Check and load config if desired 598 | # 599 | if [ "${MY_CFG}" != "" ]; then 600 | if ! check_config_file "${MY_CFG}"; then 601 | exit 1 602 | fi 603 | 604 | . "${MY_CFG}" 605 | fi 606 | 607 | 608 | 609 | ############################################################ 610 | # Evaluate Settings 611 | ############################################################ 612 | 613 | CPU_CORES="$(num_cpu)" 614 | 615 | 616 | # Var substitutions for config file directives 617 | # to match current program. 618 | EXTENSION="${MY_CONF_PRE}EXTENSION" 619 | IGNORE="${MY_CONF_PRE}IGNORE" 620 | TEXT="${MY_CONF_PRE}TEXT" 621 | SIZE="${MY_CONF_PRE}SIZE" 622 | CUSTOM="${MY_CONF_PRE}CUSTOM" 623 | 624 | # 625 | # Decide on Shebang 626 | # 627 | if [ "${MY_SHE}" != "" ]; then 628 | MY_SHE="xargs -0 -P ${CPU_CORES} -n1 awk '/^#!.*(\/${MY_SHE}|[[:space:]]+${MY_SHE})/{print FILENAME}'" 629 | else 630 | MY_SHE="" 631 | fi 632 | 633 | 634 | 635 | # 636 | # Decide on File extensions 637 | # 638 | if [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" != "0" ]; then 639 | if [ "${MY_DEB}" = "1" ]; then 640 | echo "[ARG] Cmd arg --extension=${MY_EXT} will take precedence over config file value". 641 | fi 642 | MY_EXT="${MY_EXT}" 643 | 644 | elif [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" = "0" ]; then 645 | if [ "${MY_DEB}" = "1" ]; then 646 | echo "[ARG] Using config file values: ext: ${!EXTENSION}" 647 | fi 648 | MY_EXT="${!EXTENSION}" 649 | 650 | elif [ "${MY_CFG}" = "" ] && [ "${MY_EXT}" != "0" ]; then 651 | if [ "${MY_DEB}" = "1" ]; then 652 | echo "[ARG] Using cmd argument: ext: '${MY_EXT}'" 653 | fi 654 | MY_EXT="${MY_EXT}" 655 | 656 | else 657 | if [ "${MY_DEB}" = "1" ]; then 658 | echo "[ARG] Using all file extensions" 659 | fi 660 | MY_EXT= 661 | fi 662 | 663 | 664 | # 665 | # Decide on ignore paths 666 | # 667 | if [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" != "" ]; then 668 | if [ "${MY_DEB}" = "1" ]; then 669 | echo "[ARG] Cmd arg --ignore=${MY_IGN} will take precedence over config file value". 670 | fi 671 | MY_IGN="${MY_IGN}" 672 | 673 | elif [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" = "" ]; then 674 | if [ "${MY_DEB}" = "1" ]; then 675 | echo "[ARG] Using config file values: ignore: ${!IGNORE}" 676 | fi 677 | MY_IGN="${!IGNORE}" 678 | 679 | elif [ "${MY_CFG}" = "" ] && [ "${MY_IGN}" != "" ]; then 680 | if [ "${MY_DEB}" = "1" ]; then 681 | echo "[ARG] Using cmd argument: ignore: ${MY_IGN}" 682 | fi 683 | MY_IGN="${MY_IGN}" 684 | 685 | else 686 | if [ "${MY_DEB}" = "1" ]; then 687 | echo "[ARG] Not ignoring anything" 688 | fi 689 | MY_IGN= 690 | fi 691 | 692 | 693 | # 694 | # Decide on text files (non-binary) or all files 695 | # 696 | if [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" != "0" ]; then 697 | if [ "${MY_DEB}" = "1" ]; then 698 | echo "[ARG] Cmd arg --text: '${MY_TXT}' will take precedence over config file value". 699 | fi 700 | MY_TXT="${MY_TXT}" 701 | 702 | elif [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" = "0" ]; then 703 | if [ "${MY_DEB}" = "1" ]; then 704 | echo "[ARG] Using config file values: --text: ${!TEXT}" 705 | fi 706 | MY_TXT="${!TEXT}" 707 | 708 | elif [ "${MY_CFG}" = "" ] && [ "${MY_TXT}" != "0" ]; then 709 | if [ "${MY_DEB}" = "1" ]; then 710 | echo "[ARG] Using cmd argument: --text: ${MY_TXT}" 711 | fi 712 | MY_TXT="${MY_TXT}" 713 | 714 | else 715 | if [ "${MY_DEB}" = "1" ]; then 716 | echo "[ARG] Not narrowing down by text files" 717 | fi 718 | MY_TXT="0" 719 | fi 720 | 721 | 722 | # 723 | # Decide on file size 724 | # 725 | if [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" != "0" ]; then 726 | if [ "${MY_DEB}" = "1" ]; then 727 | echo "[ARG] Cmd arg --size: '${MY_SIZ}' will take precedence over config file value". 728 | fi 729 | MY_SIZ="${MY_SIZ}" 730 | 731 | elif [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" = "0" ]; then 732 | if [ "${MY_DEB}" = "1" ]; then 733 | echo "[ARG] Using config file values: --size: ${!SIZE}" 734 | fi 735 | MY_SIZ="${!SIZE}" 736 | 737 | elif [ "${MY_CFG}" = "" ] && [ "${MY_SIZ}" != "0" ]; then 738 | if [ "${MY_DEB}" = "1" ]; then 739 | echo "[ARG] Using cmd argument: --size: ${MY_SIZ}" 740 | fi 741 | MY_SIZ="${MY_SIZ}" 742 | 743 | else 744 | if [ "${MY_DEB}" = "1" ]; then 745 | echo "[ARG] Not narrowing down by size > 0 bytes" 746 | fi 747 | MY_SIZ="0" 748 | fi 749 | 750 | if [ "${MY_SIZ}" = "1" ]; then 751 | MY_SIZ="! -size 0" 752 | else 753 | MY_SIZ="" 754 | fi 755 | 756 | 757 | 758 | # 759 | # Decide on Custom string 760 | # 761 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 762 | if [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" != "" ]; then 763 | if [ "${MY_DEB}" = "1" ]; then 764 | echo "[ARG] Cmd arg --custom=\"${MY_CUS}\" will take precedence over config file value". 765 | fi 766 | MY_CUS="${MY_CUS}" 767 | 768 | elif [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" = "" ]; then 769 | if [ "${MY_DEB}" = "1" ]; then 770 | echo "[ARG] Using config file values: custom: \"${!CUSTOM}\"" 771 | fi 772 | MY_CUS="${!CUSTOM}" 773 | 774 | elif [ "${MY_CFG}" = "" ] && [ "${MY_CUS}" != "" ]; then 775 | if [ "${MY_DEB}" = "1" ]; then 776 | echo "[ARG] Using cmd argument: custom: \"${MY_CUS}\"" 777 | fi 778 | MY_CUS="${MY_CUS}" 779 | 780 | else 781 | if [ "${MY_DEB}" = "1" ]; then 782 | echo "[ARG] No customization applied" 783 | fi 784 | MY_CUS= 785 | fi 786 | fi 787 | 788 | 789 | 790 | ############################################################ 791 | # Build command 792 | ############################################################ 793 | 794 | # 795 | # 'find' pattern for file extensions 796 | # 797 | if [ "${MY_EXT}" != "" ]; then 798 | NAME_PATTERN="\( -iname \*.${MY_EXT//,/ -o -iname \\*.} \)" 799 | else 800 | NAME_PATTERN="" 801 | fi 802 | 803 | # 804 | # 'find' pattern for ignores/excludes 805 | # 806 | if [ "${MY_IGN}" != "" ]; then 807 | EXCL_PATTERN="-not \( -path \"${MY_PATH}/${MY_IGN//,/*\" -o -path \"${MY_PATH}\/}*\" \)" 808 | else 809 | EXCL_PATTERN="" 810 | fi 811 | 812 | 813 | # 814 | # Fix? 815 | # 816 | if [ "${MY_FIX}" = "1" ]; then 817 | MY_CHECK="${MY_FIX_CMD}" 818 | else 819 | # 820 | # Normal check 821 | # (Apply custom command?) 822 | # 823 | if [ "${MY_CUS}" = "" ]; then 824 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${DEFAULT_CUST_OPS}" )" 825 | else 826 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${MY_CUS}" )" 827 | fi 828 | fi 829 | 830 | 831 | # 832 | # Show files or grep in found files? 833 | # 834 | 835 | 836 | # Be verbose? 837 | if [ "${MY_VER}" = "1" ]; then 838 | XARGS_VERBOSE="-t" 839 | else 840 | XARGS_VERBOSE="" 841 | fi 842 | 843 | # 844 | # Build command 845 | # 846 | 847 | 848 | ### Text files (list-only) 849 | if [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "1" ]; then 850 | if [ "${MY_SHE}" != "" ]; then 851 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE}" 852 | else 853 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il ''" 854 | fi 855 | 856 | ### Text files (run!!!) 857 | elif [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "0" ]; then 858 | if [ "${MY_SHE}" != "" ]; then 859 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 860 | else 861 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 862 | fi 863 | 864 | ### All files (list-only) 865 | elif [ "${MY_TXT}" = "0" ] && [ "${MY_LST}" = "1" ]; then 866 | if [ "${MY_SHE}" != "" ]; then 867 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE}" 868 | else 869 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print" 870 | fi 871 | 872 | 873 | ### All files (run!!!) 874 | else 875 | if [ "${MY_SHE}" != "" ]; then 876 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 877 | else 878 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 879 | fi 880 | 881 | fi 882 | 883 | 884 | 885 | 886 | ############################################################ 887 | # Execute 888 | ############################################################ 889 | 890 | # Dry mode? 891 | if [ "${MY_DRY}" = "1" ]; then 892 | printf "%s\n" "${MY_CMD}" 893 | exit 0 894 | fi 895 | 896 | printf "\$ %s\n" "${MY_CMD}" 897 | 898 | output="$(eval "${MY_CMD}")" 899 | 900 | # If showing files only, exit normally 901 | if [ "${MY_LST}" = "1" ]; then 902 | printf "%s\n" "${output}" 903 | exit 0 904 | fi 905 | 906 | 907 | if [ "${output}" != "" ]; then 908 | printf "%s\n" "${output}" 909 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 910 | exit 1 911 | else 912 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 913 | exit 0 914 | fi 915 | -------------------------------------------------------------------------------- /bin/git-ignored: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="git-ignored" 10 | MY_DESC="Scans your git repository for ignored files still present in git cache." 11 | MY_FINISH_OK="No ignored files within git cache." 12 | MY_FINISH_ERR="Found ignored files in git cache." 13 | 14 | # Custom required binaries 15 | REQUIRED_CUST_BINS="git" 16 | 17 | # How to check for files 18 | # Note: '%' comes from xargs and represents 19 | # one file as parameter. 20 | # Called like this: 21 | # eval "xargs -I % sh '${MY_CHECK}'" 22 | MY_CHECK="git ls-files --ignored --exclude-standard 2>&1 || true" 23 | 24 | # Command to be displayed for --info 25 | MY_INFO="git --version" 26 | 27 | 28 | 29 | 30 | 31 | 32 | ############################################################ 33 | # Do not edit from here 34 | ############################################################ 35 | 36 | # 37 | # Version 38 | # 39 | MY_VERSION="0.15" 40 | MY_DATE="2018-04-09" 41 | 42 | # 43 | # Credits 44 | # 45 | MY_AUTHOR="cytopia" 46 | MY_EMAIL="cytopia@everythingcli.org" 47 | 48 | # 49 | # Required system binaries 50 | # 51 | REQUIRED_BINS="sed" 52 | 53 | # 54 | # Variables populated by cmd args or config file 55 | # 56 | MY_PATH= 57 | MY_DRY=0 58 | MY_LST=0 59 | MY_DEB=0 60 | 61 | CLR_SUC="\033[0;32m" 62 | CLR_ERR="\033[0;31m" 63 | CLR_CLS="\033[0m" 64 | 65 | 66 | ################################################################################ 67 | # 68 | # F U N C T I O N S 69 | # 70 | ################################################################################ 71 | 72 | print_usage() { 73 | 74 | echo "Usage: ${MY_NAME} [--debug] [--dry] [--list] --path=dir" 75 | echo " ${MY_NAME} --info" 76 | echo " ${MY_NAME} --help" 77 | echo " ${MY_NAME} --version" 78 | echo 79 | echo "${MY_DESC}" 80 | echo "Will return 1 on occurance, otherwise 0." 81 | echo 82 | echo "Required arguments:" 83 | echo " --path= Specify directory where to scan." 84 | echo 85 | echo 86 | echo "Optional run arguments:" 87 | echo " --debug Print system messages." 88 | echo 89 | echo 90 | echo "Optional training arguments:" 91 | echo " --dry Don't do anything, just display the commands." 92 | echo 93 | echo " --list Instead of searching inside the files, just display the filenames" 94 | echo " that would be found by --path, --extension and --ignore" 95 | echo 96 | echo "System arguments:" 97 | echo " --info Show command version." 98 | echo " --help Show help screen." 99 | echo " --version Show version information." 100 | echo 101 | echo 102 | echo "${MY_NAME} is part of the awesome-ci collection." 103 | echo "https://github.com/cytopia/awesome-ci" 104 | } 105 | 106 | print_version() { 107 | echo "tool: ${MY_NAME}" 108 | echo "version: v${MY_VERSION} (${MY_DATE})" 109 | echo "author: ${MY_AUTHOR}" 110 | echo "email: ${MY_EMAIL}" 111 | echo 112 | echo "${MY_NAME} is part of the awesome-ci collection." 113 | echo "https://github.com/cytopia/awesome-ci" 114 | } 115 | 116 | check_requirements() { 117 | _debug="${1}" 118 | _ret1=0 119 | _ret2=0 120 | 121 | # System binaries 122 | for _bin in ${REQUIRED_BINS}; do 123 | if ! command -v "${_bin}" >/dev/null 2>&1; then 124 | echo "[ERR] Required sys binary '${_bin}' not found." 125 | _ret1=1 126 | else 127 | if [ "${_debug}" = "1" ]; then 128 | echo "[OK] Required system binary '${_bin}' found." 129 | fi 130 | fi 131 | done 132 | 133 | # Specific binaries for this check 134 | for _bin in ${REQUIRED_CUST_BINS}; do 135 | if ! command -v "${_bin}" >/dev/null 2>&1; then 136 | echo "[ERR] Required custom binary '${_bin}' not found." 137 | _ret2=1 138 | else 139 | if [ "${_debug}" = "1" ]; then 140 | echo "[OK] Required custom binary '${_bin}' found." 141 | fi 142 | fi 143 | done 144 | 145 | return $((_ret1 + _ret2)) 146 | } 147 | 148 | 149 | 150 | ################################################################################ 151 | # 152 | # M A I N E N T R Y P O I N T 153 | # 154 | ################################################################################ 155 | 156 | 157 | 158 | ############################################################ 159 | # Command Line arguments 160 | ############################################################ 161 | 162 | 163 | # 164 | # Read command line arguments 165 | # 166 | while [ $# -gt 0 ]; do 167 | case "${1}" in 168 | 169 | # ---------------------------------------- 170 | --path=*) 171 | MY_PATH="$( echo "${1}" | sed 's/--path=//g' )" 172 | ;; 173 | 174 | # ---------------------------------------- 175 | --dry) 176 | MY_DRY=1 177 | ;; 178 | 179 | # ---------------------------------------- 180 | --list) 181 | MY_LST=1 182 | ;; 183 | 184 | # ---------------------------------------- 185 | --debug) 186 | MY_DEB=1 187 | ;; 188 | 189 | # ---------------------------------------- 190 | --info) 191 | echo "\$ ${MY_INFO}" 192 | eval "${MY_INFO}" 193 | exit 0 194 | ;; 195 | 196 | # ---------------------------------------- 197 | --help) 198 | print_usage 199 | exit 0 200 | ;; 201 | 202 | # ---------------------------------------- 203 | --version) 204 | print_version 205 | exit 0 206 | ;; 207 | 208 | # ---------------------------------------- 209 | *) 210 | echo "Invalid argument: ${1}" 211 | echo "Type '${MY_NAME} --help' for available options." 212 | exit 1 213 | ;; 214 | esac 215 | shift 216 | done 217 | 218 | 219 | 220 | ############################################################ 221 | # Sanity Checks 222 | ############################################################ 223 | 224 | # 225 | # Check general requirements 226 | # 227 | if ! check_requirements "${MY_DEB}"; then 228 | exit 1 229 | fi 230 | 231 | # 232 | # Check path 233 | # 234 | if [ "${MY_PATH}" = "" ]; then 235 | echo "--path not specified" 236 | echo "Type '${MY_NAME} --help' for available options." 237 | exit 1 238 | fi 239 | if [ ! -e "${MY_PATH}" ]; then 240 | echo "Specified path does not exist: '${MY_PATH}'." 241 | echo "Type '${MY_NAME} --help' for available options." 242 | exit 1 243 | fi 244 | 245 | 246 | 247 | 248 | 249 | ############################################################ 250 | # Execute 251 | ############################################################ 252 | 253 | # Dry mode? 254 | if [ "${MY_DRY}" = "1" ]; then 255 | echo "\$ ${MY_CHECK}" 256 | exit 0 257 | fi 258 | 259 | echo "\$ ${MY_CHECK}" 260 | 261 | output="$(eval "cd ${MY_PATH} && ${MY_CHECK}")" 262 | 263 | # If showing files only, exit normally 264 | if [ "${MY_LST}" = "1" ]; then 265 | echo "${output}" 266 | exit 0 267 | fi 268 | 269 | 270 | if [ "${output}" != "" ]; then 271 | printf "%s\n" "${output}" 272 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 273 | exit 1 274 | else 275 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 276 | exit 0 277 | fi 278 | -------------------------------------------------------------------------------- /bin/syntax-js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="syntax-js" 10 | MY_DESC="Scans recursively for files containing JS syntax errors." 11 | MY_FINISH_OK="No files with JS syntax errors found." 12 | MY_FINISH_ERR="Found files with JS syntax errors." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="SYNTAX_JS_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="eslint" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=1 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="--color --no-eslintrc --quiet" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="eslint __CUSTOM_OPT_PLACEHOLDER__ \"\$1\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="eslint -v" 49 | 50 | 51 | 52 | 53 | 54 | 55 | ############################################################ 56 | # Do not edit from here 57 | ############################################################ 58 | 59 | # 60 | # Version 61 | # 62 | MY_VERSION="0.15" 63 | MY_DATE="2018-04-09" 64 | 65 | # 66 | # Credits 67 | # 68 | MY_AUTHOR="cytopia" 69 | MY_EMAIL="cytopia@everythingcli.org" 70 | 71 | # 72 | # Required system binaries 73 | # 74 | REQUIRED_BINS="awk grep find sed tr xargs" 75 | 76 | # 77 | # Variables populated by cmd args or config file 78 | # 79 | MY_PATH= 80 | MY_SHE= 81 | MY_EXT=0 82 | MY_IGN= 83 | MY_TXT=0 84 | MY_SIZ=0 85 | MY_DRY=0 86 | MY_LST=0 87 | MY_VER=0 88 | MY_DEB=0 89 | MY_FIX=0 90 | MY_CFG= 91 | MY_CUS= 92 | 93 | CLR_SUC="\033[0;32m" 94 | CLR_ERR="\033[0;31m" 95 | CLR_CLS="\033[0m" 96 | 97 | ################################################################################ 98 | # 99 | # F U N C T I O N S 100 | # 101 | ################################################################################ 102 | 103 | 104 | 105 | print_usage() { 106 | 107 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 108 | _custom=" [--custom=\"opts\"]" 109 | else 110 | _custom="" 111 | fi 112 | 113 | if [ "${ENABLE_FIX}" = "1" ];then 114 | _fix=" [--fix]" 115 | else 116 | _fix="" 117 | fi 118 | 119 | echo "Usage: ${MY_NAME} [--text] [--size] [--shebang=php] [--extension=tpl,htm,html,php,...] [--ignore=dir1,dir2] [--config=conf] [--confpre=${MY_CONF_PRE}]${_custom}${_fix} [--verbose] [--debug] [--dry] [--list] --path=dir" 120 | echo " ${MY_NAME} --info" 121 | echo " ${MY_NAME} --help" 122 | echo " ${MY_NAME} --version" 123 | echo 124 | echo "${MY_DESC}" 125 | echo "Will return 1 on occurance, otherwise 0." 126 | echo 127 | echo "Required arguments:" 128 | echo 129 | echo " --path= Specify directory where to scan." 130 | echo 131 | echo 132 | echo "Optional run arguments:" 133 | if [ "${ENABLE_FIX}" = "1" ];then 134 | echo " --fix Fixable :-)" 135 | echo " Fix the problems for the specified files." 136 | echo " Note, all other options below also apply" 137 | echo 138 | fi 139 | echo " --text Limit search to text files only (non-binary)." 140 | echo " Can be narrowed further with '--extension'" 141 | echo 142 | echo " --size Limit search to files which are not empty (bigger than 0 bytes)." 143 | echo 144 | echo " --shebang= Only find files (shell scripts) with this specific shebang." 145 | echo " It is useful to combine this with --text and --size for faster searches." 146 | echo " Use with --dry to see how this search command is generated." 147 | echo " Example:" 148 | echo " --shebang=bash" 149 | echo " --shebang=php" 150 | echo " --shebang=sh" 151 | echo 152 | echo " --extension= Only find files matching those extensions." 153 | echo " Comma separated list of file extensions." 154 | echo " Only find files matching those extensions." 155 | echo " Defaults to all files if not specified or empty." 156 | echo " Example:" 157 | echo " --extension=html,php,inc" 158 | echo " --extension=php" 159 | echo 160 | echo " --ignore= Comma separated list of ignore paths." 161 | echo " Directories must be specified from the starting location of --path." 162 | echo " Example:" 163 | echo " ignore 'foor/bar' folder inside '/var/www' path:" 164 | echo " --path=/var/www --ignore=foo/bar" 165 | echo 166 | echo " --config= Load configuration file." 167 | echo " File must contain the following directives:" 168 | echo " ${MY_CONF_PRE}EXTENSION=\"\" # comma separated" 169 | echo " ${MY_CONF_PRE}IGNORE=\"\" # comma separated" 170 | echo " ${MY_CONF_PRE}TEXT=0|1 # 0 or 1" 171 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 172 | echo " ${MY_CONF_PRE}CUSTOM=\"\" # custom command" 173 | fi 174 | echo " Note that cmd arguments take precedence over" 175 | echo " config file settings." 176 | echo 177 | echo " --confpre= Set custom configuration directive prefix." 178 | echo " Current default ist: '${MY_CONF_PRE}'." 179 | echo " This is useful, when you want to define different defaults" 180 | echo " per check via configuration file." 181 | echo 182 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 183 | echo " --custom= Parse custom command line option to the check binary." 184 | echo " Note that when you want to add config files or other files" 185 | echo " you must use an absolute path." 186 | echo 187 | echo " Current custom command:" 188 | echo " --custom=\"${DEFAULT_CUST_OPS//\"/\\\"}\"" # \" -> \\\" 189 | echo 190 | echo " Overwrite example:" 191 | echo " --custom=\"--color --config /absoulte/path/conf.json\"" 192 | echo 193 | fi 194 | echo " --verbose Be verbose and print commands and files being checked." 195 | echo 196 | echo 197 | echo " --debug Print system messages." 198 | echo 199 | echo 200 | echo "Optional training arguments:" 201 | echo " --dry Don't do anything, just display the commands." 202 | echo 203 | echo " --list Instead of searching inside the files, just display the filenames" 204 | echo " that would be found by --path, --extension and --ignore" 205 | echo 206 | echo 207 | echo "System arguments:" 208 | echo " --info Show versions of required commands (useful for bugreports)." 209 | echo " --help Show help screen." 210 | echo " --version Show version information." 211 | echo 212 | echo 213 | echo "${MY_NAME} is part of the awesome-ci collection." 214 | echo "https://github.com/cytopia/awesome-ci" 215 | } 216 | 217 | print_version() { 218 | echo "tool: ${MY_NAME}" 219 | echo "version: v${MY_VERSION} (${MY_DATE})" 220 | echo "author: ${MY_AUTHOR}" 221 | echo "email: ${MY_EMAIL}" 222 | echo 223 | echo "${MY_NAME} is part of the awesome-ci collection." 224 | echo "https://github.com/cytopia/awesome-ci" 225 | } 226 | 227 | print_info() { 228 | 229 | # 230 | # Required binaries 231 | # 232 | 233 | if ! echo "${MY_INFO}" | grep -cqE "^bash"; then 234 | MY_CMD_VERSION="bash --version | grep -E '(([0-9]+)(\.))+'" 235 | echo "\$ ${MY_CMD_VERSION}" 236 | eval "${MY_CMD_VERSION}" 237 | echo 238 | fi 239 | if ! echo "${MY_INFO}" | grep -cqE "^\(awk"; then 240 | MY_CMD_VERSION="(awk -Wversion 2>/dev/null || awk --version) | grep -E '(([0-9]+)(\.))+'" 241 | echo "\$ ${MY_CMD_VERSION}" 242 | eval "${MY_CMD_VERSION}" 243 | echo 244 | fi 245 | if ! echo "${MY_INFO}" | grep -cqE "^grep"; then 246 | MY_CMD_VERSION="grep -V | grep -E '([0-9]+\.+)+'" 247 | echo "\$ ${MY_CMD_VERSION}" 248 | eval "${MY_CMD_VERSION}" 249 | echo 250 | fi 251 | if ! echo "${MY_INFO}" | grep -cqE "^\(find"; then 252 | MY_CMD_VERSION="(find --version >/dev/null 2>&1) && (find --version 2>&1 | head -1) || (echo 'find (BSD find)')" 253 | echo "\$ ${MY_CMD_VERSION}" 254 | eval "${MY_CMD_VERSION}" 255 | echo 256 | fi 257 | if ! echo "${MY_INFO}" | grep -cqE "^\(sed"; then 258 | MY_CMD_VERSION="(sed --version >/dev/null 2>&1) && (sed --version 2>&1 | head -1) || (echo 'sed (BSD sed)')" 259 | echo "\$ ${MY_CMD_VERSION}" 260 | eval "${MY_CMD_VERSION}" 261 | echo 262 | fi 263 | if ! echo "${MY_INFO}" | grep -cqE "^\(tr"; then 264 | MY_CMD_VERSION="(tr --version >/dev/null 2>&1) && (tr --version 2>&1 | head -1) || (echo 'tr (BSD tr)')" 265 | echo "\$ ${MY_CMD_VERSION}" 266 | eval "${MY_CMD_VERSION}" 267 | echo 268 | fi 269 | if ! echo "${MY_INFO}" | grep -cqE "^\(xargs"; then 270 | MY_CMD_VERSION="(xargs --version >/dev/null 2>&1) && (xargs --version 2>&1 | head -1) || (echo 'xargs (BSD xargs)')" 271 | echo "\$ ${MY_CMD_VERSION}" 272 | eval "${MY_CMD_VERSION}" 273 | echo 274 | fi 275 | 276 | # 277 | # Custom binary 278 | # 279 | if [ "${MY_INFO}" != "" ]; then 280 | echo "\$ ${MY_INFO}" 281 | eval "${MY_INFO}" 282 | echo 283 | fi 284 | 285 | # 286 | # --fix binary 287 | # 288 | if [ "${ENABLE_FIX}" = "1" ] && [ "${REQUIRED_FIX_BINS}" != "" ]; then 289 | _can_fix="1" 290 | for _bin in ${REQUIRED_FIX_BINS}; do 291 | if ! command -v "${_bin}" >/dev/null 2>&1; then 292 | echo "${_bin}: Not found." 293 | _can_fix="0}" 294 | fi 295 | done 296 | if [ "${_can_fix}" = "1" ]; then 297 | echo "\$ ${MY_FIX_INFO}" 298 | eval "${MY_FIX_INFO}" 299 | echo 300 | else 301 | echo "Unable to use --fix" 302 | echo 303 | return 0 304 | fi 305 | fi 306 | } 307 | 308 | 309 | check_requirements() { 310 | _debug="${1}" 311 | _ret1=0 312 | _ret2=0 313 | 314 | # System binaries 315 | for _bin in ${REQUIRED_BINS}; do 316 | if ! command -v "${_bin}" >/dev/null 2>&1; then 317 | echo "[ERR] Required sys binary '${_bin}' not found." 318 | _ret1=1 319 | else 320 | if [ "${_debug}" = "1" ]; then 321 | echo "[OK] Required system binary '${_bin}' found." 322 | fi 323 | fi 324 | done 325 | 326 | # Specific binaries for this check 327 | for _bin in ${REQUIRED_CUST_BINS}; do 328 | if ! command -v "${_bin}" >/dev/null 2>&1; then 329 | echo "[ERR] Required custom binary '${_bin}' not found." 330 | _ret2=1 331 | else 332 | if [ "${_debug}" = "1" ]; then 333 | echo "[OK] Required custom binary '${_bin}' found." 334 | fi 335 | fi 336 | done 337 | 338 | # Binaries required to fix 339 | if [ "${ENABLE_FIX}" = "1" ] && [ "${MY_FIX}" = "1" ]; then 340 | for _bin in ${REQUIRED_FIX_BINS}; do 341 | if ! command -v "${_bin}" >/dev/null 2>&1; then 342 | echo "[ERR] Required --fix binary '${_bin}' not found." 343 | _ret2=1 344 | else 345 | if [ "${_debug}" = "1" ]; then 346 | echo "[OK] Required --fix binary '${_bin}' found." 347 | fi 348 | fi 349 | done 350 | fi 351 | 352 | 353 | return $((_ret1 + _ret2)) 354 | } 355 | 356 | check_config_file() { 357 | _config="${1}" 358 | 359 | # Check config file 360 | if [ ! -f "${_config}" ]; then 361 | echo "[CONFIG] Config file not found: ${_config}" 362 | return 1 363 | fi 364 | 365 | # Check directives 366 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=" "${_config}"; then 367 | echo "[CONFIG] ${MY_CONF_PRE}IGNORE variable not found in config." 368 | return 1 369 | fi 370 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=[\"']{1}.*[\"']{1}$" "${_config}"; then 371 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}IGNORE variable." 372 | return 1 373 | fi 374 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=" "${_config}"; then 375 | echo "[CONFIG] ${MY_CONF_PRE}EXTENSION variable not found in config." 376 | return 1 377 | fi 378 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=[\"']{1}.*[\"']{1}$" "${_config}"; then 379 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}EXTENSION variable." 380 | return 1 381 | fi 382 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=" "${_config}"; then 383 | echo "[CONFIG] ${MY_CONF_PRE}TEXT variable not found in config." 384 | return 1 385 | fi 386 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=[\"']*[01]{1}[\"']*$" "${_config}"; then 387 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}TEXT variable." 388 | return 1 389 | fi 390 | 391 | # Check optional directives 392 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 393 | if ! grep -Eq "^${MY_CONF_PRE}CUSTOM=[\"']{1}.*[\"']{1}$" "${_config}"; then 394 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}CUSTOM variable." 395 | return 1 396 | fi 397 | fi 398 | 399 | } 400 | 401 | 402 | # 403 | # System independent method 404 | # to get number of CPU cores. 405 | # (defaults to 1 if impossible) 406 | # 407 | num_cpu() { 408 | if ! _num="$( getconf _NPROCESSORS_ONLN 2>/dev/null )"; then 409 | echo "1" 410 | else 411 | echo "${_num}" 412 | fi 413 | } 414 | 415 | 416 | # 417 | # sed wrapper that automatically escapes 418 | # regex literals 419 | # 420 | mysed() { 421 | _input="$1" 422 | _search="$2" 423 | _replace="$3" 424 | 425 | echo "${_input}" | sed "s/$(echo "${_search}" | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo "${_replace}" | sed -e 's/[\/&]/\\&/g')/g" 426 | } 427 | 428 | 429 | 430 | 431 | ################################################################################ 432 | # 433 | # M A I N E N T R Y P O I N T 434 | # 435 | ################################################################################ 436 | 437 | 438 | 439 | ############################################################ 440 | # Command Line arguments 441 | ############################################################ 442 | 443 | 444 | # 445 | # Read command line arguments 446 | # 447 | while [ $# -gt 0 ]; do 448 | case "${1}" in 449 | 450 | # ---------------------------------------- 451 | --path=*) 452 | MY_PATH="${1//--path=/}" 453 | ;; 454 | 455 | # ---------------------------------------- 456 | --shebang=*) 457 | MY_SHE="${1//--shebang=/}" 458 | ;; 459 | 460 | # ---------------------------------------- 461 | --extension=*) 462 | MY_EXT="${1//--extension=/}" 463 | ;; 464 | 465 | # ---------------------------------------- 466 | --ignore=*) 467 | MY_IGN="${1//--ignore=/}" 468 | ;; 469 | 470 | # ---------------------------------------- 471 | --config=*) 472 | MY_CFG="${1//--config=/}" 473 | ;; 474 | 475 | # ---------------------------------------- 476 | --confpre=*) 477 | MY_CONF_PRE="${1//--confpre=/}" 478 | ;; 479 | 480 | # ---------------------------------------- 481 | --custom=*) 482 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 483 | MY_CUS="${1//--custom=/}" 484 | else 485 | echo "Invalid argument: ${1}" 486 | echo "Type '${MY_NAME} --help' for available options." 487 | exit 1 488 | fi 489 | ;; 490 | 491 | # ---------------------------------------- 492 | --fix) 493 | if [ "${ENABLE_FIX}" = "1" ]; then 494 | MY_FIX=1 495 | else 496 | echo "Invalid argument: ${1}" 497 | echo "Type '${MY_NAME} --help' for available options." 498 | exit 1 499 | fi 500 | ;; 501 | 502 | 503 | # ---------------------------------------- 504 | --text) 505 | MY_TXT=1 506 | ;; 507 | 508 | # ---------------------------------------- 509 | --size) 510 | MY_SIZ=1 511 | ;; 512 | 513 | # ---------------------------------------- 514 | --dry) 515 | MY_DRY=1 516 | ;; 517 | 518 | # ---------------------------------------- 519 | --list) 520 | MY_LST=1 521 | ;; 522 | 523 | # ---------------------------------------- 524 | --verbose) 525 | MY_VER=1 526 | ;; 527 | 528 | # ---------------------------------------- 529 | --debug) 530 | MY_DEB=1 531 | ;; 532 | 533 | # ---------------------------------------- 534 | --info) 535 | if ! check_requirements "${MY_DEB}"; then 536 | exit 1 537 | fi 538 | 539 | if ! print_info; then 540 | exit 1 541 | fi 542 | 543 | exit 0 544 | ;; 545 | 546 | # ---------------------------------------- 547 | --help) 548 | print_usage 549 | exit 0 550 | ;; 551 | 552 | # ---------------------------------------- 553 | --version) 554 | print_version 555 | exit 0 556 | ;; 557 | 558 | # ---------------------------------------- 559 | *) 560 | echo "Invalid argument: ${1}" 561 | echo "Type '${MY_NAME} --help' for available options." 562 | exit 1 563 | ;; 564 | esac 565 | shift 566 | done 567 | 568 | 569 | 570 | ############################################################ 571 | # Sanity Checks 572 | ############################################################ 573 | 574 | # 575 | # Check general requirements 576 | # 577 | if ! check_requirements "${MY_DEB}"; then 578 | exit 1 579 | fi 580 | 581 | # 582 | # Check path 583 | # 584 | if [ "${MY_PATH}" = "" ]; then 585 | echo "--path not specified" 586 | echo "Type '${MY_NAME} --help' for available options." 587 | exit 1 588 | fi 589 | if [ ! -e "${MY_PATH}" ]; then 590 | echo "Specified path does not exist: '${MY_PATH}'." 591 | echo "Type '${MY_NAME} --help' for available options." 592 | exit 1 593 | fi 594 | 595 | 596 | # 597 | # Check and load config if desired 598 | # 599 | if [ "${MY_CFG}" != "" ]; then 600 | if ! check_config_file "${MY_CFG}"; then 601 | exit 1 602 | fi 603 | 604 | . "${MY_CFG}" 605 | fi 606 | 607 | 608 | 609 | ############################################################ 610 | # Evaluate Settings 611 | ############################################################ 612 | 613 | CPU_CORES="$(num_cpu)" 614 | 615 | 616 | # Var substitutions for config file directives 617 | # to match current program. 618 | EXTENSION="${MY_CONF_PRE}EXTENSION" 619 | IGNORE="${MY_CONF_PRE}IGNORE" 620 | TEXT="${MY_CONF_PRE}TEXT" 621 | SIZE="${MY_CONF_PRE}SIZE" 622 | CUSTOM="${MY_CONF_PRE}CUSTOM" 623 | 624 | # 625 | # Decide on Shebang 626 | # 627 | if [ "${MY_SHE}" != "" ]; then 628 | MY_SHE="xargs -0 -P ${CPU_CORES} -n1 awk '/^#!.*(\/${MY_SHE}|[[:space:]]+${MY_SHE})/{print FILENAME}'" 629 | else 630 | MY_SHE="" 631 | fi 632 | 633 | 634 | 635 | # 636 | # Decide on File extensions 637 | # 638 | if [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" != "0" ]; then 639 | if [ "${MY_DEB}" = "1" ]; then 640 | echo "[ARG] Cmd arg --extension=${MY_EXT} will take precedence over config file value". 641 | fi 642 | MY_EXT="${MY_EXT}" 643 | 644 | elif [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" = "0" ]; then 645 | if [ "${MY_DEB}" = "1" ]; then 646 | echo "[ARG] Using config file values: ext: ${!EXTENSION}" 647 | fi 648 | MY_EXT="${!EXTENSION}" 649 | 650 | elif [ "${MY_CFG}" = "" ] && [ "${MY_EXT}" != "0" ]; then 651 | if [ "${MY_DEB}" = "1" ]; then 652 | echo "[ARG] Using cmd argument: ext: '${MY_EXT}'" 653 | fi 654 | MY_EXT="${MY_EXT}" 655 | 656 | else 657 | if [ "${MY_DEB}" = "1" ]; then 658 | echo "[ARG] Using all file extensions" 659 | fi 660 | MY_EXT= 661 | fi 662 | 663 | 664 | # 665 | # Decide on ignore paths 666 | # 667 | if [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" != "" ]; then 668 | if [ "${MY_DEB}" = "1" ]; then 669 | echo "[ARG] Cmd arg --ignore=${MY_IGN} will take precedence over config file value". 670 | fi 671 | MY_IGN="${MY_IGN}" 672 | 673 | elif [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" = "" ]; then 674 | if [ "${MY_DEB}" = "1" ]; then 675 | echo "[ARG] Using config file values: ignore: ${!IGNORE}" 676 | fi 677 | MY_IGN="${!IGNORE}" 678 | 679 | elif [ "${MY_CFG}" = "" ] && [ "${MY_IGN}" != "" ]; then 680 | if [ "${MY_DEB}" = "1" ]; then 681 | echo "[ARG] Using cmd argument: ignore: ${MY_IGN}" 682 | fi 683 | MY_IGN="${MY_IGN}" 684 | 685 | else 686 | if [ "${MY_DEB}" = "1" ]; then 687 | echo "[ARG] Not ignoring anything" 688 | fi 689 | MY_IGN= 690 | fi 691 | 692 | 693 | # 694 | # Decide on text files (non-binary) or all files 695 | # 696 | if [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" != "0" ]; then 697 | if [ "${MY_DEB}" = "1" ]; then 698 | echo "[ARG] Cmd arg --text: '${MY_TXT}' will take precedence over config file value". 699 | fi 700 | MY_TXT="${MY_TXT}" 701 | 702 | elif [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" = "0" ]; then 703 | if [ "${MY_DEB}" = "1" ]; then 704 | echo "[ARG] Using config file values: --text: ${!TEXT}" 705 | fi 706 | MY_TXT="${!TEXT}" 707 | 708 | elif [ "${MY_CFG}" = "" ] && [ "${MY_TXT}" != "0" ]; then 709 | if [ "${MY_DEB}" = "1" ]; then 710 | echo "[ARG] Using cmd argument: --text: ${MY_TXT}" 711 | fi 712 | MY_TXT="${MY_TXT}" 713 | 714 | else 715 | if [ "${MY_DEB}" = "1" ]; then 716 | echo "[ARG] Not narrowing down by text files" 717 | fi 718 | MY_TXT="0" 719 | fi 720 | 721 | 722 | # 723 | # Decide on file size 724 | # 725 | if [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" != "0" ]; then 726 | if [ "${MY_DEB}" = "1" ]; then 727 | echo "[ARG] Cmd arg --size: '${MY_SIZ}' will take precedence over config file value". 728 | fi 729 | MY_SIZ="${MY_SIZ}" 730 | 731 | elif [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" = "0" ]; then 732 | if [ "${MY_DEB}" = "1" ]; then 733 | echo "[ARG] Using config file values: --size: ${!SIZE}" 734 | fi 735 | MY_SIZ="${!SIZE}" 736 | 737 | elif [ "${MY_CFG}" = "" ] && [ "${MY_SIZ}" != "0" ]; then 738 | if [ "${MY_DEB}" = "1" ]; then 739 | echo "[ARG] Using cmd argument: --size: ${MY_SIZ}" 740 | fi 741 | MY_SIZ="${MY_SIZ}" 742 | 743 | else 744 | if [ "${MY_DEB}" = "1" ]; then 745 | echo "[ARG] Not narrowing down by size > 0 bytes" 746 | fi 747 | MY_SIZ="0" 748 | fi 749 | 750 | if [ "${MY_SIZ}" = "1" ]; then 751 | MY_SIZ="! -size 0" 752 | else 753 | MY_SIZ="" 754 | fi 755 | 756 | 757 | 758 | # 759 | # Decide on Custom string 760 | # 761 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 762 | if [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" != "" ]; then 763 | if [ "${MY_DEB}" = "1" ]; then 764 | echo "[ARG] Cmd arg --custom=\"${MY_CUS}\" will take precedence over config file value". 765 | fi 766 | MY_CUS="${MY_CUS}" 767 | 768 | elif [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" = "" ]; then 769 | if [ "${MY_DEB}" = "1" ]; then 770 | echo "[ARG] Using config file values: custom: \"${!CUSTOM}\"" 771 | fi 772 | MY_CUS="${!CUSTOM}" 773 | 774 | elif [ "${MY_CFG}" = "" ] && [ "${MY_CUS}" != "" ]; then 775 | if [ "${MY_DEB}" = "1" ]; then 776 | echo "[ARG] Using cmd argument: custom: \"${MY_CUS}\"" 777 | fi 778 | MY_CUS="${MY_CUS}" 779 | 780 | else 781 | if [ "${MY_DEB}" = "1" ]; then 782 | echo "[ARG] No customization applied" 783 | fi 784 | MY_CUS= 785 | fi 786 | fi 787 | 788 | 789 | 790 | ############################################################ 791 | # Build command 792 | ############################################################ 793 | 794 | # 795 | # 'find' pattern for file extensions 796 | # 797 | if [ "${MY_EXT}" != "" ]; then 798 | NAME_PATTERN="\( -iname \*.${MY_EXT//,/ -o -iname \\*.} \)" 799 | else 800 | NAME_PATTERN="" 801 | fi 802 | 803 | # 804 | # 'find' pattern for ignores/excludes 805 | # 806 | if [ "${MY_IGN}" != "" ]; then 807 | EXCL_PATTERN="-not \( -path \"${MY_PATH}/${MY_IGN//,/*\" -o -path \"${MY_PATH}\/}*\" \)" 808 | else 809 | EXCL_PATTERN="" 810 | fi 811 | 812 | 813 | # 814 | # Fix? 815 | # 816 | if [ "${MY_FIX}" = "1" ]; then 817 | MY_CHECK="${MY_FIX_CMD}" 818 | else 819 | # 820 | # Normal check 821 | # (Apply custom command?) 822 | # 823 | if [ "${MY_CUS}" = "" ]; then 824 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${DEFAULT_CUST_OPS}" )" 825 | else 826 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${MY_CUS}" )" 827 | fi 828 | fi 829 | 830 | 831 | # 832 | # Show files or grep in found files? 833 | # 834 | 835 | 836 | # Be verbose? 837 | if [ "${MY_VER}" = "1" ]; then 838 | XARGS_VERBOSE="-t" 839 | else 840 | XARGS_VERBOSE="" 841 | fi 842 | 843 | # 844 | # Build command 845 | # 846 | 847 | 848 | ### Text files (list-only) 849 | if [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "1" ]; then 850 | if [ "${MY_SHE}" != "" ]; then 851 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE}" 852 | else 853 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il ''" 854 | fi 855 | 856 | ### Text files (run!!!) 857 | elif [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "0" ]; then 858 | if [ "${MY_SHE}" != "" ]; then 859 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 860 | else 861 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 862 | fi 863 | 864 | ### All files (list-only) 865 | elif [ "${MY_TXT}" = "0" ] && [ "${MY_LST}" = "1" ]; then 866 | if [ "${MY_SHE}" != "" ]; then 867 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE}" 868 | else 869 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print" 870 | fi 871 | 872 | 873 | ### All files (run!!!) 874 | else 875 | if [ "${MY_SHE}" != "" ]; then 876 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 877 | else 878 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 879 | fi 880 | 881 | fi 882 | 883 | 884 | 885 | 886 | ############################################################ 887 | # Execute 888 | ############################################################ 889 | 890 | # Dry mode? 891 | if [ "${MY_DRY}" = "1" ]; then 892 | printf "%s\n" "${MY_CMD}" 893 | exit 0 894 | fi 895 | 896 | printf "\$ %s\n" "${MY_CMD}" 897 | 898 | output="$(eval "${MY_CMD}")" 899 | 900 | # If showing files only, exit normally 901 | if [ "${MY_LST}" = "1" ]; then 902 | printf "%s\n" "${output}" 903 | exit 0 904 | fi 905 | 906 | 907 | if [ "${output}" != "" ]; then 908 | printf "%s\n" "${output}" 909 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 910 | exit 1 911 | else 912 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 913 | exit 0 914 | fi 915 | -------------------------------------------------------------------------------- /bin/syntax-json: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="syntax-json" 10 | MY_DESC="Scans recursively for files containing JSON syntax errors." 11 | MY_FINISH_OK="No files with JSON syntax errors found." 12 | MY_FINISH_ERR="Found files with JSON syntax errors." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="SYNTAX_JSON_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="jsonlint" 19 | 20 | # Binaries required for fixing 21 | REQUIRED_FIX_BINS="" 22 | 23 | # Enable custom options (cmd arguments) 24 | # that can be parsed to the actual check binary? 25 | ENABLE_CUST_OPS=1 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="-c -q" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="jsonlint __CUSTOM_OPT_PLACEHOLDER__ \"\$1\" 2>&1 || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="jsonlint --version" 49 | 50 | 51 | 52 | 53 | 54 | 55 | ############################################################ 56 | # Do not edit from here 57 | ############################################################ 58 | 59 | # 60 | # Version 61 | # 62 | MY_VERSION="0.15" 63 | MY_DATE="2018-04-09" 64 | 65 | # 66 | # Credits 67 | # 68 | MY_AUTHOR="cytopia" 69 | MY_EMAIL="cytopia@everythingcli.org" 70 | 71 | # 72 | # Required system binaries 73 | # 74 | REQUIRED_BINS="awk grep find sed tr xargs" 75 | 76 | # 77 | # Variables populated by cmd args or config file 78 | # 79 | MY_PATH= 80 | MY_SHE= 81 | MY_EXT=0 82 | MY_IGN= 83 | MY_TXT=0 84 | MY_SIZ=0 85 | MY_DRY=0 86 | MY_LST=0 87 | MY_VER=0 88 | MY_DEB=0 89 | MY_FIX=0 90 | MY_CFG= 91 | MY_CUS= 92 | 93 | CLR_SUC="\033[0;32m" 94 | CLR_ERR="\033[0;31m" 95 | CLR_CLS="\033[0m" 96 | 97 | ################################################################################ 98 | # 99 | # F U N C T I O N S 100 | # 101 | ################################################################################ 102 | 103 | 104 | 105 | print_usage() { 106 | 107 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 108 | _custom=" [--custom=\"opts\"]" 109 | else 110 | _custom="" 111 | fi 112 | 113 | if [ "${ENABLE_FIX}" = "1" ];then 114 | _fix=" [--fix]" 115 | else 116 | _fix="" 117 | fi 118 | 119 | echo "Usage: ${MY_NAME} [--text] [--size] [--shebang=php] [--extension=tpl,htm,html,php,...] [--ignore=dir1,dir2] [--config=conf] [--confpre=${MY_CONF_PRE}]${_custom}${_fix} [--verbose] [--debug] [--dry] [--list] --path=dir" 120 | echo " ${MY_NAME} --info" 121 | echo " ${MY_NAME} --help" 122 | echo " ${MY_NAME} --version" 123 | echo 124 | echo "${MY_DESC}" 125 | echo "Will return 1 on occurance, otherwise 0." 126 | echo 127 | echo "Required arguments:" 128 | echo 129 | echo " --path= Specify directory where to scan." 130 | echo 131 | echo 132 | echo "Optional run arguments:" 133 | if [ "${ENABLE_FIX}" = "1" ];then 134 | echo " --fix Fixable :-)" 135 | echo " Fix the problems for the specified files." 136 | echo " Note, all other options below also apply" 137 | echo 138 | fi 139 | echo " --text Limit search to text files only (non-binary)." 140 | echo " Can be narrowed further with '--extension'" 141 | echo 142 | echo " --size Limit search to files which are not empty (bigger than 0 bytes)." 143 | echo 144 | echo " --shebang= Only find files (shell scripts) with this specific shebang." 145 | echo " It is useful to combine this with --text and --size for faster searches." 146 | echo " Use with --dry to see how this search command is generated." 147 | echo " Example:" 148 | echo " --shebang=bash" 149 | echo " --shebang=php" 150 | echo " --shebang=sh" 151 | echo 152 | echo " --extension= Only find files matching those extensions." 153 | echo " Comma separated list of file extensions." 154 | echo " Only find files matching those extensions." 155 | echo " Defaults to all files if not specified or empty." 156 | echo " Example:" 157 | echo " --extension=html,php,inc" 158 | echo " --extension=php" 159 | echo 160 | echo " --ignore= Comma separated list of ignore paths." 161 | echo " Directories must be specified from the starting location of --path." 162 | echo " Example:" 163 | echo " ignore 'foor/bar' folder inside '/var/www' path:" 164 | echo " --path=/var/www --ignore=foo/bar" 165 | echo 166 | echo " --config= Load configuration file." 167 | echo " File must contain the following directives:" 168 | echo " ${MY_CONF_PRE}EXTENSION=\"\" # comma separated" 169 | echo " ${MY_CONF_PRE}IGNORE=\"\" # comma separated" 170 | echo " ${MY_CONF_PRE}TEXT=0|1 # 0 or 1" 171 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 172 | echo " ${MY_CONF_PRE}CUSTOM=\"\" # custom command" 173 | fi 174 | echo " Note that cmd arguments take precedence over" 175 | echo " config file settings." 176 | echo 177 | echo " --confpre= Set custom configuration directive prefix." 178 | echo " Current default ist: '${MY_CONF_PRE}'." 179 | echo " This is useful, when you want to define different defaults" 180 | echo " per check via configuration file." 181 | echo 182 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 183 | echo " --custom= Parse custom command line option to the check binary." 184 | echo " Note that when you want to add config files or other files" 185 | echo " you must use an absolute path." 186 | echo 187 | echo " Current custom command:" 188 | echo " --custom=\"${DEFAULT_CUST_OPS//\"/\\\"}\"" # \" -> \\\" 189 | echo 190 | echo " Overwrite example:" 191 | echo " --custom=\"--color --config /absoulte/path/conf.json\"" 192 | echo 193 | fi 194 | echo " --verbose Be verbose and print commands and files being checked." 195 | echo 196 | echo 197 | echo " --debug Print system messages." 198 | echo 199 | echo 200 | echo "Optional training arguments:" 201 | echo " --dry Don't do anything, just display the commands." 202 | echo 203 | echo " --list Instead of searching inside the files, just display the filenames" 204 | echo " that would be found by --path, --extension and --ignore" 205 | echo 206 | echo 207 | echo "System arguments:" 208 | echo " --info Show versions of required commands (useful for bugreports)." 209 | echo " --help Show help screen." 210 | echo " --version Show version information." 211 | echo 212 | echo 213 | echo "${MY_NAME} is part of the awesome-ci collection." 214 | echo "https://github.com/cytopia/awesome-ci" 215 | } 216 | 217 | print_version() { 218 | echo "tool: ${MY_NAME}" 219 | echo "version: v${MY_VERSION} (${MY_DATE})" 220 | echo "author: ${MY_AUTHOR}" 221 | echo "email: ${MY_EMAIL}" 222 | echo 223 | echo "${MY_NAME} is part of the awesome-ci collection." 224 | echo "https://github.com/cytopia/awesome-ci" 225 | } 226 | 227 | print_info() { 228 | 229 | # 230 | # Required binaries 231 | # 232 | 233 | if ! echo "${MY_INFO}" | grep -cqE "^bash"; then 234 | MY_CMD_VERSION="bash --version | grep -E '(([0-9]+)(\.))+'" 235 | echo "\$ ${MY_CMD_VERSION}" 236 | eval "${MY_CMD_VERSION}" 237 | echo 238 | fi 239 | if ! echo "${MY_INFO}" | grep -cqE "^\(awk"; then 240 | MY_CMD_VERSION="(awk -Wversion 2>/dev/null || awk --version) | grep -E '(([0-9]+)(\.))+'" 241 | echo "\$ ${MY_CMD_VERSION}" 242 | eval "${MY_CMD_VERSION}" 243 | echo 244 | fi 245 | if ! echo "${MY_INFO}" | grep -cqE "^grep"; then 246 | MY_CMD_VERSION="grep -V | grep -E '([0-9]+\.+)+'" 247 | echo "\$ ${MY_CMD_VERSION}" 248 | eval "${MY_CMD_VERSION}" 249 | echo 250 | fi 251 | if ! echo "${MY_INFO}" | grep -cqE "^\(find"; then 252 | MY_CMD_VERSION="(find --version >/dev/null 2>&1) && (find --version 2>&1 | head -1) || (echo 'find (BSD find)')" 253 | echo "\$ ${MY_CMD_VERSION}" 254 | eval "${MY_CMD_VERSION}" 255 | echo 256 | fi 257 | if ! echo "${MY_INFO}" | grep -cqE "^\(sed"; then 258 | MY_CMD_VERSION="(sed --version >/dev/null 2>&1) && (sed --version 2>&1 | head -1) || (echo 'sed (BSD sed)')" 259 | echo "\$ ${MY_CMD_VERSION}" 260 | eval "${MY_CMD_VERSION}" 261 | echo 262 | fi 263 | if ! echo "${MY_INFO}" | grep -cqE "^\(tr"; then 264 | MY_CMD_VERSION="(tr --version >/dev/null 2>&1) && (tr --version 2>&1 | head -1) || (echo 'tr (BSD tr)')" 265 | echo "\$ ${MY_CMD_VERSION}" 266 | eval "${MY_CMD_VERSION}" 267 | echo 268 | fi 269 | if ! echo "${MY_INFO}" | grep -cqE "^\(xargs"; then 270 | MY_CMD_VERSION="(xargs --version >/dev/null 2>&1) && (xargs --version 2>&1 | head -1) || (echo 'xargs (BSD xargs)')" 271 | echo "\$ ${MY_CMD_VERSION}" 272 | eval "${MY_CMD_VERSION}" 273 | echo 274 | fi 275 | 276 | # 277 | # Custom binary 278 | # 279 | if [ "${MY_INFO}" != "" ]; then 280 | echo "\$ ${MY_INFO}" 281 | eval "${MY_INFO}" 282 | echo 283 | fi 284 | 285 | # 286 | # --fix binary 287 | # 288 | if [ "${ENABLE_FIX}" = "1" ] && [ "${REQUIRED_FIX_BINS}" != "" ]; then 289 | _can_fix="1" 290 | for _bin in ${REQUIRED_FIX_BINS}; do 291 | if ! command -v "${_bin}" >/dev/null 2>&1; then 292 | echo "${_bin}: Not found." 293 | _can_fix="0}" 294 | fi 295 | done 296 | if [ "${_can_fix}" = "1" ]; then 297 | echo "\$ ${MY_FIX_INFO}" 298 | eval "${MY_FIX_INFO}" 299 | echo 300 | else 301 | echo "Unable to use --fix" 302 | echo 303 | return 0 304 | fi 305 | fi 306 | } 307 | 308 | 309 | check_requirements() { 310 | _debug="${1}" 311 | _ret1=0 312 | _ret2=0 313 | 314 | # System binaries 315 | for _bin in ${REQUIRED_BINS}; do 316 | if ! command -v "${_bin}" >/dev/null 2>&1; then 317 | echo "[ERR] Required sys binary '${_bin}' not found." 318 | _ret1=1 319 | else 320 | if [ "${_debug}" = "1" ]; then 321 | echo "[OK] Required system binary '${_bin}' found." 322 | fi 323 | fi 324 | done 325 | 326 | # Specific binaries for this check 327 | for _bin in ${REQUIRED_CUST_BINS}; do 328 | if ! command -v "${_bin}" >/dev/null 2>&1; then 329 | echo "[ERR] Required custom binary '${_bin}' not found." 330 | _ret2=1 331 | else 332 | if [ "${_debug}" = "1" ]; then 333 | echo "[OK] Required custom binary '${_bin}' found." 334 | fi 335 | fi 336 | done 337 | 338 | # Binaries required to fix 339 | if [ "${ENABLE_FIX}" = "1" ] && [ "${MY_FIX}" = "1" ]; then 340 | for _bin in ${REQUIRED_FIX_BINS}; do 341 | if ! command -v "${_bin}" >/dev/null 2>&1; then 342 | echo "[ERR] Required --fix binary '${_bin}' not found." 343 | _ret2=1 344 | else 345 | if [ "${_debug}" = "1" ]; then 346 | echo "[OK] Required --fix binary '${_bin}' found." 347 | fi 348 | fi 349 | done 350 | fi 351 | 352 | 353 | return $((_ret1 + _ret2)) 354 | } 355 | 356 | check_config_file() { 357 | _config="${1}" 358 | 359 | # Check config file 360 | if [ ! -f "${_config}" ]; then 361 | echo "[CONFIG] Config file not found: ${_config}" 362 | return 1 363 | fi 364 | 365 | # Check directives 366 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=" "${_config}"; then 367 | echo "[CONFIG] ${MY_CONF_PRE}IGNORE variable not found in config." 368 | return 1 369 | fi 370 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=[\"']{1}.*[\"']{1}$" "${_config}"; then 371 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}IGNORE variable." 372 | return 1 373 | fi 374 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=" "${_config}"; then 375 | echo "[CONFIG] ${MY_CONF_PRE}EXTENSION variable not found in config." 376 | return 1 377 | fi 378 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=[\"']{1}.*[\"']{1}$" "${_config}"; then 379 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}EXTENSION variable." 380 | return 1 381 | fi 382 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=" "${_config}"; then 383 | echo "[CONFIG] ${MY_CONF_PRE}TEXT variable not found in config." 384 | return 1 385 | fi 386 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=[\"']*[01]{1}[\"']*$" "${_config}"; then 387 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}TEXT variable." 388 | return 1 389 | fi 390 | 391 | # Check optional directives 392 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 393 | if ! grep -Eq "^${MY_CONF_PRE}CUSTOM=[\"']{1}.*[\"']{1}$" "${_config}"; then 394 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}CUSTOM variable." 395 | return 1 396 | fi 397 | fi 398 | 399 | } 400 | 401 | 402 | # 403 | # System independent method 404 | # to get number of CPU cores. 405 | # (defaults to 1 if impossible) 406 | # 407 | num_cpu() { 408 | if ! _num="$( getconf _NPROCESSORS_ONLN 2>/dev/null )"; then 409 | echo "1" 410 | else 411 | echo "${_num}" 412 | fi 413 | } 414 | 415 | 416 | # 417 | # sed wrapper that automatically escapes 418 | # regex literals 419 | # 420 | mysed() { 421 | _input="$1" 422 | _search="$2" 423 | _replace="$3" 424 | 425 | echo "${_input}" | sed "s/$(echo "${_search}" | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo "${_replace}" | sed -e 's/[\/&]/\\&/g')/g" 426 | } 427 | 428 | 429 | 430 | 431 | ################################################################################ 432 | # 433 | # M A I N E N T R Y P O I N T 434 | # 435 | ################################################################################ 436 | 437 | 438 | 439 | ############################################################ 440 | # Command Line arguments 441 | ############################################################ 442 | 443 | 444 | # 445 | # Read command line arguments 446 | # 447 | while [ $# -gt 0 ]; do 448 | case "${1}" in 449 | 450 | # ---------------------------------------- 451 | --path=*) 452 | MY_PATH="${1//--path=/}" 453 | ;; 454 | 455 | # ---------------------------------------- 456 | --shebang=*) 457 | MY_SHE="${1//--shebang=/}" 458 | ;; 459 | 460 | # ---------------------------------------- 461 | --extension=*) 462 | MY_EXT="${1//--extension=/}" 463 | ;; 464 | 465 | # ---------------------------------------- 466 | --ignore=*) 467 | MY_IGN="${1//--ignore=/}" 468 | ;; 469 | 470 | # ---------------------------------------- 471 | --config=*) 472 | MY_CFG="${1//--config=/}" 473 | ;; 474 | 475 | # ---------------------------------------- 476 | --confpre=*) 477 | MY_CONF_PRE="${1//--confpre=/}" 478 | ;; 479 | 480 | # ---------------------------------------- 481 | --custom=*) 482 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 483 | MY_CUS="${1//--custom=/}" 484 | else 485 | echo "Invalid argument: ${1}" 486 | echo "Type '${MY_NAME} --help' for available options." 487 | exit 1 488 | fi 489 | ;; 490 | 491 | # ---------------------------------------- 492 | --fix) 493 | if [ "${ENABLE_FIX}" = "1" ]; then 494 | MY_FIX=1 495 | else 496 | echo "Invalid argument: ${1}" 497 | echo "Type '${MY_NAME} --help' for available options." 498 | exit 1 499 | fi 500 | ;; 501 | 502 | 503 | # ---------------------------------------- 504 | --text) 505 | MY_TXT=1 506 | ;; 507 | 508 | # ---------------------------------------- 509 | --size) 510 | MY_SIZ=1 511 | ;; 512 | 513 | # ---------------------------------------- 514 | --dry) 515 | MY_DRY=1 516 | ;; 517 | 518 | # ---------------------------------------- 519 | --list) 520 | MY_LST=1 521 | ;; 522 | 523 | # ---------------------------------------- 524 | --verbose) 525 | MY_VER=1 526 | ;; 527 | 528 | # ---------------------------------------- 529 | --debug) 530 | MY_DEB=1 531 | ;; 532 | 533 | # ---------------------------------------- 534 | --info) 535 | if ! check_requirements "${MY_DEB}"; then 536 | exit 1 537 | fi 538 | 539 | if ! print_info; then 540 | exit 1 541 | fi 542 | 543 | exit 0 544 | ;; 545 | 546 | # ---------------------------------------- 547 | --help) 548 | print_usage 549 | exit 0 550 | ;; 551 | 552 | # ---------------------------------------- 553 | --version) 554 | print_version 555 | exit 0 556 | ;; 557 | 558 | # ---------------------------------------- 559 | *) 560 | echo "Invalid argument: ${1}" 561 | echo "Type '${MY_NAME} --help' for available options." 562 | exit 1 563 | ;; 564 | esac 565 | shift 566 | done 567 | 568 | 569 | 570 | ############################################################ 571 | # Sanity Checks 572 | ############################################################ 573 | 574 | # 575 | # Check general requirements 576 | # 577 | if ! check_requirements "${MY_DEB}"; then 578 | exit 1 579 | fi 580 | 581 | # 582 | # Check path 583 | # 584 | if [ "${MY_PATH}" = "" ]; then 585 | echo "--path not specified" 586 | echo "Type '${MY_NAME} --help' for available options." 587 | exit 1 588 | fi 589 | if [ ! -e "${MY_PATH}" ]; then 590 | echo "Specified path does not exist: '${MY_PATH}'." 591 | echo "Type '${MY_NAME} --help' for available options." 592 | exit 1 593 | fi 594 | 595 | 596 | # 597 | # Check and load config if desired 598 | # 599 | if [ "${MY_CFG}" != "" ]; then 600 | if ! check_config_file "${MY_CFG}"; then 601 | exit 1 602 | fi 603 | 604 | . "${MY_CFG}" 605 | fi 606 | 607 | 608 | 609 | ############################################################ 610 | # Evaluate Settings 611 | ############################################################ 612 | 613 | CPU_CORES="$(num_cpu)" 614 | 615 | 616 | # Var substitutions for config file directives 617 | # to match current program. 618 | EXTENSION="${MY_CONF_PRE}EXTENSION" 619 | IGNORE="${MY_CONF_PRE}IGNORE" 620 | TEXT="${MY_CONF_PRE}TEXT" 621 | SIZE="${MY_CONF_PRE}SIZE" 622 | CUSTOM="${MY_CONF_PRE}CUSTOM" 623 | 624 | # 625 | # Decide on Shebang 626 | # 627 | if [ "${MY_SHE}" != "" ]; then 628 | MY_SHE="xargs -0 -P ${CPU_CORES} -n1 awk '/^#!.*(\/${MY_SHE}|[[:space:]]+${MY_SHE})/{print FILENAME}'" 629 | else 630 | MY_SHE="" 631 | fi 632 | 633 | 634 | 635 | # 636 | # Decide on File extensions 637 | # 638 | if [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" != "0" ]; then 639 | if [ "${MY_DEB}" = "1" ]; then 640 | echo "[ARG] Cmd arg --extension=${MY_EXT} will take precedence over config file value". 641 | fi 642 | MY_EXT="${MY_EXT}" 643 | 644 | elif [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" = "0" ]; then 645 | if [ "${MY_DEB}" = "1" ]; then 646 | echo "[ARG] Using config file values: ext: ${!EXTENSION}" 647 | fi 648 | MY_EXT="${!EXTENSION}" 649 | 650 | elif [ "${MY_CFG}" = "" ] && [ "${MY_EXT}" != "0" ]; then 651 | if [ "${MY_DEB}" = "1" ]; then 652 | echo "[ARG] Using cmd argument: ext: '${MY_EXT}'" 653 | fi 654 | MY_EXT="${MY_EXT}" 655 | 656 | else 657 | if [ "${MY_DEB}" = "1" ]; then 658 | echo "[ARG] Using all file extensions" 659 | fi 660 | MY_EXT= 661 | fi 662 | 663 | 664 | # 665 | # Decide on ignore paths 666 | # 667 | if [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" != "" ]; then 668 | if [ "${MY_DEB}" = "1" ]; then 669 | echo "[ARG] Cmd arg --ignore=${MY_IGN} will take precedence over config file value". 670 | fi 671 | MY_IGN="${MY_IGN}" 672 | 673 | elif [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" = "" ]; then 674 | if [ "${MY_DEB}" = "1" ]; then 675 | echo "[ARG] Using config file values: ignore: ${!IGNORE}" 676 | fi 677 | MY_IGN="${!IGNORE}" 678 | 679 | elif [ "${MY_CFG}" = "" ] && [ "${MY_IGN}" != "" ]; then 680 | if [ "${MY_DEB}" = "1" ]; then 681 | echo "[ARG] Using cmd argument: ignore: ${MY_IGN}" 682 | fi 683 | MY_IGN="${MY_IGN}" 684 | 685 | else 686 | if [ "${MY_DEB}" = "1" ]; then 687 | echo "[ARG] Not ignoring anything" 688 | fi 689 | MY_IGN= 690 | fi 691 | 692 | 693 | # 694 | # Decide on text files (non-binary) or all files 695 | # 696 | if [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" != "0" ]; then 697 | if [ "${MY_DEB}" = "1" ]; then 698 | echo "[ARG] Cmd arg --text: '${MY_TXT}' will take precedence over config file value". 699 | fi 700 | MY_TXT="${MY_TXT}" 701 | 702 | elif [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" = "0" ]; then 703 | if [ "${MY_DEB}" = "1" ]; then 704 | echo "[ARG] Using config file values: --text: ${!TEXT}" 705 | fi 706 | MY_TXT="${!TEXT}" 707 | 708 | elif [ "${MY_CFG}" = "" ] && [ "${MY_TXT}" != "0" ]; then 709 | if [ "${MY_DEB}" = "1" ]; then 710 | echo "[ARG] Using cmd argument: --text: ${MY_TXT}" 711 | fi 712 | MY_TXT="${MY_TXT}" 713 | 714 | else 715 | if [ "${MY_DEB}" = "1" ]; then 716 | echo "[ARG] Not narrowing down by text files" 717 | fi 718 | MY_TXT="0" 719 | fi 720 | 721 | 722 | # 723 | # Decide on file size 724 | # 725 | if [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" != "0" ]; then 726 | if [ "${MY_DEB}" = "1" ]; then 727 | echo "[ARG] Cmd arg --size: '${MY_SIZ}' will take precedence over config file value". 728 | fi 729 | MY_SIZ="${MY_SIZ}" 730 | 731 | elif [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" = "0" ]; then 732 | if [ "${MY_DEB}" = "1" ]; then 733 | echo "[ARG] Using config file values: --size: ${!SIZE}" 734 | fi 735 | MY_SIZ="${!SIZE}" 736 | 737 | elif [ "${MY_CFG}" = "" ] && [ "${MY_SIZ}" != "0" ]; then 738 | if [ "${MY_DEB}" = "1" ]; then 739 | echo "[ARG] Using cmd argument: --size: ${MY_SIZ}" 740 | fi 741 | MY_SIZ="${MY_SIZ}" 742 | 743 | else 744 | if [ "${MY_DEB}" = "1" ]; then 745 | echo "[ARG] Not narrowing down by size > 0 bytes" 746 | fi 747 | MY_SIZ="0" 748 | fi 749 | 750 | if [ "${MY_SIZ}" = "1" ]; then 751 | MY_SIZ="! -size 0" 752 | else 753 | MY_SIZ="" 754 | fi 755 | 756 | 757 | 758 | # 759 | # Decide on Custom string 760 | # 761 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 762 | if [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" != "" ]; then 763 | if [ "${MY_DEB}" = "1" ]; then 764 | echo "[ARG] Cmd arg --custom=\"${MY_CUS}\" will take precedence over config file value". 765 | fi 766 | MY_CUS="${MY_CUS}" 767 | 768 | elif [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" = "" ]; then 769 | if [ "${MY_DEB}" = "1" ]; then 770 | echo "[ARG] Using config file values: custom: \"${!CUSTOM}\"" 771 | fi 772 | MY_CUS="${!CUSTOM}" 773 | 774 | elif [ "${MY_CFG}" = "" ] && [ "${MY_CUS}" != "" ]; then 775 | if [ "${MY_DEB}" = "1" ]; then 776 | echo "[ARG] Using cmd argument: custom: \"${MY_CUS}\"" 777 | fi 778 | MY_CUS="${MY_CUS}" 779 | 780 | else 781 | if [ "${MY_DEB}" = "1" ]; then 782 | echo "[ARG] No customization applied" 783 | fi 784 | MY_CUS= 785 | fi 786 | fi 787 | 788 | 789 | 790 | ############################################################ 791 | # Build command 792 | ############################################################ 793 | 794 | # 795 | # 'find' pattern for file extensions 796 | # 797 | if [ "${MY_EXT}" != "" ]; then 798 | NAME_PATTERN="\( -iname \*.${MY_EXT//,/ -o -iname \\*.} \)" 799 | else 800 | NAME_PATTERN="" 801 | fi 802 | 803 | # 804 | # 'find' pattern for ignores/excludes 805 | # 806 | if [ "${MY_IGN}" != "" ]; then 807 | EXCL_PATTERN="-not \( -path \"${MY_PATH}/${MY_IGN//,/*\" -o -path \"${MY_PATH}\/}*\" \)" 808 | else 809 | EXCL_PATTERN="" 810 | fi 811 | 812 | 813 | # 814 | # Fix? 815 | # 816 | if [ "${MY_FIX}" = "1" ]; then 817 | MY_CHECK="${MY_FIX_CMD}" 818 | else 819 | # 820 | # Normal check 821 | # (Apply custom command?) 822 | # 823 | if [ "${MY_CUS}" = "" ]; then 824 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${DEFAULT_CUST_OPS}" )" 825 | else 826 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${MY_CUS}" )" 827 | fi 828 | fi 829 | 830 | 831 | # 832 | # Show files or grep in found files? 833 | # 834 | 835 | 836 | # Be verbose? 837 | if [ "${MY_VER}" = "1" ]; then 838 | XARGS_VERBOSE="-t" 839 | else 840 | XARGS_VERBOSE="" 841 | fi 842 | 843 | # 844 | # Build command 845 | # 846 | 847 | 848 | ### Text files (list-only) 849 | if [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "1" ]; then 850 | if [ "${MY_SHE}" != "" ]; then 851 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE}" 852 | else 853 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il ''" 854 | fi 855 | 856 | ### Text files (run!!!) 857 | elif [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "0" ]; then 858 | if [ "${MY_SHE}" != "" ]; then 859 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 860 | else 861 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 862 | fi 863 | 864 | ### All files (list-only) 865 | elif [ "${MY_TXT}" = "0" ] && [ "${MY_LST}" = "1" ]; then 866 | if [ "${MY_SHE}" != "" ]; then 867 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE}" 868 | else 869 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print" 870 | fi 871 | 872 | 873 | ### All files (run!!!) 874 | else 875 | if [ "${MY_SHE}" != "" ]; then 876 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 877 | else 878 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 879 | fi 880 | 881 | fi 882 | 883 | 884 | 885 | 886 | ############################################################ 887 | # Execute 888 | ############################################################ 889 | 890 | # Dry mode? 891 | if [ "${MY_DRY}" = "1" ]; then 892 | printf "%s\n" "${MY_CMD}" 893 | exit 0 894 | fi 895 | 896 | printf "\$ %s\n" "${MY_CMD}" 897 | 898 | output="$(eval "${MY_CMD}")" 899 | 900 | # If showing files only, exit normally 901 | if [ "${MY_LST}" = "1" ]; then 902 | printf "%s\n" "${output}" 903 | exit 0 904 | fi 905 | 906 | 907 | if [ "${output}" != "" ]; then 908 | printf "%s\n" "${output}" 909 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 910 | exit 1 911 | else 912 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 913 | exit 0 914 | fi 915 | -------------------------------------------------------------------------------- /bin/syntax-python: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="syntax-python" 10 | MY_DESC="Scans recursively for files containing Python syntax errors." 11 | MY_FINISH_OK="No files with Python syntax errors found." 12 | MY_FINISH_ERR="Found files with Python syntax errors." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="SYNTAX_PYTHON_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="python" 19 | 20 | # Enable custom options (cmd arguments) 21 | # that can be parsed to the actual check binary? 22 | ENABLE_CUST_OPS=0 23 | 24 | # Binaries required for fixing 25 | REQUIRED_FIX_BINS="" 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="python -m py_compile \"\$1\" 2>&1 || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="python --version" 49 | 50 | 51 | 52 | 53 | 54 | 55 | ############################################################ 56 | # Do not edit from here 57 | ############################################################ 58 | 59 | # 60 | # Version 61 | # 62 | MY_VERSION="0.15" 63 | MY_DATE="2018-04-09" 64 | 65 | # 66 | # Credits 67 | # 68 | MY_AUTHOR="cytopia" 69 | MY_EMAIL="cytopia@everythingcli.org" 70 | 71 | # 72 | # Required system binaries 73 | # 74 | REQUIRED_BINS="awk grep find sed tr xargs" 75 | 76 | # 77 | # Variables populated by cmd args or config file 78 | # 79 | MY_PATH= 80 | MY_SHE= 81 | MY_EXT=0 82 | MY_IGN= 83 | MY_TXT=0 84 | MY_SIZ=0 85 | MY_DRY=0 86 | MY_LST=0 87 | MY_VER=0 88 | MY_DEB=0 89 | MY_FIX=0 90 | MY_CFG= 91 | MY_CUS= 92 | 93 | CLR_SUC="\033[0;32m" 94 | CLR_ERR="\033[0;31m" 95 | CLR_CLS="\033[0m" 96 | 97 | ################################################################################ 98 | # 99 | # F U N C T I O N S 100 | # 101 | ################################################################################ 102 | 103 | 104 | 105 | print_usage() { 106 | 107 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 108 | _custom=" [--custom=\"opts\"]" 109 | else 110 | _custom="" 111 | fi 112 | 113 | if [ "${ENABLE_FIX}" = "1" ];then 114 | _fix=" [--fix]" 115 | else 116 | _fix="" 117 | fi 118 | 119 | echo "Usage: ${MY_NAME} [--text] [--size] [--shebang=php] [--extension=tpl,htm,html,php,...] [--ignore=dir1,dir2] [--config=conf] [--confpre=${MY_CONF_PRE}]${_custom}${_fix} [--verbose] [--debug] [--dry] [--list] --path=dir" 120 | echo " ${MY_NAME} --info" 121 | echo " ${MY_NAME} --help" 122 | echo " ${MY_NAME} --version" 123 | echo 124 | echo "${MY_DESC}" 125 | echo "Will return 1 on occurance, otherwise 0." 126 | echo 127 | echo "Required arguments:" 128 | echo 129 | echo " --path= Specify directory where to scan." 130 | echo 131 | echo 132 | echo "Optional run arguments:" 133 | if [ "${ENABLE_FIX}" = "1" ];then 134 | echo " --fix Fixable :-)" 135 | echo " Fix the problems for the specified files." 136 | echo " Note, all other options below also apply" 137 | echo 138 | fi 139 | echo " --text Limit search to text files only (non-binary)." 140 | echo " Can be narrowed further with '--extension'" 141 | echo 142 | echo " --size Limit search to files which are not empty (bigger than 0 bytes)." 143 | echo 144 | echo " --shebang= Only find files (shell scripts) with this specific shebang." 145 | echo " It is useful to combine this with --text and --size for faster searches." 146 | echo " Use with --dry to see how this search command is generated." 147 | echo " Example:" 148 | echo " --shebang=bash" 149 | echo " --shebang=php" 150 | echo " --shebang=sh" 151 | echo 152 | echo " --extension= Only find files matching those extensions." 153 | echo " Comma separated list of file extensions." 154 | echo " Only find files matching those extensions." 155 | echo " Defaults to all files if not specified or empty." 156 | echo " Example:" 157 | echo " --extension=html,php,inc" 158 | echo " --extension=php" 159 | echo 160 | echo " --ignore= Comma separated list of ignore paths." 161 | echo " Directories must be specified from the starting location of --path." 162 | echo " Example:" 163 | echo " ignore 'foor/bar' folder inside '/var/www' path:" 164 | echo " --path=/var/www --ignore=foo/bar" 165 | echo 166 | echo " --config= Load configuration file." 167 | echo " File must contain the following directives:" 168 | echo " ${MY_CONF_PRE}EXTENSION=\"\" # comma separated" 169 | echo " ${MY_CONF_PRE}IGNORE=\"\" # comma separated" 170 | echo " ${MY_CONF_PRE}TEXT=0|1 # 0 or 1" 171 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 172 | echo " ${MY_CONF_PRE}CUSTOM=\"\" # custom command" 173 | fi 174 | echo " Note that cmd arguments take precedence over" 175 | echo " config file settings." 176 | echo 177 | echo " --confpre= Set custom configuration directive prefix." 178 | echo " Current default ist: '${MY_CONF_PRE}'." 179 | echo " This is useful, when you want to define different defaults" 180 | echo " per check via configuration file." 181 | echo 182 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 183 | echo " --custom= Parse custom command line option to the check binary." 184 | echo " Note that when you want to add config files or other files" 185 | echo " you must use an absolute path." 186 | echo 187 | echo " Current custom command:" 188 | echo " --custom=\"${DEFAULT_CUST_OPS//\"/\\\"}\"" # \" -> \\\" 189 | echo 190 | echo " Overwrite example:" 191 | echo " --custom=\"--color --config /absoulte/path/conf.json\"" 192 | echo 193 | fi 194 | echo " --verbose Be verbose and print commands and files being checked." 195 | echo 196 | echo 197 | echo " --debug Print system messages." 198 | echo 199 | echo 200 | echo "Optional training arguments:" 201 | echo " --dry Don't do anything, just display the commands." 202 | echo 203 | echo " --list Instead of searching inside the files, just display the filenames" 204 | echo " that would be found by --path, --extension and --ignore" 205 | echo 206 | echo 207 | echo "System arguments:" 208 | echo " --info Show versions of required commands (useful for bugreports)." 209 | echo " --help Show help screen." 210 | echo " --version Show version information." 211 | echo 212 | echo 213 | echo "${MY_NAME} is part of the awesome-ci collection." 214 | echo "https://github.com/cytopia/awesome-ci" 215 | } 216 | 217 | print_version() { 218 | echo "tool: ${MY_NAME}" 219 | echo "version: v${MY_VERSION} (${MY_DATE})" 220 | echo "author: ${MY_AUTHOR}" 221 | echo "email: ${MY_EMAIL}" 222 | echo 223 | echo "${MY_NAME} is part of the awesome-ci collection." 224 | echo "https://github.com/cytopia/awesome-ci" 225 | } 226 | 227 | print_info() { 228 | 229 | # 230 | # Required binaries 231 | # 232 | 233 | if ! echo "${MY_INFO}" | grep -cqE "^bash"; then 234 | MY_CMD_VERSION="bash --version | grep -E '(([0-9]+)(\.))+'" 235 | echo "\$ ${MY_CMD_VERSION}" 236 | eval "${MY_CMD_VERSION}" 237 | echo 238 | fi 239 | if ! echo "${MY_INFO}" | grep -cqE "^\(awk"; then 240 | MY_CMD_VERSION="(awk -Wversion 2>/dev/null || awk --version) | grep -E '(([0-9]+)(\.))+'" 241 | echo "\$ ${MY_CMD_VERSION}" 242 | eval "${MY_CMD_VERSION}" 243 | echo 244 | fi 245 | if ! echo "${MY_INFO}" | grep -cqE "^grep"; then 246 | MY_CMD_VERSION="grep -V | grep -E '([0-9]+\.+)+'" 247 | echo "\$ ${MY_CMD_VERSION}" 248 | eval "${MY_CMD_VERSION}" 249 | echo 250 | fi 251 | if ! echo "${MY_INFO}" | grep -cqE "^\(find"; then 252 | MY_CMD_VERSION="(find --version >/dev/null 2>&1) && (find --version 2>&1 | head -1) || (echo 'find (BSD find)')" 253 | echo "\$ ${MY_CMD_VERSION}" 254 | eval "${MY_CMD_VERSION}" 255 | echo 256 | fi 257 | if ! echo "${MY_INFO}" | grep -cqE "^\(sed"; then 258 | MY_CMD_VERSION="(sed --version >/dev/null 2>&1) && (sed --version 2>&1 | head -1) || (echo 'sed (BSD sed)')" 259 | echo "\$ ${MY_CMD_VERSION}" 260 | eval "${MY_CMD_VERSION}" 261 | echo 262 | fi 263 | if ! echo "${MY_INFO}" | grep -cqE "^\(tr"; then 264 | MY_CMD_VERSION="(tr --version >/dev/null 2>&1) && (tr --version 2>&1 | head -1) || (echo 'tr (BSD tr)')" 265 | echo "\$ ${MY_CMD_VERSION}" 266 | eval "${MY_CMD_VERSION}" 267 | echo 268 | fi 269 | if ! echo "${MY_INFO}" | grep -cqE "^\(xargs"; then 270 | MY_CMD_VERSION="(xargs --version >/dev/null 2>&1) && (xargs --version 2>&1 | head -1) || (echo 'xargs (BSD xargs)')" 271 | echo "\$ ${MY_CMD_VERSION}" 272 | eval "${MY_CMD_VERSION}" 273 | echo 274 | fi 275 | 276 | # 277 | # Custom binary 278 | # 279 | if [ "${MY_INFO}" != "" ]; then 280 | echo "\$ ${MY_INFO}" 281 | eval "${MY_INFO}" 282 | echo 283 | fi 284 | 285 | # 286 | # --fix binary 287 | # 288 | if [ "${ENABLE_FIX}" = "1" ] && [ "${REQUIRED_FIX_BINS}" != "" ]; then 289 | _can_fix="1" 290 | for _bin in ${REQUIRED_FIX_BINS}; do 291 | if ! command -v "${_bin}" >/dev/null 2>&1; then 292 | echo "${_bin}: Not found." 293 | _can_fix="0}" 294 | fi 295 | done 296 | if [ "${_can_fix}" = "1" ]; then 297 | echo "\$ ${MY_FIX_INFO}" 298 | eval "${MY_FIX_INFO}" 299 | echo 300 | else 301 | echo "Unable to use --fix" 302 | echo 303 | return 0 304 | fi 305 | fi 306 | } 307 | 308 | 309 | check_requirements() { 310 | _debug="${1}" 311 | _ret1=0 312 | _ret2=0 313 | 314 | # System binaries 315 | for _bin in ${REQUIRED_BINS}; do 316 | if ! command -v "${_bin}" >/dev/null 2>&1; then 317 | echo "[ERR] Required sys binary '${_bin}' not found." 318 | _ret1=1 319 | else 320 | if [ "${_debug}" = "1" ]; then 321 | echo "[OK] Required system binary '${_bin}' found." 322 | fi 323 | fi 324 | done 325 | 326 | # Specific binaries for this check 327 | for _bin in ${REQUIRED_CUST_BINS}; do 328 | if ! command -v "${_bin}" >/dev/null 2>&1; then 329 | echo "[ERR] Required custom binary '${_bin}' not found." 330 | _ret2=1 331 | else 332 | if [ "${_debug}" = "1" ]; then 333 | echo "[OK] Required custom binary '${_bin}' found." 334 | fi 335 | fi 336 | done 337 | 338 | # Binaries required to fix 339 | if [ "${ENABLE_FIX}" = "1" ] && [ "${MY_FIX}" = "1" ]; then 340 | for _bin in ${REQUIRED_FIX_BINS}; do 341 | if ! command -v "${_bin}" >/dev/null 2>&1; then 342 | echo "[ERR] Required --fix binary '${_bin}' not found." 343 | _ret2=1 344 | else 345 | if [ "${_debug}" = "1" ]; then 346 | echo "[OK] Required --fix binary '${_bin}' found." 347 | fi 348 | fi 349 | done 350 | fi 351 | 352 | 353 | return $((_ret1 + _ret2)) 354 | } 355 | 356 | check_config_file() { 357 | _config="${1}" 358 | 359 | # Check config file 360 | if [ ! -f "${_config}" ]; then 361 | echo "[CONFIG] Config file not found: ${_config}" 362 | return 1 363 | fi 364 | 365 | # Check directives 366 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=" "${_config}"; then 367 | echo "[CONFIG] ${MY_CONF_PRE}IGNORE variable not found in config." 368 | return 1 369 | fi 370 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=[\"']{1}.*[\"']{1}$" "${_config}"; then 371 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}IGNORE variable." 372 | return 1 373 | fi 374 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=" "${_config}"; then 375 | echo "[CONFIG] ${MY_CONF_PRE}EXTENSION variable not found in config." 376 | return 1 377 | fi 378 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=[\"']{1}.*[\"']{1}$" "${_config}"; then 379 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}EXTENSION variable." 380 | return 1 381 | fi 382 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=" "${_config}"; then 383 | echo "[CONFIG] ${MY_CONF_PRE}TEXT variable not found in config." 384 | return 1 385 | fi 386 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=[\"']*[01]{1}[\"']*$" "${_config}"; then 387 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}TEXT variable." 388 | return 1 389 | fi 390 | 391 | # Check optional directives 392 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 393 | if ! grep -Eq "^${MY_CONF_PRE}CUSTOM=[\"']{1}.*[\"']{1}$" "${_config}"; then 394 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}CUSTOM variable." 395 | return 1 396 | fi 397 | fi 398 | 399 | } 400 | 401 | 402 | # 403 | # System independent method 404 | # to get number of CPU cores. 405 | # (defaults to 1 if impossible) 406 | # 407 | num_cpu() { 408 | if ! _num="$( getconf _NPROCESSORS_ONLN 2>/dev/null )"; then 409 | echo "1" 410 | else 411 | echo "${_num}" 412 | fi 413 | } 414 | 415 | 416 | # 417 | # sed wrapper that automatically escapes 418 | # regex literals 419 | # 420 | mysed() { 421 | _input="$1" 422 | _search="$2" 423 | _replace="$3" 424 | 425 | echo "${_input}" | sed "s/$(echo "${_search}" | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo "${_replace}" | sed -e 's/[\/&]/\\&/g')/g" 426 | } 427 | 428 | 429 | 430 | 431 | ################################################################################ 432 | # 433 | # M A I N E N T R Y P O I N T 434 | # 435 | ################################################################################ 436 | 437 | 438 | 439 | ############################################################ 440 | # Command Line arguments 441 | ############################################################ 442 | 443 | 444 | # 445 | # Read command line arguments 446 | # 447 | while [ $# -gt 0 ]; do 448 | case "${1}" in 449 | 450 | # ---------------------------------------- 451 | --path=*) 452 | MY_PATH="${1//--path=/}" 453 | ;; 454 | 455 | # ---------------------------------------- 456 | --shebang=*) 457 | MY_SHE="${1//--shebang=/}" 458 | ;; 459 | 460 | # ---------------------------------------- 461 | --extension=*) 462 | MY_EXT="${1//--extension=/}" 463 | ;; 464 | 465 | # ---------------------------------------- 466 | --ignore=*) 467 | MY_IGN="${1//--ignore=/}" 468 | ;; 469 | 470 | # ---------------------------------------- 471 | --config=*) 472 | MY_CFG="${1//--config=/}" 473 | ;; 474 | 475 | # ---------------------------------------- 476 | --confpre=*) 477 | MY_CONF_PRE="${1//--confpre=/}" 478 | ;; 479 | 480 | # ---------------------------------------- 481 | --custom=*) 482 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 483 | MY_CUS="${1//--custom=/}" 484 | else 485 | echo "Invalid argument: ${1}" 486 | echo "Type '${MY_NAME} --help' for available options." 487 | exit 1 488 | fi 489 | ;; 490 | 491 | # ---------------------------------------- 492 | --fix) 493 | if [ "${ENABLE_FIX}" = "1" ]; then 494 | MY_FIX=1 495 | else 496 | echo "Invalid argument: ${1}" 497 | echo "Type '${MY_NAME} --help' for available options." 498 | exit 1 499 | fi 500 | ;; 501 | 502 | 503 | # ---------------------------------------- 504 | --text) 505 | MY_TXT=1 506 | ;; 507 | 508 | # ---------------------------------------- 509 | --size) 510 | MY_SIZ=1 511 | ;; 512 | 513 | # ---------------------------------------- 514 | --dry) 515 | MY_DRY=1 516 | ;; 517 | 518 | # ---------------------------------------- 519 | --list) 520 | MY_LST=1 521 | ;; 522 | 523 | # ---------------------------------------- 524 | --verbose) 525 | MY_VER=1 526 | ;; 527 | 528 | # ---------------------------------------- 529 | --debug) 530 | MY_DEB=1 531 | ;; 532 | 533 | # ---------------------------------------- 534 | --info) 535 | if ! check_requirements "${MY_DEB}"; then 536 | exit 1 537 | fi 538 | 539 | if ! print_info; then 540 | exit 1 541 | fi 542 | 543 | exit 0 544 | ;; 545 | 546 | # ---------------------------------------- 547 | --help) 548 | print_usage 549 | exit 0 550 | ;; 551 | 552 | # ---------------------------------------- 553 | --version) 554 | print_version 555 | exit 0 556 | ;; 557 | 558 | # ---------------------------------------- 559 | *) 560 | echo "Invalid argument: ${1}" 561 | echo "Type '${MY_NAME} --help' for available options." 562 | exit 1 563 | ;; 564 | esac 565 | shift 566 | done 567 | 568 | 569 | 570 | ############################################################ 571 | # Sanity Checks 572 | ############################################################ 573 | 574 | # 575 | # Check general requirements 576 | # 577 | if ! check_requirements "${MY_DEB}"; then 578 | exit 1 579 | fi 580 | 581 | # 582 | # Check path 583 | # 584 | if [ "${MY_PATH}" = "" ]; then 585 | echo "--path not specified" 586 | echo "Type '${MY_NAME} --help' for available options." 587 | exit 1 588 | fi 589 | if [ ! -e "${MY_PATH}" ]; then 590 | echo "Specified path does not exist: '${MY_PATH}'." 591 | echo "Type '${MY_NAME} --help' for available options." 592 | exit 1 593 | fi 594 | 595 | 596 | # 597 | # Check and load config if desired 598 | # 599 | if [ "${MY_CFG}" != "" ]; then 600 | if ! check_config_file "${MY_CFG}"; then 601 | exit 1 602 | fi 603 | 604 | . "${MY_CFG}" 605 | fi 606 | 607 | 608 | 609 | ############################################################ 610 | # Evaluate Settings 611 | ############################################################ 612 | 613 | CPU_CORES="$(num_cpu)" 614 | 615 | 616 | # Var substitutions for config file directives 617 | # to match current program. 618 | EXTENSION="${MY_CONF_PRE}EXTENSION" 619 | IGNORE="${MY_CONF_PRE}IGNORE" 620 | TEXT="${MY_CONF_PRE}TEXT" 621 | SIZE="${MY_CONF_PRE}SIZE" 622 | CUSTOM="${MY_CONF_PRE}CUSTOM" 623 | 624 | # 625 | # Decide on Shebang 626 | # 627 | if [ "${MY_SHE}" != "" ]; then 628 | MY_SHE="xargs -0 -P ${CPU_CORES} -n1 awk '/^#!.*(\/${MY_SHE}|[[:space:]]+${MY_SHE})/{print FILENAME}'" 629 | else 630 | MY_SHE="" 631 | fi 632 | 633 | 634 | 635 | # 636 | # Decide on File extensions 637 | # 638 | if [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" != "0" ]; then 639 | if [ "${MY_DEB}" = "1" ]; then 640 | echo "[ARG] Cmd arg --extension=${MY_EXT} will take precedence over config file value". 641 | fi 642 | MY_EXT="${MY_EXT}" 643 | 644 | elif [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" = "0" ]; then 645 | if [ "${MY_DEB}" = "1" ]; then 646 | echo "[ARG] Using config file values: ext: ${!EXTENSION}" 647 | fi 648 | MY_EXT="${!EXTENSION}" 649 | 650 | elif [ "${MY_CFG}" = "" ] && [ "${MY_EXT}" != "0" ]; then 651 | if [ "${MY_DEB}" = "1" ]; then 652 | echo "[ARG] Using cmd argument: ext: '${MY_EXT}'" 653 | fi 654 | MY_EXT="${MY_EXT}" 655 | 656 | else 657 | if [ "${MY_DEB}" = "1" ]; then 658 | echo "[ARG] Using all file extensions" 659 | fi 660 | MY_EXT= 661 | fi 662 | 663 | 664 | # 665 | # Decide on ignore paths 666 | # 667 | if [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" != "" ]; then 668 | if [ "${MY_DEB}" = "1" ]; then 669 | echo "[ARG] Cmd arg --ignore=${MY_IGN} will take precedence over config file value". 670 | fi 671 | MY_IGN="${MY_IGN}" 672 | 673 | elif [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" = "" ]; then 674 | if [ "${MY_DEB}" = "1" ]; then 675 | echo "[ARG] Using config file values: ignore: ${!IGNORE}" 676 | fi 677 | MY_IGN="${!IGNORE}" 678 | 679 | elif [ "${MY_CFG}" = "" ] && [ "${MY_IGN}" != "" ]; then 680 | if [ "${MY_DEB}" = "1" ]; then 681 | echo "[ARG] Using cmd argument: ignore: ${MY_IGN}" 682 | fi 683 | MY_IGN="${MY_IGN}" 684 | 685 | else 686 | if [ "${MY_DEB}" = "1" ]; then 687 | echo "[ARG] Not ignoring anything" 688 | fi 689 | MY_IGN= 690 | fi 691 | 692 | 693 | # 694 | # Decide on text files (non-binary) or all files 695 | # 696 | if [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" != "0" ]; then 697 | if [ "${MY_DEB}" = "1" ]; then 698 | echo "[ARG] Cmd arg --text: '${MY_TXT}' will take precedence over config file value". 699 | fi 700 | MY_TXT="${MY_TXT}" 701 | 702 | elif [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" = "0" ]; then 703 | if [ "${MY_DEB}" = "1" ]; then 704 | echo "[ARG] Using config file values: --text: ${!TEXT}" 705 | fi 706 | MY_TXT="${!TEXT}" 707 | 708 | elif [ "${MY_CFG}" = "" ] && [ "${MY_TXT}" != "0" ]; then 709 | if [ "${MY_DEB}" = "1" ]; then 710 | echo "[ARG] Using cmd argument: --text: ${MY_TXT}" 711 | fi 712 | MY_TXT="${MY_TXT}" 713 | 714 | else 715 | if [ "${MY_DEB}" = "1" ]; then 716 | echo "[ARG] Not narrowing down by text files" 717 | fi 718 | MY_TXT="0" 719 | fi 720 | 721 | 722 | # 723 | # Decide on file size 724 | # 725 | if [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" != "0" ]; then 726 | if [ "${MY_DEB}" = "1" ]; then 727 | echo "[ARG] Cmd arg --size: '${MY_SIZ}' will take precedence over config file value". 728 | fi 729 | MY_SIZ="${MY_SIZ}" 730 | 731 | elif [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" = "0" ]; then 732 | if [ "${MY_DEB}" = "1" ]; then 733 | echo "[ARG] Using config file values: --size: ${!SIZE}" 734 | fi 735 | MY_SIZ="${!SIZE}" 736 | 737 | elif [ "${MY_CFG}" = "" ] && [ "${MY_SIZ}" != "0" ]; then 738 | if [ "${MY_DEB}" = "1" ]; then 739 | echo "[ARG] Using cmd argument: --size: ${MY_SIZ}" 740 | fi 741 | MY_SIZ="${MY_SIZ}" 742 | 743 | else 744 | if [ "${MY_DEB}" = "1" ]; then 745 | echo "[ARG] Not narrowing down by size > 0 bytes" 746 | fi 747 | MY_SIZ="0" 748 | fi 749 | 750 | if [ "${MY_SIZ}" = "1" ]; then 751 | MY_SIZ="! -size 0" 752 | else 753 | MY_SIZ="" 754 | fi 755 | 756 | 757 | 758 | # 759 | # Decide on Custom string 760 | # 761 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 762 | if [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" != "" ]; then 763 | if [ "${MY_DEB}" = "1" ]; then 764 | echo "[ARG] Cmd arg --custom=\"${MY_CUS}\" will take precedence over config file value". 765 | fi 766 | MY_CUS="${MY_CUS}" 767 | 768 | elif [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" = "" ]; then 769 | if [ "${MY_DEB}" = "1" ]; then 770 | echo "[ARG] Using config file values: custom: \"${!CUSTOM}\"" 771 | fi 772 | MY_CUS="${!CUSTOM}" 773 | 774 | elif [ "${MY_CFG}" = "" ] && [ "${MY_CUS}" != "" ]; then 775 | if [ "${MY_DEB}" = "1" ]; then 776 | echo "[ARG] Using cmd argument: custom: \"${MY_CUS}\"" 777 | fi 778 | MY_CUS="${MY_CUS}" 779 | 780 | else 781 | if [ "${MY_DEB}" = "1" ]; then 782 | echo "[ARG] No customization applied" 783 | fi 784 | MY_CUS= 785 | fi 786 | fi 787 | 788 | 789 | 790 | ############################################################ 791 | # Build command 792 | ############################################################ 793 | 794 | # 795 | # 'find' pattern for file extensions 796 | # 797 | if [ "${MY_EXT}" != "" ]; then 798 | NAME_PATTERN="\( -iname \*.${MY_EXT//,/ -o -iname \\*.} \)" 799 | else 800 | NAME_PATTERN="" 801 | fi 802 | 803 | # 804 | # 'find' pattern for ignores/excludes 805 | # 806 | if [ "${MY_IGN}" != "" ]; then 807 | EXCL_PATTERN="-not \( -path \"${MY_PATH}/${MY_IGN//,/*\" -o -path \"${MY_PATH}\/}*\" \)" 808 | else 809 | EXCL_PATTERN="" 810 | fi 811 | 812 | 813 | # 814 | # Fix? 815 | # 816 | if [ "${MY_FIX}" = "1" ]; then 817 | MY_CHECK="${MY_FIX_CMD}" 818 | else 819 | # 820 | # Normal check 821 | # (Apply custom command?) 822 | # 823 | if [ "${MY_CUS}" = "" ]; then 824 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${DEFAULT_CUST_OPS}" )" 825 | else 826 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${MY_CUS}" )" 827 | fi 828 | fi 829 | 830 | 831 | # 832 | # Show files or grep in found files? 833 | # 834 | 835 | 836 | # Be verbose? 837 | if [ "${MY_VER}" = "1" ]; then 838 | XARGS_VERBOSE="-t" 839 | else 840 | XARGS_VERBOSE="" 841 | fi 842 | 843 | # 844 | # Build command 845 | # 846 | 847 | 848 | ### Text files (list-only) 849 | if [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "1" ]; then 850 | if [ "${MY_SHE}" != "" ]; then 851 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE}" 852 | else 853 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il ''" 854 | fi 855 | 856 | ### Text files (run!!!) 857 | elif [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "0" ]; then 858 | if [ "${MY_SHE}" != "" ]; then 859 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 860 | else 861 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 862 | fi 863 | 864 | ### All files (list-only) 865 | elif [ "${MY_TXT}" = "0" ] && [ "${MY_LST}" = "1" ]; then 866 | if [ "${MY_SHE}" != "" ]; then 867 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE}" 868 | else 869 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print" 870 | fi 871 | 872 | 873 | ### All files (run!!!) 874 | else 875 | if [ "${MY_SHE}" != "" ]; then 876 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 877 | else 878 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 879 | fi 880 | 881 | fi 882 | 883 | 884 | 885 | 886 | ############################################################ 887 | # Execute 888 | ############################################################ 889 | 890 | # Dry mode? 891 | if [ "${MY_DRY}" = "1" ]; then 892 | printf "%s\n" "${MY_CMD}" 893 | exit 0 894 | fi 895 | 896 | printf "\$ %s\n" "${MY_CMD}" 897 | 898 | output="$(eval "${MY_CMD}")" 899 | 900 | # If showing files only, exit normally 901 | if [ "${MY_LST}" = "1" ]; then 902 | printf "%s\n" "${output}" 903 | exit 0 904 | fi 905 | 906 | 907 | if [ "${output}" != "" ]; then 908 | printf "%s\n" "${output}" 909 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 910 | exit 1 911 | else 912 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 913 | exit 0 914 | fi 915 | -------------------------------------------------------------------------------- /bin/syntax-ruby: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -u 3 | 4 | ############################################################ 5 | # Adjust for each check 6 | ############################################################ 7 | 8 | # Name and messages 9 | MY_NAME="syntax-ruby" 10 | MY_DESC="Scans recursively for files containing Ruby syntax errors." 11 | MY_FINISH_OK="No files with Ruby syntax errors found." 12 | MY_FINISH_ERR="Found files with Ruby syntax errors." 13 | 14 | # Configuration file prefix 15 | MY_CONF_PRE="SYNTAX_RUBY_" 16 | 17 | # Custom required binaries 18 | REQUIRED_CUST_BINS="ruby" 19 | 20 | # Enable custom options (cmd arguments) 21 | # that can be parsed to the actual check binary? 22 | ENABLE_CUST_OPS=0 23 | 24 | # Binaries required for fixing 25 | REQUIRED_FIX_BINS="" 26 | 27 | # When not specifying --custom, 28 | # always use this as the default options 29 | # to parse to the check binary. 30 | DEFAULT_CUST_OPS="" 31 | 32 | # How to add your check here: 33 | # --------------------------- 34 | # $1 This comes from xargs and represents 35 | # the current file to work on: 36 | # xargs sh '${MY_CHECK}' -- 37 | # 38 | # __CUSTOM_OPT_PLACEHOLDER__ 39 | # This will be replaced either with custom options 40 | # or with the default options. 41 | 42 | MY_CHECK="ruby -c \"\$1\" 2>&1 | grep -vE \"[[:space:]]*OK\$\" || true" 43 | 44 | # Can this check fix the problems? 45 | ENABLE_FIX=0 46 | 47 | # Command to be displayed for --info 48 | MY_INFO="ruby --version" 49 | 50 | 51 | 52 | 53 | 54 | 55 | ############################################################ 56 | # Do not edit from here 57 | ############################################################ 58 | 59 | # 60 | # Version 61 | # 62 | MY_VERSION="0.15" 63 | MY_DATE="2018-04-09" 64 | 65 | # 66 | # Credits 67 | # 68 | MY_AUTHOR="cytopia" 69 | MY_EMAIL="cytopia@everythingcli.org" 70 | 71 | # 72 | # Required system binaries 73 | # 74 | REQUIRED_BINS="awk grep find sed tr xargs" 75 | 76 | # 77 | # Variables populated by cmd args or config file 78 | # 79 | MY_PATH= 80 | MY_SHE= 81 | MY_EXT=0 82 | MY_IGN= 83 | MY_TXT=0 84 | MY_SIZ=0 85 | MY_DRY=0 86 | MY_LST=0 87 | MY_VER=0 88 | MY_DEB=0 89 | MY_FIX=0 90 | MY_CFG= 91 | MY_CUS= 92 | 93 | CLR_SUC="\033[0;32m" 94 | CLR_ERR="\033[0;31m" 95 | CLR_CLS="\033[0m" 96 | 97 | ################################################################################ 98 | # 99 | # F U N C T I O N S 100 | # 101 | ################################################################################ 102 | 103 | 104 | 105 | print_usage() { 106 | 107 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 108 | _custom=" [--custom=\"opts\"]" 109 | else 110 | _custom="" 111 | fi 112 | 113 | if [ "${ENABLE_FIX}" = "1" ];then 114 | _fix=" [--fix]" 115 | else 116 | _fix="" 117 | fi 118 | 119 | echo "Usage: ${MY_NAME} [--text] [--size] [--shebang=php] [--extension=tpl,htm,html,php,...] [--ignore=dir1,dir2] [--config=conf] [--confpre=${MY_CONF_PRE}]${_custom}${_fix} [--verbose] [--debug] [--dry] [--list] --path=dir" 120 | echo " ${MY_NAME} --info" 121 | echo " ${MY_NAME} --help" 122 | echo " ${MY_NAME} --version" 123 | echo 124 | echo "${MY_DESC}" 125 | echo "Will return 1 on occurance, otherwise 0." 126 | echo 127 | echo "Required arguments:" 128 | echo 129 | echo " --path= Specify directory where to scan." 130 | echo 131 | echo 132 | echo "Optional run arguments:" 133 | if [ "${ENABLE_FIX}" = "1" ];then 134 | echo " --fix Fixable :-)" 135 | echo " Fix the problems for the specified files." 136 | echo " Note, all other options below also apply" 137 | echo 138 | fi 139 | echo " --text Limit search to text files only (non-binary)." 140 | echo " Can be narrowed further with '--extension'" 141 | echo 142 | echo " --size Limit search to files which are not empty (bigger than 0 bytes)." 143 | echo 144 | echo " --shebang= Only find files (shell scripts) with this specific shebang." 145 | echo " It is useful to combine this with --text and --size for faster searches." 146 | echo " Use with --dry to see how this search command is generated." 147 | echo " Example:" 148 | echo " --shebang=bash" 149 | echo " --shebang=php" 150 | echo " --shebang=sh" 151 | echo 152 | echo " --extension= Only find files matching those extensions." 153 | echo " Comma separated list of file extensions." 154 | echo " Only find files matching those extensions." 155 | echo " Defaults to all files if not specified or empty." 156 | echo " Example:" 157 | echo " --extension=html,php,inc" 158 | echo " --extension=php" 159 | echo 160 | echo " --ignore= Comma separated list of ignore paths." 161 | echo " Directories must be specified from the starting location of --path." 162 | echo " Example:" 163 | echo " ignore 'foor/bar' folder inside '/var/www' path:" 164 | echo " --path=/var/www --ignore=foo/bar" 165 | echo 166 | echo " --config= Load configuration file." 167 | echo " File must contain the following directives:" 168 | echo " ${MY_CONF_PRE}EXTENSION=\"\" # comma separated" 169 | echo " ${MY_CONF_PRE}IGNORE=\"\" # comma separated" 170 | echo " ${MY_CONF_PRE}TEXT=0|1 # 0 or 1" 171 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 172 | echo " ${MY_CONF_PRE}CUSTOM=\"\" # custom command" 173 | fi 174 | echo " Note that cmd arguments take precedence over" 175 | echo " config file settings." 176 | echo 177 | echo " --confpre= Set custom configuration directive prefix." 178 | echo " Current default ist: '${MY_CONF_PRE}'." 179 | echo " This is useful, when you want to define different defaults" 180 | echo " per check via configuration file." 181 | echo 182 | if [ "${ENABLE_CUST_OPS}" = "1" ];then 183 | echo " --custom= Parse custom command line option to the check binary." 184 | echo " Note that when you want to add config files or other files" 185 | echo " you must use an absolute path." 186 | echo 187 | echo " Current custom command:" 188 | echo " --custom=\"${DEFAULT_CUST_OPS//\"/\\\"}\"" # \" -> \\\" 189 | echo 190 | echo " Overwrite example:" 191 | echo " --custom=\"--color --config /absoulte/path/conf.json\"" 192 | echo 193 | fi 194 | echo " --verbose Be verbose and print commands and files being checked." 195 | echo 196 | echo 197 | echo " --debug Print system messages." 198 | echo 199 | echo 200 | echo "Optional training arguments:" 201 | echo " --dry Don't do anything, just display the commands." 202 | echo 203 | echo " --list Instead of searching inside the files, just display the filenames" 204 | echo " that would be found by --path, --extension and --ignore" 205 | echo 206 | echo 207 | echo "System arguments:" 208 | echo " --info Show versions of required commands (useful for bugreports)." 209 | echo " --help Show help screen." 210 | echo " --version Show version information." 211 | echo 212 | echo 213 | echo "${MY_NAME} is part of the awesome-ci collection." 214 | echo "https://github.com/cytopia/awesome-ci" 215 | } 216 | 217 | print_version() { 218 | echo "tool: ${MY_NAME}" 219 | echo "version: v${MY_VERSION} (${MY_DATE})" 220 | echo "author: ${MY_AUTHOR}" 221 | echo "email: ${MY_EMAIL}" 222 | echo 223 | echo "${MY_NAME} is part of the awesome-ci collection." 224 | echo "https://github.com/cytopia/awesome-ci" 225 | } 226 | 227 | print_info() { 228 | 229 | # 230 | # Required binaries 231 | # 232 | 233 | if ! echo "${MY_INFO}" | grep -cqE "^bash"; then 234 | MY_CMD_VERSION="bash --version | grep -E '(([0-9]+)(\.))+'" 235 | echo "\$ ${MY_CMD_VERSION}" 236 | eval "${MY_CMD_VERSION}" 237 | echo 238 | fi 239 | if ! echo "${MY_INFO}" | grep -cqE "^\(awk"; then 240 | MY_CMD_VERSION="(awk -Wversion 2>/dev/null || awk --version) | grep -E '(([0-9]+)(\.))+'" 241 | echo "\$ ${MY_CMD_VERSION}" 242 | eval "${MY_CMD_VERSION}" 243 | echo 244 | fi 245 | if ! echo "${MY_INFO}" | grep -cqE "^grep"; then 246 | MY_CMD_VERSION="grep -V | grep -E '([0-9]+\.+)+'" 247 | echo "\$ ${MY_CMD_VERSION}" 248 | eval "${MY_CMD_VERSION}" 249 | echo 250 | fi 251 | if ! echo "${MY_INFO}" | grep -cqE "^\(find"; then 252 | MY_CMD_VERSION="(find --version >/dev/null 2>&1) && (find --version 2>&1 | head -1) || (echo 'find (BSD find)')" 253 | echo "\$ ${MY_CMD_VERSION}" 254 | eval "${MY_CMD_VERSION}" 255 | echo 256 | fi 257 | if ! echo "${MY_INFO}" | grep -cqE "^\(sed"; then 258 | MY_CMD_VERSION="(sed --version >/dev/null 2>&1) && (sed --version 2>&1 | head -1) || (echo 'sed (BSD sed)')" 259 | echo "\$ ${MY_CMD_VERSION}" 260 | eval "${MY_CMD_VERSION}" 261 | echo 262 | fi 263 | if ! echo "${MY_INFO}" | grep -cqE "^\(tr"; then 264 | MY_CMD_VERSION="(tr --version >/dev/null 2>&1) && (tr --version 2>&1 | head -1) || (echo 'tr (BSD tr)')" 265 | echo "\$ ${MY_CMD_VERSION}" 266 | eval "${MY_CMD_VERSION}" 267 | echo 268 | fi 269 | if ! echo "${MY_INFO}" | grep -cqE "^\(xargs"; then 270 | MY_CMD_VERSION="(xargs --version >/dev/null 2>&1) && (xargs --version 2>&1 | head -1) || (echo 'xargs (BSD xargs)')" 271 | echo "\$ ${MY_CMD_VERSION}" 272 | eval "${MY_CMD_VERSION}" 273 | echo 274 | fi 275 | 276 | # 277 | # Custom binary 278 | # 279 | if [ "${MY_INFO}" != "" ]; then 280 | echo "\$ ${MY_INFO}" 281 | eval "${MY_INFO}" 282 | echo 283 | fi 284 | 285 | # 286 | # --fix binary 287 | # 288 | if [ "${ENABLE_FIX}" = "1" ] && [ "${REQUIRED_FIX_BINS}" != "" ]; then 289 | _can_fix="1" 290 | for _bin in ${REQUIRED_FIX_BINS}; do 291 | if ! command -v "${_bin}" >/dev/null 2>&1; then 292 | echo "${_bin}: Not found." 293 | _can_fix="0}" 294 | fi 295 | done 296 | if [ "${_can_fix}" = "1" ]; then 297 | echo "\$ ${MY_FIX_INFO}" 298 | eval "${MY_FIX_INFO}" 299 | echo 300 | else 301 | echo "Unable to use --fix" 302 | echo 303 | return 0 304 | fi 305 | fi 306 | } 307 | 308 | 309 | check_requirements() { 310 | _debug="${1}" 311 | _ret1=0 312 | _ret2=0 313 | 314 | # System binaries 315 | for _bin in ${REQUIRED_BINS}; do 316 | if ! command -v "${_bin}" >/dev/null 2>&1; then 317 | echo "[ERR] Required sys binary '${_bin}' not found." 318 | _ret1=1 319 | else 320 | if [ "${_debug}" = "1" ]; then 321 | echo "[OK] Required system binary '${_bin}' found." 322 | fi 323 | fi 324 | done 325 | 326 | # Specific binaries for this check 327 | for _bin in ${REQUIRED_CUST_BINS}; do 328 | if ! command -v "${_bin}" >/dev/null 2>&1; then 329 | echo "[ERR] Required custom binary '${_bin}' not found." 330 | _ret2=1 331 | else 332 | if [ "${_debug}" = "1" ]; then 333 | echo "[OK] Required custom binary '${_bin}' found." 334 | fi 335 | fi 336 | done 337 | 338 | # Binaries required to fix 339 | if [ "${ENABLE_FIX}" = "1" ] && [ "${MY_FIX}" = "1" ]; then 340 | for _bin in ${REQUIRED_FIX_BINS}; do 341 | if ! command -v "${_bin}" >/dev/null 2>&1; then 342 | echo "[ERR] Required --fix binary '${_bin}' not found." 343 | _ret2=1 344 | else 345 | if [ "${_debug}" = "1" ]; then 346 | echo "[OK] Required --fix binary '${_bin}' found." 347 | fi 348 | fi 349 | done 350 | fi 351 | 352 | 353 | return $((_ret1 + _ret2)) 354 | } 355 | 356 | check_config_file() { 357 | _config="${1}" 358 | 359 | # Check config file 360 | if [ ! -f "${_config}" ]; then 361 | echo "[CONFIG] Config file not found: ${_config}" 362 | return 1 363 | fi 364 | 365 | # Check directives 366 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=" "${_config}"; then 367 | echo "[CONFIG] ${MY_CONF_PRE}IGNORE variable not found in config." 368 | return 1 369 | fi 370 | if ! grep -Eq "^${MY_CONF_PRE}IGNORE=[\"']{1}.*[\"']{1}$" "${_config}"; then 371 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}IGNORE variable." 372 | return 1 373 | fi 374 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=" "${_config}"; then 375 | echo "[CONFIG] ${MY_CONF_PRE}EXTENSION variable not found in config." 376 | return 1 377 | fi 378 | if ! grep -Eq "^${MY_CONF_PRE}EXTENSION=[\"']{1}.*[\"']{1}$" "${_config}"; then 379 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}EXTENSION variable." 380 | return 1 381 | fi 382 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=" "${_config}"; then 383 | echo "[CONFIG] ${MY_CONF_PRE}TEXT variable not found in config." 384 | return 1 385 | fi 386 | if ! grep -Eq "^${MY_CONF_PRE}TEXT=[\"']*[01]{1}[\"']*$" "${_config}"; then 387 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}TEXT variable." 388 | return 1 389 | fi 390 | 391 | # Check optional directives 392 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 393 | if ! grep -Eq "^${MY_CONF_PRE}CUSTOM=[\"']{1}.*[\"']{1}$" "${_config}"; then 394 | echo "[CONFIG] Invalid syntax for ${MY_CONF_PRE}CUSTOM variable." 395 | return 1 396 | fi 397 | fi 398 | 399 | } 400 | 401 | 402 | # 403 | # System independent method 404 | # to get number of CPU cores. 405 | # (defaults to 1 if impossible) 406 | # 407 | num_cpu() { 408 | if ! _num="$( getconf _NPROCESSORS_ONLN 2>/dev/null )"; then 409 | echo "1" 410 | else 411 | echo "${_num}" 412 | fi 413 | } 414 | 415 | 416 | # 417 | # sed wrapper that automatically escapes 418 | # regex literals 419 | # 420 | mysed() { 421 | _input="$1" 422 | _search="$2" 423 | _replace="$3" 424 | 425 | echo "${_input}" | sed "s/$(echo "${_search}" | sed -e 's/\([[\/.*]\|\]\)/\\&/g')/$(echo "${_replace}" | sed -e 's/[\/&]/\\&/g')/g" 426 | } 427 | 428 | 429 | 430 | 431 | ################################################################################ 432 | # 433 | # M A I N E N T R Y P O I N T 434 | # 435 | ################################################################################ 436 | 437 | 438 | 439 | ############################################################ 440 | # Command Line arguments 441 | ############################################################ 442 | 443 | 444 | # 445 | # Read command line arguments 446 | # 447 | while [ $# -gt 0 ]; do 448 | case "${1}" in 449 | 450 | # ---------------------------------------- 451 | --path=*) 452 | MY_PATH="${1//--path=/}" 453 | ;; 454 | 455 | # ---------------------------------------- 456 | --shebang=*) 457 | MY_SHE="${1//--shebang=/}" 458 | ;; 459 | 460 | # ---------------------------------------- 461 | --extension=*) 462 | MY_EXT="${1//--extension=/}" 463 | ;; 464 | 465 | # ---------------------------------------- 466 | --ignore=*) 467 | MY_IGN="${1//--ignore=/}" 468 | ;; 469 | 470 | # ---------------------------------------- 471 | --config=*) 472 | MY_CFG="${1//--config=/}" 473 | ;; 474 | 475 | # ---------------------------------------- 476 | --confpre=*) 477 | MY_CONF_PRE="${1//--confpre=/}" 478 | ;; 479 | 480 | # ---------------------------------------- 481 | --custom=*) 482 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 483 | MY_CUS="${1//--custom=/}" 484 | else 485 | echo "Invalid argument: ${1}" 486 | echo "Type '${MY_NAME} --help' for available options." 487 | exit 1 488 | fi 489 | ;; 490 | 491 | # ---------------------------------------- 492 | --fix) 493 | if [ "${ENABLE_FIX}" = "1" ]; then 494 | MY_FIX=1 495 | else 496 | echo "Invalid argument: ${1}" 497 | echo "Type '${MY_NAME} --help' for available options." 498 | exit 1 499 | fi 500 | ;; 501 | 502 | 503 | # ---------------------------------------- 504 | --text) 505 | MY_TXT=1 506 | ;; 507 | 508 | # ---------------------------------------- 509 | --size) 510 | MY_SIZ=1 511 | ;; 512 | 513 | # ---------------------------------------- 514 | --dry) 515 | MY_DRY=1 516 | ;; 517 | 518 | # ---------------------------------------- 519 | --list) 520 | MY_LST=1 521 | ;; 522 | 523 | # ---------------------------------------- 524 | --verbose) 525 | MY_VER=1 526 | ;; 527 | 528 | # ---------------------------------------- 529 | --debug) 530 | MY_DEB=1 531 | ;; 532 | 533 | # ---------------------------------------- 534 | --info) 535 | if ! check_requirements "${MY_DEB}"; then 536 | exit 1 537 | fi 538 | 539 | if ! print_info; then 540 | exit 1 541 | fi 542 | 543 | exit 0 544 | ;; 545 | 546 | # ---------------------------------------- 547 | --help) 548 | print_usage 549 | exit 0 550 | ;; 551 | 552 | # ---------------------------------------- 553 | --version) 554 | print_version 555 | exit 0 556 | ;; 557 | 558 | # ---------------------------------------- 559 | *) 560 | echo "Invalid argument: ${1}" 561 | echo "Type '${MY_NAME} --help' for available options." 562 | exit 1 563 | ;; 564 | esac 565 | shift 566 | done 567 | 568 | 569 | 570 | ############################################################ 571 | # Sanity Checks 572 | ############################################################ 573 | 574 | # 575 | # Check general requirements 576 | # 577 | if ! check_requirements "${MY_DEB}"; then 578 | exit 1 579 | fi 580 | 581 | # 582 | # Check path 583 | # 584 | if [ "${MY_PATH}" = "" ]; then 585 | echo "--path not specified" 586 | echo "Type '${MY_NAME} --help' for available options." 587 | exit 1 588 | fi 589 | if [ ! -e "${MY_PATH}" ]; then 590 | echo "Specified path does not exist: '${MY_PATH}'." 591 | echo "Type '${MY_NAME} --help' for available options." 592 | exit 1 593 | fi 594 | 595 | 596 | # 597 | # Check and load config if desired 598 | # 599 | if [ "${MY_CFG}" != "" ]; then 600 | if ! check_config_file "${MY_CFG}"; then 601 | exit 1 602 | fi 603 | 604 | . "${MY_CFG}" 605 | fi 606 | 607 | 608 | 609 | ############################################################ 610 | # Evaluate Settings 611 | ############################################################ 612 | 613 | CPU_CORES="$(num_cpu)" 614 | 615 | 616 | # Var substitutions for config file directives 617 | # to match current program. 618 | EXTENSION="${MY_CONF_PRE}EXTENSION" 619 | IGNORE="${MY_CONF_PRE}IGNORE" 620 | TEXT="${MY_CONF_PRE}TEXT" 621 | SIZE="${MY_CONF_PRE}SIZE" 622 | CUSTOM="${MY_CONF_PRE}CUSTOM" 623 | 624 | # 625 | # Decide on Shebang 626 | # 627 | if [ "${MY_SHE}" != "" ]; then 628 | MY_SHE="xargs -0 -P ${CPU_CORES} -n1 awk '/^#!.*(\/${MY_SHE}|[[:space:]]+${MY_SHE})/{print FILENAME}'" 629 | else 630 | MY_SHE="" 631 | fi 632 | 633 | 634 | 635 | # 636 | # Decide on File extensions 637 | # 638 | if [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" != "0" ]; then 639 | if [ "${MY_DEB}" = "1" ]; then 640 | echo "[ARG] Cmd arg --extension=${MY_EXT} will take precedence over config file value". 641 | fi 642 | MY_EXT="${MY_EXT}" 643 | 644 | elif [ "${MY_CFG}" != "" ] && [ "${MY_EXT}" = "0" ]; then 645 | if [ "${MY_DEB}" = "1" ]; then 646 | echo "[ARG] Using config file values: ext: ${!EXTENSION}" 647 | fi 648 | MY_EXT="${!EXTENSION}" 649 | 650 | elif [ "${MY_CFG}" = "" ] && [ "${MY_EXT}" != "0" ]; then 651 | if [ "${MY_DEB}" = "1" ]; then 652 | echo "[ARG] Using cmd argument: ext: '${MY_EXT}'" 653 | fi 654 | MY_EXT="${MY_EXT}" 655 | 656 | else 657 | if [ "${MY_DEB}" = "1" ]; then 658 | echo "[ARG] Using all file extensions" 659 | fi 660 | MY_EXT= 661 | fi 662 | 663 | 664 | # 665 | # Decide on ignore paths 666 | # 667 | if [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" != "" ]; then 668 | if [ "${MY_DEB}" = "1" ]; then 669 | echo "[ARG] Cmd arg --ignore=${MY_IGN} will take precedence over config file value". 670 | fi 671 | MY_IGN="${MY_IGN}" 672 | 673 | elif [ "${MY_CFG}" != "" ] && [ "${MY_IGN}" = "" ]; then 674 | if [ "${MY_DEB}" = "1" ]; then 675 | echo "[ARG] Using config file values: ignore: ${!IGNORE}" 676 | fi 677 | MY_IGN="${!IGNORE}" 678 | 679 | elif [ "${MY_CFG}" = "" ] && [ "${MY_IGN}" != "" ]; then 680 | if [ "${MY_DEB}" = "1" ]; then 681 | echo "[ARG] Using cmd argument: ignore: ${MY_IGN}" 682 | fi 683 | MY_IGN="${MY_IGN}" 684 | 685 | else 686 | if [ "${MY_DEB}" = "1" ]; then 687 | echo "[ARG] Not ignoring anything" 688 | fi 689 | MY_IGN= 690 | fi 691 | 692 | 693 | # 694 | # Decide on text files (non-binary) or all files 695 | # 696 | if [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" != "0" ]; then 697 | if [ "${MY_DEB}" = "1" ]; then 698 | echo "[ARG] Cmd arg --text: '${MY_TXT}' will take precedence over config file value". 699 | fi 700 | MY_TXT="${MY_TXT}" 701 | 702 | elif [ "${MY_CFG}" != "" ] && [ "${MY_TXT}" = "0" ]; then 703 | if [ "${MY_DEB}" = "1" ]; then 704 | echo "[ARG] Using config file values: --text: ${!TEXT}" 705 | fi 706 | MY_TXT="${!TEXT}" 707 | 708 | elif [ "${MY_CFG}" = "" ] && [ "${MY_TXT}" != "0" ]; then 709 | if [ "${MY_DEB}" = "1" ]; then 710 | echo "[ARG] Using cmd argument: --text: ${MY_TXT}" 711 | fi 712 | MY_TXT="${MY_TXT}" 713 | 714 | else 715 | if [ "${MY_DEB}" = "1" ]; then 716 | echo "[ARG] Not narrowing down by text files" 717 | fi 718 | MY_TXT="0" 719 | fi 720 | 721 | 722 | # 723 | # Decide on file size 724 | # 725 | if [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" != "0" ]; then 726 | if [ "${MY_DEB}" = "1" ]; then 727 | echo "[ARG] Cmd arg --size: '${MY_SIZ}' will take precedence over config file value". 728 | fi 729 | MY_SIZ="${MY_SIZ}" 730 | 731 | elif [ "${MY_CFG}" != "" ] && [ "${MY_SIZ}" = "0" ]; then 732 | if [ "${MY_DEB}" = "1" ]; then 733 | echo "[ARG] Using config file values: --size: ${!SIZE}" 734 | fi 735 | MY_SIZ="${!SIZE}" 736 | 737 | elif [ "${MY_CFG}" = "" ] && [ "${MY_SIZ}" != "0" ]; then 738 | if [ "${MY_DEB}" = "1" ]; then 739 | echo "[ARG] Using cmd argument: --size: ${MY_SIZ}" 740 | fi 741 | MY_SIZ="${MY_SIZ}" 742 | 743 | else 744 | if [ "${MY_DEB}" = "1" ]; then 745 | echo "[ARG] Not narrowing down by size > 0 bytes" 746 | fi 747 | MY_SIZ="0" 748 | fi 749 | 750 | if [ "${MY_SIZ}" = "1" ]; then 751 | MY_SIZ="! -size 0" 752 | else 753 | MY_SIZ="" 754 | fi 755 | 756 | 757 | 758 | # 759 | # Decide on Custom string 760 | # 761 | if [ "${ENABLE_CUST_OPS}" = "1" ]; then 762 | if [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" != "" ]; then 763 | if [ "${MY_DEB}" = "1" ]; then 764 | echo "[ARG] Cmd arg --custom=\"${MY_CUS}\" will take precedence over config file value". 765 | fi 766 | MY_CUS="${MY_CUS}" 767 | 768 | elif [ "${MY_CFG}" != "" ] && [ "${MY_CUS}" = "" ]; then 769 | if [ "${MY_DEB}" = "1" ]; then 770 | echo "[ARG] Using config file values: custom: \"${!CUSTOM}\"" 771 | fi 772 | MY_CUS="${!CUSTOM}" 773 | 774 | elif [ "${MY_CFG}" = "" ] && [ "${MY_CUS}" != "" ]; then 775 | if [ "${MY_DEB}" = "1" ]; then 776 | echo "[ARG] Using cmd argument: custom: \"${MY_CUS}\"" 777 | fi 778 | MY_CUS="${MY_CUS}" 779 | 780 | else 781 | if [ "${MY_DEB}" = "1" ]; then 782 | echo "[ARG] No customization applied" 783 | fi 784 | MY_CUS= 785 | fi 786 | fi 787 | 788 | 789 | 790 | ############################################################ 791 | # Build command 792 | ############################################################ 793 | 794 | # 795 | # 'find' pattern for file extensions 796 | # 797 | if [ "${MY_EXT}" != "" ]; then 798 | NAME_PATTERN="\( -iname \*.${MY_EXT//,/ -o -iname \\*.} \)" 799 | else 800 | NAME_PATTERN="" 801 | fi 802 | 803 | # 804 | # 'find' pattern for ignores/excludes 805 | # 806 | if [ "${MY_IGN}" != "" ]; then 807 | EXCL_PATTERN="-not \( -path \"${MY_PATH}/${MY_IGN//,/*\" -o -path \"${MY_PATH}\/}*\" \)" 808 | else 809 | EXCL_PATTERN="" 810 | fi 811 | 812 | 813 | # 814 | # Fix? 815 | # 816 | if [ "${MY_FIX}" = "1" ]; then 817 | MY_CHECK="${MY_FIX_CMD}" 818 | else 819 | # 820 | # Normal check 821 | # (Apply custom command?) 822 | # 823 | if [ "${MY_CUS}" = "" ]; then 824 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${DEFAULT_CUST_OPS}" )" 825 | else 826 | MY_CHECK="$( mysed "${MY_CHECK}" "__CUSTOM_OPT_PLACEHOLDER__" "${MY_CUS}" )" 827 | fi 828 | fi 829 | 830 | 831 | # 832 | # Show files or grep in found files? 833 | # 834 | 835 | 836 | # Be verbose? 837 | if [ "${MY_VER}" = "1" ]; then 838 | XARGS_VERBOSE="-t" 839 | else 840 | XARGS_VERBOSE="" 841 | fi 842 | 843 | # 844 | # Build command 845 | # 846 | 847 | 848 | ### Text files (list-only) 849 | if [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "1" ]; then 850 | if [ "${MY_SHE}" != "" ]; then 851 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE}" 852 | else 853 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il ''" 854 | fi 855 | 856 | ### Text files (run!!!) 857 | elif [ "${MY_TXT}" = "1" ] && [ "${MY_LST}" = "0" ]; then 858 | if [ "${MY_SHE}" != "" ]; then 859 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 860 | else 861 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 grep -Il '' | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 862 | fi 863 | 864 | ### All files (list-only) 865 | elif [ "${MY_TXT}" = "0" ] && [ "${MY_LST}" = "1" ]; then 866 | if [ "${MY_SHE}" != "" ]; then 867 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE}" 868 | else 869 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print" 870 | fi 871 | 872 | 873 | ### All files (run!!!) 874 | else 875 | if [ "${MY_SHE}" != "" ]; then 876 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | ${MY_SHE} | tr '\n' '\0' | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 877 | else 878 | MY_CMD="find ${MY_PATH} -type f ${NAME_PATTERN} ${EXCL_PATTERN} ${MY_SIZ} -print0 | xargs -0 -P ${CPU_CORES} -n1 ${XARGS_VERBOSE} sh -c 'if [ -f \"\${1}\" ]; then ${MY_CHECK}; fi' --" 879 | fi 880 | 881 | fi 882 | 883 | 884 | 885 | 886 | ############################################################ 887 | # Execute 888 | ############################################################ 889 | 890 | # Dry mode? 891 | if [ "${MY_DRY}" = "1" ]; then 892 | printf "%s\n" "${MY_CMD}" 893 | exit 0 894 | fi 895 | 896 | printf "\$ %s\n" "${MY_CMD}" 897 | 898 | output="$(eval "${MY_CMD}")" 899 | 900 | # If showing files only, exit normally 901 | if [ "${MY_LST}" = "1" ]; then 902 | printf "%s\n" "${output}" 903 | exit 0 904 | fi 905 | 906 | 907 | if [ "${output}" != "" ]; then 908 | printf "%s\n" "${output}" 909 | printf "${CLR_ERR}[ERR] %s${CLR_CLS}\n" "${MY_FINISH_ERR}" 910 | exit 1 911 | else 912 | printf "${CLR_SUC}[OK] %s${CLR_CLS}\n" "${MY_FINISH_OK}" 913 | exit 0 914 | fi 915 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cytopia/awesome-ci", 3 | "description": "Lot's of tools for git, file and static source code analysis.", 4 | "type": "library", 5 | "keywords": ["continuous integration", "linter", "regex"], 6 | "homepage": "https://github.com/cytopia/awesome-ci", 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name" : "cytopia", 11 | "homepage": "https://github.com/cytopia/awesome-ci", 12 | "role": "Developer" 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /configure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This is a leight-weight self-styled configure script 4 | 5 | 6 | PREFIX="" 7 | 8 | print_help() { 9 | 10 | echo "Usage: configure [--prefix]" 11 | echo "" 12 | echo "--prefix Specify custom install prefix." 13 | echo " e.g. --prefix=/usr/local" 14 | echo "" 15 | } 16 | 17 | 18 | while [ $# -gt 0 ]; do 19 | 20 | case "$1" in 21 | 22 | --help) 23 | print_help 24 | exit 0 25 | ;; 26 | 27 | --prefix*) 28 | CUSTOM_PREFIX="$(echo "$1" | $(which sed) 's/^--prefix=//g')" 29 | # Remove trailing slash 30 | CUSTOM_PREFIX="/$(echo "${CUSTOM_PREFIX}" | $(which sed) 's#/*$##;s#^/*##')" 31 | PREFIX="${CUSTOM_PREFIX}" 32 | ;; 33 | 34 | *) 35 | echo "Invalid argument: '${1}'" 36 | echo "Type '${0} --help' for available options." 37 | exit 1 38 | ;; 39 | esac 40 | shift 41 | done 42 | 43 | 44 | if [ -z "${PREFIX}" ]; then 45 | BINDIR="/usr/bin" 46 | else 47 | BINDIR="${PREFIX}/bin" 48 | fi 49 | 50 | 51 | 52 | # Write configure configuration file 53 | echo "PREFIX = ${PREFIX}" > configure.in 54 | echo "ETCDIR = ${ETCDIR}" >> configure.in 55 | echo "BINDIR = ${BINDIR}" >> configure.in 56 | echo "MANDIR = ${MANDIR}" >> configure.in 57 | 58 | echo "" 59 | echo "Configure run successfully" 60 | echo "" 61 | if [ -z "${PREFIX}" ]; then 62 | echo " Install prefix: /" 63 | else 64 | echo " Install prefix: ${PREFIX}" 65 | fi 66 | echo "" 67 | echo " ${BINDIR}/" 68 | echo "" 69 | echo "Run 'make install' to install" 70 | exit 0 71 | -------------------------------------------------------------------------------- /dependencies/README.md: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | 3 | Files in here must be placed in an executable path, such as `/usr/bin` or `/usr/local/bin` and must be executable. 4 | 5 | Those files are needed, as the command itself could not have been placed inside `sh -c ""` in the corresponding check due to the system's limit of command line argument length. 6 | -------------------------------------------------------------------------------- /dependencies/aci-trailing-newline: -------------------------------------------------------------------------------- 1 | #!/bin/sh -u 2 | 3 | NAME="aci-trailing-newline" 4 | 5 | 6 | 7 | print_usage() { 8 | echo "Usage: ${NAME} -n file" 9 | echo " ${NAME} -1 file" 10 | echo " ${NAME} -v" 11 | echo 12 | echo "Validates if a file has at least 1 or exactly only 1 trailing newline." 13 | echo "Returns 0, if condition is met, otherwise > 0" 14 | echo 15 | echo " -n Must have at least 1 trailing newline at the end of the file." 16 | echo " -1 Must have exactly only 1 trailing newline at the end of the file." 17 | echo " -v Show version" 18 | exit 1 19 | } 20 | print_version() { 21 | echo "${NAME} v0.1 (2016-08-21)" 22 | echo "Written by cytopia " 23 | echo "https://github.com/cytopia" 24 | } 25 | 26 | if [ "${#}" = "1" ] && [ "${1}" = "-v" ]; then 27 | print_version 28 | exit 0 29 | fi 30 | 31 | if [ "${#}" != "2" ]; then 32 | print_usage 33 | exit 1 34 | fi 35 | if [ "${1}" != "-n" ] && [ "${1}" != "-1" ]; then 36 | print_usage 37 | exit 1 38 | fi 39 | 40 | OPTION="${1}" 41 | FILE="${2}" 42 | 43 | # 44 | # Validate file 45 | # 46 | if [ ! -f "${FILE}" ]; then 47 | echo "No such file: ${FILE}" 48 | exit 1 49 | fi 50 | if [ ! -r "${FILE}" ]; then 51 | echo "Cannot read file: ${FILE}" 52 | exit 1 53 | fi 54 | 55 | 56 | 57 | # No trailing newline at the end of the file 58 | if ! tail -c 1 "${FILE}" | grep -qE "^$"; then 59 | exit 2 60 | fi 61 | 62 | 63 | # Check if only 1 trailing newline 64 | if [ "${OPTION}" = "-1" ]; then 65 | 66 | # At least two newlines at the end of the file 67 | if tail -c 2 "${FILE}" | grep -qE "^$"; then 68 | exit 3 69 | fi 70 | 71 | fi 72 | 73 | exit 0 74 | -------------------------------------------------------------------------------- /etc/awesome-ci.conf: -------------------------------------------------------------------------------- 1 | # 2 | # Awesome-ci configuration file 3 | # 4 | # Each tool will have its own config section 5 | # which all behave in the same way: 6 | # 7 | # 8 | # 1. File extensions 9 | # ------------------ 10 | # Comma separated list of file extensions 11 | # to narrow down the files to check. 12 | # _EXTENSION="" 13 | # _EXTENSION="tpl,html" 14 | # 15 | # 2. Ignored paths 16 | # ---------------- 17 | # Comma separated list of file paths 18 | # to narrow down the files to check. 19 | # Note that those paths must start at the 20 | # path where --path starts. 21 | # _IGNORE="" 22 | # _IGNORE="tmp/log,tmp/run" 23 | # 24 | # 3. Text files 25 | # ------------- 26 | # 0 or 1 to specify whether to work on text files 27 | # only. 28 | # _TEXT=0 29 | # _TEXT=1 30 | 31 | 32 | 33 | 34 | # 35 | # Custom/generic regexer 36 | # 37 | 38 | # Perl 39 | REGEX_PERL_EXTENSION="" 40 | REGEX_PERL_IGNORE=".git,*.svn" 41 | REGEX_PERL_TEXT=1 42 | REGEX_PERL_SIZE=1 43 | REGEX_PERL_CUSTOM="" 44 | 45 | # Grep 46 | REGEX_GREP_EXTENSION="" 47 | REGEX_GREP_IGNORE=".git,*.svn" 48 | REGEX_GREP_TEXT=1 49 | REGEX_GREP_SIZE=1 50 | REGEX_GREP_CUSTOM="" 51 | 52 | 53 | 54 | # 55 | # File checkers 56 | # 57 | # file-cr 58 | FILE_CR_EXTENSION="" 59 | FILE_CR_IGNORE=".git,*.svn" 60 | FILE_CR_TEXT=1 61 | FILE_CR_SIZE=1 62 | 63 | # file-crlf 64 | FILE_CRLF_EXTENSION="" 65 | FILE_CRLF_IGNORE=".git,*.svn" 66 | FILE_CRLF_TEXT=1 67 | FILE_CRLF_SIZE=1 68 | 69 | # file-empty 70 | FILE_EMPTY_EXTENSION="" 71 | FILE_EMPTY_IGNORE=".git,*.svn" 72 | FILE_EMPTY_TEXT=0 73 | FILE_EMPTY_SIZE=0 74 | 75 | # file-crlf 76 | FILE_NULLBYTE_EXTENSION="" 77 | FILE_NULLBYTE_IGNORE=".git,*.svn,*.pyc" 78 | FILE_NULLBYTE_TEXT=0 79 | FILE_NULLBYTE_SIZE=1 80 | 81 | # file-trailing-newline 82 | FILE_TRAILING_NEWLINE_EXTENSION="" 83 | FILE_TRAILING_NEWLINE_IGNORE=".git,*.svn" 84 | FILE_TRAILING_NEWLINE_TEXT=1 85 | FILE_TRAILING_NEWLINE_SIZE=1 86 | 87 | # file-trailing-single-newline 88 | FILE_TRAILING_SINGLE_NEWLINE_EXTENSION="" 89 | FILE_TRAILING_SINGLE_NEWLINE_IGNORE=".git,*.svn" 90 | FILE_TRAILING_SINGLE_NEWLINE_TEXT=1 91 | FILE_TRAILING_SINGLE_NEWLINE_SIZE=1 92 | 93 | # file-trailing-space 94 | FILE_TRAILING_SPACE_EXTENSION="" 95 | FILE_TRAILING_SPACE_IGNORE=".git,*.svn" 96 | FILE_TRAILING_SPACE_TEXT=1 97 | FILE_TRAILING_SPACE_SIZE=1 98 | 99 | # file-utf8 100 | FILE_UTF8_EXTENSION="" 101 | FILE_UTF8_IGNORE=".git,*.svn" 102 | FILE_UTF8_TEXT=1 103 | FILE_UTF8_SIZE=1 104 | 105 | # file-utf8-bom 106 | FILE_UTF8_BOM_EXTENSION="" 107 | FILE_UTF8_BOM_IGNORE=".git,*.svn" 108 | FILE_UTF8_BOM_TEXT=1 109 | FILE_UTF8_BOM_SIZE=1 110 | 111 | 112 | 113 | # 114 | # Git checkers 115 | # 116 | 117 | # git-conflicts 118 | GIT_CONFLICTS_EXTENSION="" 119 | GIT_CONFLICTS_IGNORE=".git,*.svn" 120 | GIT_CONFLICTS_TEXT=1 121 | GIT_CONFLICTS_SIZE=1 122 | 123 | 124 | 125 | # 126 | # Inline code checkers 127 | # 128 | 129 | # inline-css 130 | INLINE_CSS_EXTENSION="php,tpl,htm,html" 131 | INLINE_CSS_IGNORE=".git,*.svn" 132 | INLINE_CSS_TEXT=1 133 | INLINE_CSS_SIZE=1 134 | 135 | # inline-js 136 | INLINE_JS_EXTENSION="php,tpl,htm,html" 137 | INLINE_JS_IGNORE=".git,*.svn" 138 | INLINE_JS_TEXT=1 139 | INLINE_JS_SIZE=1 140 | 141 | 142 | 143 | # 144 | # Syntax error checkers 145 | # 146 | 147 | # syntax-bash 148 | SYNTAX_BASH_EXTENSION="sh,bash" 149 | SYNTAX_BASH_IGNORE=".git,*.svn" 150 | SYNTAX_BASH_TEXT=1 151 | SYNTAX_BASH_SIZE=1 152 | 153 | # syntax-css 154 | SYNTAX_CSS_EXTENSION="css" 155 | SYNTAX_CSS_IGNORE=".git,*.svn" 156 | SYNTAX_CSS_TEXT=1 157 | SYNTAX_CSS_SIZE=1 158 | SYNTAX_CSS_CUSTOM="--color --include-linter \"\"" 159 | 160 | # syntax-js 161 | SYNTAX_JS_EXTENSION="js" 162 | SYNTAX_JS_IGNORE=".git,*.svn" 163 | SYNTAX_JS_TEXT=1 164 | SYNTAX_JS_SIZE=1 165 | SYNTAX_JS_CUSTOM="--color --no-eslintrc --quiet" 166 | 167 | # syntax-json 168 | SYNTAX_JSON_EXTENSION="json" 169 | SYNTAX_JSON_IGNORE=".git,*.svn" 170 | SYNTAX_JSON_TEXT=1 171 | SYNTAX_JSON_SIZE=1 172 | SYNTAX_JSON_CUSTOM="-c -q" 173 | 174 | # syntax-markdown 175 | SYNTAX_MARKDOWN_EXTENSION="md" 176 | SYNTAX_MARKDOWN_IGNORE=".git,*.svn" 177 | SYNTAX_MARKDOWN_TEXT=1 178 | SYNTAX_MARKDOWN_SIZE=1 179 | SYNTAX_MARKDOWN_CUSTOM="" 180 | 181 | # syntax-perl 182 | SYNTAX_PERL_EXTENSION="pl" 183 | SYNTAX_PERL_IGNORE=".git,*.svn" 184 | SYNTAX_PERL_TEXT=1 185 | SYNTAX_PERL_SIZE=1 186 | 187 | # syntax-php 188 | SYNTAX_PHP_EXTENSION="php,tpl,inc" 189 | SYNTAX_PHP_IGNORE=".git,*.svn" 190 | SYNTAX_PHP_TEXT=1 191 | SYNTAX_PHP_SIZE=1 192 | SYNTAX_PHP_CUSTOM="-d display_errors=1 -d error_reporting=-1" 193 | 194 | # syntax-python 195 | SYNTAX_PYTHON_EXTENSION="py" 196 | SYNTAX_PYTHON_IGNORE=".git,*.svn" 197 | SYNTAX_PYTHON_TEXT=1 198 | SYNTAX_PYTHON_SIZE=1 199 | 200 | # syntax-ruby 201 | SYNTAX_RUBY_EXTENSION="rb" 202 | SYNTAX_RUBY_IGNORE=".git,*.svn" 203 | SYNTAX_RUBY_TEXT=1 204 | SYNTAX_RUBY_SIZE=1 205 | 206 | # syntax-scss 207 | SYNTAX_SCSS_EXTENSION="scss" 208 | SYNTAX_SCSS_IGNORE=".git,*.svn" 209 | SYNTAX_SCSS_TEXT=1 210 | SYNTAX_SCSS_SIZE=1 211 | SYNTAX_SCSS_CUSTOM="--color --include-linter \"\"" 212 | 213 | # syntax-sh 214 | SYNTAX_SH_EXTENSION="sh,bash" 215 | SYNTAX_SH_IGNORE=".git,*.svn" 216 | SYNTAX_SH_TEXT=1 217 | SYNTAX_SH_SIZE=1 218 | -------------------------------------------------------------------------------- /test/README.md: -------------------------------------------------------------------------------- 1 | # Awesome-CI test cases 2 | 3 | This directory contains test cases for awesome-ci. 4 | -------------------------------------------------------------------------------- /test/err/file-cr_err: -------------------------------------------------------------------------------- 1 | ------- MIIDuDCCAqACAQAwgegxCzAJBgNVBA 2 | -------------------------------------------------------------------------------- /test/err/file-crlf_err: -------------------------------------------------------------------------------- 1 | LINE1 2 | LINE2 3 | LINE3 4 | -------------------------------------------------------------------------------- /test/err/file-empty_err: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/awesome-ci/f84b19d496b6d8e316d05b4c25f0a0b86d907d81/test/err/file-empty_err -------------------------------------------------------------------------------- /test/err/file-nullbyte-char_err.bin: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if ! run "git-conflicts --config=.awesome-ci.conf --path=."; then 4 | # This line contains a \0 (null byte character) 5 | printf "${CLR_ERR}[%s]${CLR_CLS}\n" "FAILED" 6 | ERRNO=$((ERRNO + 1)) 7 | fi 8 | -------------------------------------------------------------------------------- /test/err/file-trailing-newline_err: -------------------------------------------------------------------------------- 1 | This file does not have a trailing newline -------------------------------------------------------------------------------- /test/err/file-trailing-single-newline_err: -------------------------------------------------------------------------------- 1 | This file does not have a single trailing newline, 2 | but much more 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /test/err/file-trailing-space_err: -------------------------------------------------------------------------------- 1 | A lot 2 | of trailing 3 | space 4 | -------------------------------------------------------------------------------- /test/err/file-utf8-bom_err: -------------------------------------------------------------------------------- 1 | This file contains BOM 2 | -------------------------------------------------------------------------------- /test/err/file-utf8_err: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cytopia/awesome-ci/f84b19d496b6d8e316d05b4c25f0a0b86d907d81/test/err/file-utf8_err -------------------------------------------------------------------------------- /test/err/git-conflicts_err: -------------------------------------------------------------------------------- 1 | the number of planets are 2 | <<<<<<< HEAD 3 | nine 4 | ======= 5 | eight 6 | >>>>>>> branch-a 7 | -------------------------------------------------------------------------------- /test/err/inline-css_err.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 2 | 3 | 4 | test 5 | 6 | 2 | 3 | 4 | 5 | 6 | 2 | 3 | 4 | 5 | 6 | &2 echo "This script requires exactly one argument: ${#} are given." 27 | exit 1 28 | fi 29 | 30 | # Path to binary 31 | BINARY="${BIN_PATH}/${1}" 32 | 33 | 34 | ############################################################ 35 | # Functions 36 | ############################################################ 37 | 38 | run () { 39 | local cmd="${1}" 40 | 41 | >&2 echo "----------------------------------------------------------------------------------------------------" 42 | >&2 echo "\$ ${cmd}" 43 | >&2 echo "----------------------------------------------------------------------------------------------------" 44 | 45 | ${cmd} 46 | } 47 | 48 | 49 | ############################################################ 50 | # Run tests 51 | ############################################################ 52 | 53 | 54 | ### 55 | ### 1. Info 56 | ### 57 | COMMAND="${BINARY} --info" 58 | if ! OUT="$( run "${COMMAND}" )"; then 59 | echo "${OUT}" 60 | >&2 echo "[Error] 'Info test' failed" 61 | exit 1 62 | fi 63 | echo "[TEST PASSED]" 64 | echo 65 | 66 | 67 | ### 68 | ### 2. Dry 69 | ### 70 | if [ "${1}" = "git-ignored" ]; then 71 | COMMAND="${BINARY} --path=. --dry" 72 | else 73 | COMMAND="${BINARY} --path=. --config=${ETC_PATH} --dry" 74 | fi 75 | if ! OUT="$( run "${COMMAND}" )"; then 76 | echo "${OUT}" 77 | >&2 echo "[TEST FAILED] 'Dry test' failed" 78 | exit 1 79 | fi 80 | echo "[TEST PASSED]" 81 | echo 82 | 83 | 84 | ### 85 | ### 3. Test OK 86 | ### 87 | if [ "${1}" != "git-ignored" ] && [ "${1}" != "regex-grep" ] && [ "${1}" != "regex-perl" ]; then 88 | 89 | COMMAND="${BINARY} --path=${TEST_SUCC_PATH} --config=${ETC_PATH}" 90 | 91 | if ! OUT="$( run "${COMMAND} --list" )"; then 92 | echo "${OUT}" 93 | >&2 echo "[TEST FAILED] 'Success test' failed" 94 | exit 1 95 | fi 96 | echo "[TEST PASSED]" 97 | echo 98 | 99 | if ! OUT="$( run "${COMMAND} --verbose" )"; then 100 | echo "${OUT}" 101 | >&2 echo "[TEST FAILED] 'Success test' failed" 102 | exit 1 103 | fi 104 | echo "[TEST PASSED]" 105 | echo 106 | 107 | if ! OUT="$( run "${COMMAND}" )"; then 108 | echo "${OUT}" 109 | >&2 echo "[TEST FAILED] 'Success test' failed" 110 | exit 1 111 | fi 112 | echo "[TEST PASSED]" 113 | echo 114 | fi 115 | 116 | 117 | ### 118 | ### 3. Test Failure 119 | ### 120 | if [ "${1}" != "git-ignored" ] && [ "${1}" != "regex-grep" ] && [ "${1}" != "regex-perl" ]; then 121 | 122 | COMMAND="${BINARY} --path=${TEST_FAIL_PATH} --config=${ETC_PATH}" 123 | 124 | if ! OUT="$( run "${COMMAND} --verbose" )"; then 125 | echo "[TEST PASSED]" 126 | echo 127 | else 128 | echo "${OUT}" 129 | >&2 echo "[TEST FAILED] 'Failure test' failed" 130 | exit 1 131 | fi 132 | 133 | if ! OUT="$( run "${COMMAND}" )"; then 134 | echo "[TEST PASSED]" 135 | echo 136 | else 137 | echo "${OUT}" 138 | >&2 echo "[TEST FAILED] 'Failure test' failed" 139 | exit 1 140 | fi 141 | fi 142 | --------------------------------------------------------------------------------