Loading README.md +22 −6 Changes for README.md: 22 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -28,12 +28,13 @@ The following step is required before using the tool: <!-- readme-help-start --> ```yaml usage: gitlab-projects-settings [-h] [--version] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups] [--exclude-projects] [--available-features] [--reset-features [KEEP_FEATURES]] [--disable-features FEATURES] [--enable-features FEATURES] [--reset-members] [--set-avatar FILE] [--set-description TEXT] [--update-description] [--run-housekeeping] [--archive-project | --unarchive-project] [--delete-group] [--delete-project] [--protect-branches] [--protect-tags LEVEL] [--] usage: gitlab-projects-settings [-h] [--version] [--settings] [--set GROUP KEY VAL] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups] [--exclude-projects] [--available-features] [--reset-features [KEEP_FEATURES]] [--disable-features FEATURES] [--enable-features FEATURES] [--reset-members] [--set-avatar FILE] [--set-description TEXT] [--update-description] [--run-housekeeping] [--archive-project | --unarchive-project] [--delete-group] [--delete-project] [--protect-branches] [--protect-tags LEVEL] [--] [gitlab] [path] gitlab-projects-settings: Configure GitLab groups and projects settings automatically Loading @@ -41,6 +42,9 @@ gitlab-projects-settings: Configure GitLab groups and projects settings automati internal arguments: -h, --help # Show this help message --version # Show the current version --settings # Show the current settings path and contents --set GROUP KEY VAL # Set settings specific 'VAL' value to [GROUP] > KEY # or unset by using 'UNSET' as 'VAL' credentials arguments: -t TOKEN # GitLab API token (default: GITLAB_TOKEN environment) Loading Loading @@ -84,6 +88,18 @@ positional arguments: --- ## Userspace available settings `gitlab-projects-settings` creates a `settings.ini` configuration file in a userspace folder. The `settings.ini` file location and contents can be shown with the following command: ```bash gitlab-projects-settings --settings ``` --- ## Dependencies - [colored](https://pypi.org/project/colored/): Terminal colors and styles Loading src/cli/main.py +30 −0 Changes for src/cli/main.py: 30 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ from sys import exit as sys_exit # Components from ..package.bundle import Bundle from ..package.settings import Settings from ..package.version import Version from ..prints.colors import Colors from ..system.platform import Platform Loading Loading @@ -52,6 +53,21 @@ def main() -> None: action='store_true', help='Show the current version', ) group.add_argument( '--settings', dest='settings', action='store_true', help='Show the current settings path and contents', ) group.add_argument( '--set', dest='set', action='store', metavar=('GROUP', 'KEY', 'VAL'), nargs=3, help='Set settings specific \'VAL\' value to [GROUP] > KEY\n' \ 'or unset by using \'UNSET\' as \'VAL\'', ) # Arguments credentials definitions group = parser.add_argument_group('credentials arguments') Loading Loading @@ -229,9 +245,23 @@ def main() -> None: Platform.flush() sys_exit(0) # Instantiate settings settings: Settings = Settings(name=Bundle.NAME) # Prepare colors Colors.prepare() # Settings setter if options.set: settings.set(options.set[0], options.set[1], options.set[2]) settings.show() sys_exit(0) # Settings informations if options.settings: settings.show() sys_exit(0) # Version informations if options.version: print( Loading src/package/settings.py 0 → 100644 +144 −0 Changes for src/package/settings.py: 144 added lines, 0 removed lines. Original line number Diff line number Diff line #!/usr/bin/env python3 # Standard libraries from configparser import ConfigParser from pathlib import Path from sys import stdout from typing import Optional, Union # Components from ..prints.colors import Colors from ..system.platform import Platform # Settings class class Settings: # Types Value = Union[int, str] # Constants SETTINGS_FILE: str = 'settings.ini' # Members __folder: Path __persistent: bool __path: Path __settings: ConfigParser # Constructor def __init__(self, name: str) -> None: # Prepare paths self.__folder = Platform.userspace(name) self.__path = self.__folder / Settings.SETTINGS_FILE self.__persistent = False # Parse settings self.__settings = ConfigParser() self.__settings.read(self.__path) # Prepare missing settings try: if self.get('package', 'name') != name: raise ValueError('Missing settings files') self.__persistent = True except ValueError: try: self.__prepare() self.__reset(name) self.__persistent = True except PermissionError: # pragma: no cover self.__persistent = False # Prepare def __prepare(self) -> None: # Prepare folder path if not Platform.IS_SIMULATED: self.__folder.mkdir(parents=True, exist_ok=True) # Reset def __reset(self, name: str) -> None: # Prepare barebone settings self.__settings = ConfigParser() self.set('package', 'name', name) # Writer def __write(self) -> None: # Write initial settings if self.__persistent and not Platform.IS_SIMULATED: with open(self.__path, encoding='utf8', mode='w') as output: self.__settings.write(output) # Has def has(self, group: str, key: str) -> bool: # Check settings key in group return group in self.__settings and key in self.__settings[group] # Get def get(self, group: str, key: str) -> Optional[Value]: # Get settings key in group if group in self.__settings and key in self.__settings[group]: return self.__settings[group][key] # Default fallback return None # Get bool def get_bool(self, group: str, key: str) -> Optional[bool]: # Get settings key as boolean try: value: str = str(self.get(group, key)) return value.lower() == 'true' or int(value) == 1 except (TypeError, ValueError): return False # Set def set(self, group: str, key: str, value: Value) -> None: # Prepare group if group not in self.__settings: self.__settings[group] = {} # Unset key if str(value) == 'UNSET': del self.__settings[group][key] # Set key else: self.__settings[group][key] = str(value) # Write updated settings self.__write() # Set bool def set_bool(self, group: str, key: str, value: Value) -> None: # Set settings key as boolean self.set(group, key, 1 if value else 0) # Show def show(self) -> None: # Settings file path print(' ') print( f' {Colors.GREEN}===[ {Colors.YELLOW}Settings:' \ f' {Colors.BOLD}{self.__path} {Colors.GREEN}]==={Colors.RESET}' ) print(' ') # Settings simulated contents if Platform.IS_SIMULATED: self.__settings.write(stdout) # Settings file contents else: with open(self.__path, encoding='utf8', mode='r') as data: print(data.read()) Platform.flush() src/system/platform.py +41 −1 Changes for src/system/platform.py: 41 added lines, 1 removed line. Original line number Diff line number Diff line #!/usr/bin/env python3 # Standard libraries from os import sep from os import access, environ, R_OK, sep from os.path import expanduser from pathlib import Path from sys import platform, stdin, stdout # Platform, pylint: disable=too-few-public-methods class Platform: # Environment ENV_SIMULATE_MAC_OS: str = 'SIMULATE_MAC_OS' ENV_SUDO_USER: str = 'SUDO_USER' # Constants IS_LINUX: bool = platform in ['linux', 'linux2'] IS_MAC_OS: bool = platform in ['darwin'] or ENV_SIMULATE_MAC_OS in environ IS_SIMULATED: bool = ENV_SIMULATE_MAC_OS in environ IS_WINDOWS: bool = platform in ['win32', 'win64'] # Separators Loading @@ -19,9 +27,41 @@ class Platform: IS_TTY_STDOUT: bool = stdout.isatty() IS_TTY_UTF8: bool = str(stdout.encoding).lower() == 'utf-8' # Users IS_USER_SUDO: bool = ENV_SUDO_USER in environ USER_SUDO: str = environ[ENV_SUDO_USER] if IS_USER_SUDO else '' # Flush @staticmethod def flush() -> None: # Flush output print('', end='', flush=Platform.IS_TTY_STDOUT) # Userspace @staticmethod def userspace(name: str) -> Path: # Variables home: None | Path = None # Elevated home if Platform.IS_USER_SUDO: home = Path(expanduser(f'~{Platform.USER_SUDO}')) if not access(home, R_OK): home = None # Default home if not home or not home.is_dir(): home = Path.home() # Windows userspace if Platform.IS_WINDOWS: return home / 'AppData' / 'Local' / name # macOS userspace if Platform.IS_MAC_OS: return home / 'Library' / 'Preferences' / name # Linux userspace return home / '.config' / name Loading
README.md +22 −6 Changes for README.md: 22 added lines, 6 removed lines. Original line number Diff line number Diff line Loading @@ -28,12 +28,13 @@ The following step is required before using the tool: <!-- readme-help-start --> ```yaml usage: gitlab-projects-settings [-h] [--version] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups] [--exclude-projects] [--available-features] [--reset-features [KEEP_FEATURES]] [--disable-features FEATURES] [--enable-features FEATURES] [--reset-members] [--set-avatar FILE] [--set-description TEXT] [--update-description] [--run-housekeeping] [--archive-project | --unarchive-project] [--delete-group] [--delete-project] [--protect-branches] [--protect-tags LEVEL] [--] usage: gitlab-projects-settings [-h] [--version] [--settings] [--set GROUP KEY VAL] [-t TOKEN] [--dry-run] [--exclude-group] [--exclude-subgroups] [--exclude-projects] [--available-features] [--reset-features [KEEP_FEATURES]] [--disable-features FEATURES] [--enable-features FEATURES] [--reset-members] [--set-avatar FILE] [--set-description TEXT] [--update-description] [--run-housekeeping] [--archive-project | --unarchive-project] [--delete-group] [--delete-project] [--protect-branches] [--protect-tags LEVEL] [--] [gitlab] [path] gitlab-projects-settings: Configure GitLab groups and projects settings automatically Loading @@ -41,6 +42,9 @@ gitlab-projects-settings: Configure GitLab groups and projects settings automati internal arguments: -h, --help # Show this help message --version # Show the current version --settings # Show the current settings path and contents --set GROUP KEY VAL # Set settings specific 'VAL' value to [GROUP] > KEY # or unset by using 'UNSET' as 'VAL' credentials arguments: -t TOKEN # GitLab API token (default: GITLAB_TOKEN environment) Loading Loading @@ -84,6 +88,18 @@ positional arguments: --- ## Userspace available settings `gitlab-projects-settings` creates a `settings.ini` configuration file in a userspace folder. The `settings.ini` file location and contents can be shown with the following command: ```bash gitlab-projects-settings --settings ``` --- ## Dependencies - [colored](https://pypi.org/project/colored/): Terminal colors and styles Loading
src/cli/main.py +30 −0 Changes for src/cli/main.py: 30 added lines, 0 removed lines. Original line number Diff line number Diff line Loading @@ -9,6 +9,7 @@ from sys import exit as sys_exit # Components from ..package.bundle import Bundle from ..package.settings import Settings from ..package.version import Version from ..prints.colors import Colors from ..system.platform import Platform Loading Loading @@ -52,6 +53,21 @@ def main() -> None: action='store_true', help='Show the current version', ) group.add_argument( '--settings', dest='settings', action='store_true', help='Show the current settings path and contents', ) group.add_argument( '--set', dest='set', action='store', metavar=('GROUP', 'KEY', 'VAL'), nargs=3, help='Set settings specific \'VAL\' value to [GROUP] > KEY\n' \ 'or unset by using \'UNSET\' as \'VAL\'', ) # Arguments credentials definitions group = parser.add_argument_group('credentials arguments') Loading Loading @@ -229,9 +245,23 @@ def main() -> None: Platform.flush() sys_exit(0) # Instantiate settings settings: Settings = Settings(name=Bundle.NAME) # Prepare colors Colors.prepare() # Settings setter if options.set: settings.set(options.set[0], options.set[1], options.set[2]) settings.show() sys_exit(0) # Settings informations if options.settings: settings.show() sys_exit(0) # Version informations if options.version: print( Loading
src/package/settings.py 0 → 100644 +144 −0 Changes for src/package/settings.py: 144 added lines, 0 removed lines. Original line number Diff line number Diff line #!/usr/bin/env python3 # Standard libraries from configparser import ConfigParser from pathlib import Path from sys import stdout from typing import Optional, Union # Components from ..prints.colors import Colors from ..system.platform import Platform # Settings class class Settings: # Types Value = Union[int, str] # Constants SETTINGS_FILE: str = 'settings.ini' # Members __folder: Path __persistent: bool __path: Path __settings: ConfigParser # Constructor def __init__(self, name: str) -> None: # Prepare paths self.__folder = Platform.userspace(name) self.__path = self.__folder / Settings.SETTINGS_FILE self.__persistent = False # Parse settings self.__settings = ConfigParser() self.__settings.read(self.__path) # Prepare missing settings try: if self.get('package', 'name') != name: raise ValueError('Missing settings files') self.__persistent = True except ValueError: try: self.__prepare() self.__reset(name) self.__persistent = True except PermissionError: # pragma: no cover self.__persistent = False # Prepare def __prepare(self) -> None: # Prepare folder path if not Platform.IS_SIMULATED: self.__folder.mkdir(parents=True, exist_ok=True) # Reset def __reset(self, name: str) -> None: # Prepare barebone settings self.__settings = ConfigParser() self.set('package', 'name', name) # Writer def __write(self) -> None: # Write initial settings if self.__persistent and not Platform.IS_SIMULATED: with open(self.__path, encoding='utf8', mode='w') as output: self.__settings.write(output) # Has def has(self, group: str, key: str) -> bool: # Check settings key in group return group in self.__settings and key in self.__settings[group] # Get def get(self, group: str, key: str) -> Optional[Value]: # Get settings key in group if group in self.__settings and key in self.__settings[group]: return self.__settings[group][key] # Default fallback return None # Get bool def get_bool(self, group: str, key: str) -> Optional[bool]: # Get settings key as boolean try: value: str = str(self.get(group, key)) return value.lower() == 'true' or int(value) == 1 except (TypeError, ValueError): return False # Set def set(self, group: str, key: str, value: Value) -> None: # Prepare group if group not in self.__settings: self.__settings[group] = {} # Unset key if str(value) == 'UNSET': del self.__settings[group][key] # Set key else: self.__settings[group][key] = str(value) # Write updated settings self.__write() # Set bool def set_bool(self, group: str, key: str, value: Value) -> None: # Set settings key as boolean self.set(group, key, 1 if value else 0) # Show def show(self) -> None: # Settings file path print(' ') print( f' {Colors.GREEN}===[ {Colors.YELLOW}Settings:' \ f' {Colors.BOLD}{self.__path} {Colors.GREEN}]==={Colors.RESET}' ) print(' ') # Settings simulated contents if Platform.IS_SIMULATED: self.__settings.write(stdout) # Settings file contents else: with open(self.__path, encoding='utf8', mode='r') as data: print(data.read()) Platform.flush()
src/system/platform.py +41 −1 Changes for src/system/platform.py: 41 added lines, 1 removed line. Original line number Diff line number Diff line #!/usr/bin/env python3 # Standard libraries from os import sep from os import access, environ, R_OK, sep from os.path import expanduser from pathlib import Path from sys import platform, stdin, stdout # Platform, pylint: disable=too-few-public-methods class Platform: # Environment ENV_SIMULATE_MAC_OS: str = 'SIMULATE_MAC_OS' ENV_SUDO_USER: str = 'SUDO_USER' # Constants IS_LINUX: bool = platform in ['linux', 'linux2'] IS_MAC_OS: bool = platform in ['darwin'] or ENV_SIMULATE_MAC_OS in environ IS_SIMULATED: bool = ENV_SIMULATE_MAC_OS in environ IS_WINDOWS: bool = platform in ['win32', 'win64'] # Separators Loading @@ -19,9 +27,41 @@ class Platform: IS_TTY_STDOUT: bool = stdout.isatty() IS_TTY_UTF8: bool = str(stdout.encoding).lower() == 'utf-8' # Users IS_USER_SUDO: bool = ENV_SUDO_USER in environ USER_SUDO: str = environ[ENV_SUDO_USER] if IS_USER_SUDO else '' # Flush @staticmethod def flush() -> None: # Flush output print('', end='', flush=Platform.IS_TTY_STDOUT) # Userspace @staticmethod def userspace(name: str) -> Path: # Variables home: None | Path = None # Elevated home if Platform.IS_USER_SUDO: home = Path(expanduser(f'~{Platform.USER_SUDO}')) if not access(home, R_OK): home = None # Default home if not home or not home.is_dir(): home = Path.home() # Windows userspace if Platform.IS_WINDOWS: return home / 'AppData' / 'Local' / name # macOS userspace if Platform.IS_MAC_OS: return home / 'Library' / 'Preferences' / name # Linux userspace return home / '.config' / name