mirror of
https://github.com/asdf-vm/asdf.git
synced 2024-11-15 01:28:17 -07:00
fix: enforce consistent shell redirection format (#1533)
This commit is contained in:
parent
a1bc0e97cd
commit
1bc205e8aa
@ -11,7 +11,7 @@ remove_shim_for_version() {
|
|||||||
local count_installed
|
local count_installed
|
||||||
count_installed=$(list_installed_versions "$plugin_name" | wc -l)
|
count_installed=$(list_installed_versions "$plugin_name" | wc -l)
|
||||||
|
|
||||||
if ! grep -x "# asdf-plugin: $plugin_name $version" "$shim_path" >/dev/null 2>&1; then
|
if ! grep -x "# asdf-plugin: $plugin_name $version" "$shim_path" &>/dev/null; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
@ -25,9 +25,9 @@ install_command() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get_concurrency() {
|
get_concurrency() {
|
||||||
if command -v nproc >/dev/null 2>&1; then
|
if command -v nproc &>/dev/null; then
|
||||||
nproc
|
nproc
|
||||||
elif command -v sysctl >/dev/null 2>&1 && sysctl hw.ncpu >/dev/null 2>&1; then
|
elif command -v sysctl &>/dev/null && sysctl hw.ncpu &>/dev/null; then
|
||||||
sysctl -n hw.ncpu
|
sysctl -n hw.ncpu
|
||||||
elif [ -f /proc/cpuinfo ]; then
|
elif [ -f /proc/cpuinfo ]; then
|
||||||
grep -c processor /proc/cpuinfo
|
grep -c processor /proc/cpuinfo
|
||||||
|
@ -80,17 +80,41 @@ def noFunctionKeywordFixer(line: str, m: Any) -> str:
|
|||||||
|
|
||||||
return f'{prestr}{midstr}() {poststr}'
|
return f'{prestr}{midstr}() {poststr}'
|
||||||
|
|
||||||
def lintfile(filepath: Path, rules: List[Rule], options: Dict[str, Any]):
|
# Before: >/dev/null 2>&1
|
||||||
content_arr = filepath.read_text().split('\n')
|
# After: &>/dev/null
|
||||||
|
# ---
|
||||||
|
# Before: 2>/dev/null 1>&2
|
||||||
|
# After: &>/dev/null
|
||||||
|
def noVerboseRedirectionFixer(line: str, m: Any) -> str:
|
||||||
|
prestr, _, poststr = utilGetStrs(line, m)
|
||||||
|
|
||||||
|
return f'{prestr}&>/dev/null{poststr}'
|
||||||
|
|
||||||
|
def lintfile(file: Path, rules: List[Rule], options: Dict[str, Any]):
|
||||||
|
content_arr = file.read_text().split('\n')
|
||||||
|
|
||||||
for line_i, line in enumerate(content_arr):
|
for line_i, line in enumerate(content_arr):
|
||||||
if 'checkstyle-ignore' in line:
|
if 'checkstyle-ignore' in line:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
|
should_run = False
|
||||||
|
if 'sh' in rule['fileTypes']:
|
||||||
|
if file.name.endswith('.sh') or str(file.absolute()).endswith('bin/asdf'):
|
||||||
|
should_run = True
|
||||||
|
if 'bash' in rule['fileTypes']:
|
||||||
|
if file.name.endswith('.bash') or file.name.endswith('.bats'):
|
||||||
|
should_run = True
|
||||||
|
|
||||||
|
if options['verbose']:
|
||||||
|
print(f'{str(file)}: {should_run}')
|
||||||
|
|
||||||
|
if not should_run:
|
||||||
|
continue
|
||||||
|
|
||||||
m = re.search(rule['regex'], line)
|
m = re.search(rule['regex'], line)
|
||||||
if m is not None and m.group('match') is not None:
|
if m is not None and m.group('match') is not None:
|
||||||
dir = os.path.relpath(filepath.resolve(), Path.cwd())
|
dir = os.path.relpath(file.resolve(), Path.cwd())
|
||||||
prestr = line[0:m.start('match')]
|
prestr = line[0:m.start('match')]
|
||||||
midstr = line[m.start('match'):m.end('match')]
|
midstr = line[m.start('match'):m.end('match')]
|
||||||
poststr = line[m.end('match'):]
|
poststr = line[m.end('match'):]
|
||||||
@ -106,7 +130,7 @@ def lintfile(filepath: Path, rules: List[Rule], options: Dict[str, Any]):
|
|||||||
rule['found'] += 1
|
rule['found'] += 1
|
||||||
|
|
||||||
if options['fix']:
|
if options['fix']:
|
||||||
filepath.write_text('\n'.join(content_arr))
|
file.write_text('\n'.join(content_arr))
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
rules: List[Rule] = [
|
rules: List[Rule] = [
|
||||||
@ -114,6 +138,7 @@ def main():
|
|||||||
'name': 'no-double-backslash',
|
'name': 'no-double-backslash',
|
||||||
'regex': '".*?(?P<match>\\\\\\\\[abeEfnrtv\'"?xuUc]).*?(?<!\\\\)"',
|
'regex': '".*?(?P<match>\\\\\\\\[abeEfnrtv\'"?xuUc]).*?(?<!\\\\)"',
|
||||||
'reason': 'Backslashes are only required if followed by a $, `, ", \\, or <newline>',
|
'reason': 'Backslashes are only required if followed by a $, `, ", \\, or <newline>',
|
||||||
|
'fileTypes': ['bash', 'sh'],
|
||||||
'fixerFn': noDoubleBackslashFixer,
|
'fixerFn': noDoubleBackslashFixer,
|
||||||
'testPositiveMatches': [
|
'testPositiveMatches': [
|
||||||
'printf "%s\\\\n" "Hai"',
|
'printf "%s\\\\n" "Hai"',
|
||||||
@ -123,12 +148,12 @@ def main():
|
|||||||
'printf "%s\\n" "Hai"',
|
'printf "%s\\n" "Hai"',
|
||||||
'echo -n "Hello\\n"'
|
'echo -n "Hello\\n"'
|
||||||
],
|
],
|
||||||
'found': 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'no-pwd-capture',
|
'name': 'no-pwd-capture',
|
||||||
'regex': '(?P<match>\\$\\(pwd\\))',
|
'regex': '(?P<match>\\$\\(pwd\\))',
|
||||||
'reason': '$PWD is essentially equivalent to $(pwd) without the overhead of a subshell',
|
'reason': '$PWD is essentially equivalent to $(pwd) without the overhead of a subshell',
|
||||||
|
'fileTypes': ['bash', 'sh'],
|
||||||
'fixerFn': noPwdCaptureFixer,
|
'fixerFn': noPwdCaptureFixer,
|
||||||
'testPositiveMatches': [
|
'testPositiveMatches': [
|
||||||
'$(pwd)'
|
'$(pwd)'
|
||||||
@ -136,12 +161,12 @@ def main():
|
|||||||
'testNegativeMatches': [
|
'testNegativeMatches': [
|
||||||
'$PWD'
|
'$PWD'
|
||||||
],
|
],
|
||||||
'found': 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'no-test-double-equals',
|
'name': 'no-test-double-equals',
|
||||||
'regex': '(?<!\\[)\\[ (?:[^]]|](?=}))*?(?P<match>==).*?]',
|
'regex': '(?<!\\[)\\[ (?:[^]]|](?=}))*?(?P<match>==).*?]',
|
||||||
'reason': 'Disallow double equals in places where they are not necessary for consistency',
|
'reason': 'Disallow double equals in places where they are not necessary for consistency',
|
||||||
|
'fileTypes': ['bash', 'sh'],
|
||||||
'fixerFn': noTestDoubleEqualsFixer,
|
'fixerFn': noTestDoubleEqualsFixer,
|
||||||
'testPositiveMatches': [
|
'testPositiveMatches': [
|
||||||
'[ a == b ]',
|
'[ a == b ]',
|
||||||
@ -156,12 +181,12 @@ def main():
|
|||||||
'[[ "${lines[0]}" == \'usage: \'* ]]',
|
'[[ "${lines[0]}" == \'usage: \'* ]]',
|
||||||
'[ "${lines[0]}" = blah ]',
|
'[ "${lines[0]}" = blah ]',
|
||||||
],
|
],
|
||||||
'found': 0
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'no-function-keyword',
|
'name': 'no-function-keyword',
|
||||||
'regex': '^[ \\t]*(?P<match>function .*?(?:\\([ \\t]*\\))?[ \\t]*){',
|
'regex': '^[ \\t]*(?P<match>function .*?(?:\\([ \\t]*\\))?[ \\t]*){',
|
||||||
'reason': 'Only allow functions declared like `fn_name() {{ :; }}` for consistency (see ' + c.LINK('https://www.shellcheck.net/wiki/SC2113', 'ShellCheck SC2113') + ')',
|
'reason': 'Only allow functions declared like `fn_name() {{ :; }}` for consistency (see ' + c.LINK('https://www.shellcheck.net/wiki/SC2113', 'ShellCheck SC2113') + ')',
|
||||||
|
'fileTypes': ['bash', 'sh'],
|
||||||
'fixerFn': noFunctionKeywordFixer,
|
'fixerFn': noFunctionKeywordFixer,
|
||||||
'testPositiveMatches': [
|
'testPositiveMatches': [
|
||||||
'function fn() { :; }',
|
'function fn() { :; }',
|
||||||
@ -170,13 +195,29 @@ def main():
|
|||||||
'testNegativeMatches': [
|
'testNegativeMatches': [
|
||||||
'fn() { :; }',
|
'fn() { :; }',
|
||||||
],
|
],
|
||||||
'found': 0
|
},
|
||||||
|
{
|
||||||
|
'name': 'no-verbose-redirection',
|
||||||
|
'regex': '(?P<match>(>/dev/null 2>&1|2>/dev/null 1>&2))',
|
||||||
|
'reason': 'Use `&>/dev/null` instead of `>/dev/null 2>&1` or `2>/dev/null 1>&2` for consistency',
|
||||||
|
'fileTypes': ['bash'],
|
||||||
|
'fixerFn': noVerboseRedirectionFixer,
|
||||||
|
'testPositiveMatches': [
|
||||||
|
'echo woof >/dev/null 2>&1',
|
||||||
|
'echo woof 2>/dev/null 1>&2',
|
||||||
|
],
|
||||||
|
'testNegativeMatches': [
|
||||||
|
'echo woof &>/dev/null',
|
||||||
|
'echo woof >&/dev/null',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
[rule.update({ 'found': 0 }) for rule in rules]
|
||||||
|
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument('files', metavar='FILES', nargs='*')
|
parser.add_argument('files', metavar='FILES', nargs='*')
|
||||||
parser.add_argument('--fix', action='store_true')
|
parser.add_argument('--fix', action='store_true')
|
||||||
|
parser.add_argument('--verbose', action='store_true')
|
||||||
parser.add_argument('--internal-test-regex', action='store_true')
|
parser.add_argument('--internal-test-regex', action='store_true')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
@ -199,7 +240,8 @@ def main():
|
|||||||
return
|
return
|
||||||
|
|
||||||
options = {
|
options = {
|
||||||
'fix': args.fix
|
'fix': args.fix,
|
||||||
|
'verbose': args.verbose,
|
||||||
}
|
}
|
||||||
|
|
||||||
# parse files and print matched lints
|
# parse files and print matched lints
|
||||||
@ -210,9 +252,11 @@ def main():
|
|||||||
lintfile(p, rules, options)
|
lintfile(p, rules, options)
|
||||||
else:
|
else:
|
||||||
for file in Path.cwd().glob('**/*'):
|
for file in Path.cwd().glob('**/*'):
|
||||||
if file.name.endswith('.bash') or file.name.endswith('.sh') or file.name.endswith('.bats') or str(file.absolute()).endswith('bin/asdf'):
|
if '.git' in str(file.absolute()):
|
||||||
if file.is_file():
|
continue
|
||||||
lintfile(file, rules, options)
|
|
||||||
|
if file.is_file():
|
||||||
|
lintfile(file, rules, options)
|
||||||
|
|
||||||
# print final results
|
# print final results
|
||||||
print(f'{c.UNDERLINE}TOTAL ISSUES{c.RESET}')
|
print(f'{c.UNDERLINE}TOTAL ISSUES{c.RESET}')
|
||||||
|
Loading…
Reference in New Issue
Block a user