diff options
| author | Simeon Simeonov | 2025-07-02 20:58:43 +0200 |
|---|---|---|
| committer | Simeon Simeonov | 2025-07-02 20:58:43 +0200 |
| commit | 29817dfd24ca5b2536eb14aaadd84d3cbded7a32 (patch) | |
| tree | f555340bfce16c8ffd70ee3bad8348d1f1fdd6ad | |
| parent | 76c02cdbbec34c37795bc378dee4cb3249939c48 (diff) | |
| -rw-r--r-- | .ruff.toml | 96 | ||||
| -rwxr-xr-x | smount.py | 20 | ||||
| -rwxr-xr-x | sumount.py | 71 |
3 files changed, 149 insertions, 38 deletions
diff --git a/.ruff.toml b/.ruff.toml new file mode 100644 index 0000000..12d671b --- /dev/null +++ b/.ruff.toml | |||
| @@ -0,0 +1,96 @@ | |||
| 1 | cache-dir = "~/.cache/ruff" | ||
| 2 | indent-width = 4 | ||
| 3 | line-length = 79 | ||
| 4 | target-version = "py311" | ||
| 5 | |||
| 6 | [lint] | ||
| 7 | select = ["ALL", "D101", "D102", "D103", "D104"] | ||
| 8 | ignore = [ | ||
| 9 | "ANN", | ||
| 10 | "BLE001", | ||
| 11 | "COM812", | ||
| 12 | "D", | ||
| 13 | "EM101", # Exception must not use a string literal, assign to variable first | ||
| 14 | "EM102", # Exception must not use an f-string literal, assign to variable first | ||
| 15 | "ERA001", | ||
| 16 | #"FBT001", | ||
| 17 | #"FBT002", | ||
| 18 | #"INP001", | ||
| 19 | #"ISC001", | ||
| 20 | #"N802", | ||
| 21 | #"N806", | ||
| 22 | "PLR2004", | ||
| 23 | "PTH111", | ||
| 24 | "PTH123", | ||
| 25 | "RUF012", | ||
| 26 | #"RUF013", | ||
| 27 | #"S101", | ||
| 28 | "S308", | ||
| 29 | "S603", | ||
| 30 | "T201", | ||
| 31 | "TRY003", | ||
| 32 | "TRY300", | ||
| 33 | #"UP020" | ||
| 34 | ] | ||
| 35 | |||
| 36 | # D101 - Missing docstring in public class | ||
| 37 | # D102 - Missing docstring in public method | ||
| 38 | # D200 - One-line docstring should fit on one line | ||
| 39 | # D203 - 1 blank line required before class docstring | ||
| 40 | # D205 - 1 blank line required between summary line and description | ||
| 41 | # D403 - First word of the first line should be capitalized: `str` -> `Str` | ||
| 42 | # ERA001 - Found commented-out code | ||
| 43 | # FBT001 - Boolean-typed positional argument in function definition | ||
| 44 | # FBT002 - Boolean default positional argument in function definition | ||
| 45 | # INP001 - File `beinc_weechat.py` is part of an implicit namespace package. Add an `__init__.py` | ||
| 46 | # N802 - Function name `do_GET` should be lowercase | ||
| 47 | # N806 - Variable `POST_data` in function should be lowercase | ||
| 48 | # PTH111 - `os.path.expanduser()` should be replaced by `Path.expanduser()` | ||
| 49 | # PTH123 - `open()` should be replaced by `Path.open()` | ||
| 50 | # PLR2004 - Magic value used in comparison, consider replacing `200` with a constant variable | ||
| 51 | # RUF012 - Mutable class attributes should be annotated with `typing.ClassVar` | ||
| 52 | # RUF013 - PEP 484 prohibits implicit `Optional` | ||
| 53 | # S101 - Use of `assert` detected | ||
| 54 | # S308 - Use of `mark_safe` may expose cross-site scripting vulnerabilities | ||
| 55 | # S603 - `subprocess` call: check for execution of untrusted input | ||
| 56 | # T201 - `print` found | ||
| 57 | # TRY003 - Avoid specifying long messages outside the exception class | ||
| 58 | # TRY300 - Consider moving this statement to an `else` block | ||
| 59 | # UP020 - Use builtin `open` | ||
| 60 | |||
| 61 | # Allow fix for all enabled rules (when `--fix`) is provided. | ||
| 62 | fixable = ["ALL"] | ||
| 63 | unfixable = [] | ||
| 64 | |||
| 65 | [format] | ||
| 66 | # Like Black, use double quotes for strings. | ||
| 67 | quote-style = "single" | ||
| 68 | |||
| 69 | # Like Black, indent with spaces, rather than tabs. | ||
| 70 | indent-style = "space" | ||
| 71 | |||
| 72 | # Like Black, respect magic trailing commas. | ||
| 73 | skip-magic-trailing-comma = true | ||
| 74 | |||
| 75 | # Like Black, automatically detect the appropriate line ending. | ||
| 76 | line-ending = "lf" | ||
| 77 | |||
| 78 | # Enable auto-formatting of code examples in docstrings. Markdown, | ||
| 79 | # reStructuredText code/literal blocks and doctests are all supported. | ||
| 80 | # | ||
| 81 | # This is currently disabled by default, but it is planned for this | ||
| 82 | # to be opt-out in the future. | ||
| 83 | docstring-code-format = false | ||
| 84 | |||
| 85 | # Set the line length limit used when formatting code snippets in | ||
| 86 | # docstrings. | ||
| 87 | # | ||
| 88 | # This only has an effect when the `docstring-code-format` setting is | ||
| 89 | # enabled. | ||
| 90 | docstring-code-line-length = "dynamic" | ||
| 91 | |||
| 92 | [lint.flake8-quotes] | ||
| 93 | inline-quotes = "single" | ||
| 94 | |||
| 95 | [lint.isort] | ||
| 96 | split-on-trailing-comma = false | ||
| @@ -1,5 +1,4 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | 2 | ||
| 4 | import json | 3 | import json |
| 5 | import os | 4 | import os |
| @@ -9,27 +8,30 @@ import sys | |||
| 9 | 8 | ||
| 10 | def main(): | 9 | def main(): |
| 11 | """Main entry point""" | 10 | """Main entry point""" |
| 12 | if (len(sys.argv) != 2): | 11 | if len(sys.argv) != 2: |
| 13 | sys.exit('Invalid parameter. Usage: {0} <mapping>\n'.format( | 12 | sys.exit(f'Invalid parameter. Usage: {sys.argv[0]} <mapping>\n') |
| 14 | sys.argv[0])) | 13 | |
| 15 | cstm_error = '' | 14 | cstm_error = '' |
| 15 | |||
| 16 | try: | 16 | try: |
| 17 | cstm_error = 'Could not open config (~/.smount.json)' | 17 | cstm_error = 'Could not open config (~/.smount.json)' |
| 18 | |||
| 18 | with open(os.path.expanduser('~/.smount.json')) as fp: | 19 | with open(os.path.expanduser('~/.smount.json')) as fp: |
| 19 | config_dict = json.load(fp) | 20 | config_dict = json.load(fp) |
| 20 | cstm_error = 'Invalid / nonexistent mapping: {0}'.format(sys.argv[1]) | 21 | |
| 22 | cstm_error = f'Invalid / nonexistent mapping: {sys.argv[1]}' | ||
| 21 | data = config_dict[sys.argv[1]] | 23 | data = config_dict[sys.argv[1]] |
| 22 | cstm_error = 'system() error' | 24 | cstm_error = 'subprocess error' |
| 23 | args = ['/usr/bin/sshfs'] | 25 | args = ['/usr/bin/sshfs'] |
| 24 | if data.get('options'): | 26 | if data.get('options'): |
| 25 | for opt in data.get('options'): | 27 | for opt in data.get('options'): |
| 26 | args.extend(['-o', opt]) | 28 | args.extend(['-o', opt]) |
| 27 | args.extend([data['src'], data['dest']]) | 29 | args.extend([data['src'], data['dest']]) |
| 28 | subprocess.check_call(args) | 30 | subprocess.check_call(args) |
| 29 | except subprocess.CalledProcessError as e: | 31 | except subprocess.CalledProcessError as err: |
| 30 | print('Execution error: {0}'.format(e), file=sys.stderr, flush=True) | 32 | print(f'Execution error: {err}', file=sys.stderr, flush=True) |
| 31 | except Exception: | 33 | except Exception: |
| 32 | print('Error: {0}'.format(cstm_error), file=sys.stderr, flush=True) | 34 | print(f'Error: {cstm_error}', file=sys.stderr, flush=True) |
| 33 | 35 | ||
| 34 | 36 | ||
| 35 | if __name__ == '__main__': | 37 | if __name__ == '__main__': |
| @@ -1,5 +1,4 @@ | |||
| 1 | #!/usr/bin/env python | 1 | #!/usr/bin/env python |
| 2 | # -*- coding: utf-8 -*- | ||
| 3 | 2 | ||
| 4 | import json | 3 | import json |
| 5 | import os | 4 | import os |
| @@ -9,47 +8,61 @@ import sys | |||
| 9 | 8 | ||
| 10 | def main(): | 9 | def main(): |
| 11 | """Main entry point""" | 10 | """Main entry point""" |
| 12 | if (len(sys.argv) != 2): | 11 | if len(sys.argv) != 2: |
| 13 | sys.exit('Invalid parameter. Usage: {0} <mapping>\n'.format( | 12 | sys.exit(f'Invalid parameter. Usage: {sys.argv[0]} <mapping>\n') |
| 14 | sys.argv[0])) | 13 | |
| 15 | cstm_error = '' | 14 | cstm_error = '' |
| 15 | |||
| 16 | try: | 16 | try: |
| 17 | cstm_error = 'Could not open config (~/.smount.json)' | 17 | cstm_error = 'Could not open config (~/.smount.json)' |
| 18 | |||
| 18 | with open(os.path.expanduser('~/.smount.json')) as fp: | 19 | with open(os.path.expanduser('~/.smount.json')) as fp: |
| 19 | config_dict = json.load(fp) | 20 | config_dict = json.load(fp) |
| 21 | |||
| 20 | cstm_error = 'Errror while executing all' | 22 | cstm_error = 'Errror while executing all' |
| 23 | |||
| 21 | if sys.argv[1].lower() == 'all': | 24 | if sys.argv[1].lower() == 'all': |
| 22 | mounts = set() | 25 | mounts = ( |
| 23 | umounted = list() # already umounted | 26 | subprocess.run( |
| 24 | with open('/etc/mtab') as fp: | 27 | [ |
| 25 | for line in fp: | 28 | '/bin/findmnt', |
| 26 | mounts.update(line.strip().split()) | 29 | '-t', |
| 30 | 'fuse.sshfs', | ||
| 31 | '--list', | ||
| 32 | '-n', | ||
| 33 | '-o', | ||
| 34 | 'TARGET', | ||
| 35 | ], | ||
| 36 | capture_output=True, | ||
| 37 | check=False, | ||
| 38 | encoding='utf-8', | ||
| 39 | ) | ||
| 40 | .stdout.strip() | ||
| 41 | .split() | ||
| 42 | ) | ||
| 43 | |||
| 27 | for key, value in config_dict.items(): | 44 | for key, value in config_dict.items(): |
| 28 | if value['dest'] not in mounts: | 45 | if value['dest'] not in mounts: |
| 29 | print('{mount} not in /etc/mtab'.format(mount=key)) | 46 | print(f'{key} not mounted') |
| 30 | continue | ||
| 31 | if value['dest'] in umounted: | ||
| 32 | print('{mount}: {dest} already umounted'.format( | ||
| 33 | mount=key, | ||
| 34 | dest=value['dest'])) | ||
| 35 | continue | 47 | continue |
| 36 | subprocess.check_call(['/usr/bin/fusermount', | 48 | |
| 37 | '-u', | 49 | subprocess.run( |
| 38 | value['dest']]) | 50 | ['/usr/bin/fusermount3', '-u', value['dest']], check=True |
| 39 | umounted.append(value['dest']) | 51 | ) |
| 40 | print('umonted: {key} - {dest}'.format( | 52 | mounts.pop(mounts.index(value['dest'])) |
| 41 | key=key, | 53 | print(f'umonted: {key} - {value["dest"]}') |
| 42 | dest=value['dest'])) | 54 | |
| 43 | sys.exit(0) | 55 | sys.exit(0) |
| 44 | cstm_error = 'Invalid / nonexistent mapping: {0}'.format(sys.argv[1]) | 56 | |
| 57 | cstm_error = f'Invalid / nonexistent mapping: {sys.argv[1]}' | ||
| 45 | data = config_dict[sys.argv[1]] | 58 | data = config_dict[sys.argv[1]] |
| 46 | subprocess.check_call(['/usr/bin/fusermount', | 59 | subprocess.run( |
| 47 | '-u', | 60 | ['/usr/bin/fusermount3', '-u', data['dest']], check=True |
| 48 | data['dest']]) | 61 | ) |
| 49 | except subprocess.CalledProcessError as e: | 62 | except subprocess.CalledProcessError as err: |
| 50 | print('Execution error: {0}'.format(e), file=sys.stderr, flush=True) | 63 | print(f'Execution error: {err}', file=sys.stderr, flush=True) |
| 51 | except Exception: | 64 | except Exception: |
| 52 | print('Error: {0}'.format(cstm_error), file=sys.stderr, flush=True) | 65 | print(f'Error: {cstm_error}', file=sys.stderr, flush=True) |
| 53 | 66 | ||
| 54 | 67 | ||
| 55 | if __name__ == '__main__': | 68 | if __name__ == '__main__': |
