Add a mechanism for building a cache of "system parameters"
- Add a system_parameters module to eryntools that implements some basic types and can write a cache to a file. - Add a system-parameters Python script that builds the cache. - Add init_system_parameters to zsh that exports an environment variable that points to the parameters file - Add an eryn.system-parameters.plist LaunchAgent file for running the script at regular intervals
This commit is contained in:
		
							parent
							
								
									05b5fef583
								
							
						
					
					
						commit
						661e5516e7
					
				
					 5 changed files with 253 additions and 0 deletions
				
			
		
							
								
								
									
										27
									
								
								LaunchAgents/eryn.system-parameters.plist
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								LaunchAgents/eryn.system-parameters.plist
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,27 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | ||||
| <plist version="1.0"> | ||||
|   <dict> | ||||
|     <key>Label</key> | ||||
|     <string>eryn.system-parameters</string> | ||||
|     <key>ProgramArguments</key> | ||||
|     <array> | ||||
|         <string>/Users/eryn/bin/system-parameters</string> | ||||
|         <string>--output</string> | ||||
|         <string>/Users/eryn/.config/eryn/system_parameters.json</string> | ||||
|     </array> | ||||
|     <key>WorkingDirectory</key> | ||||
|     <string>/Users/eryn</string> | ||||
|     <key>StandardOutPath</key> | ||||
|     <string>/Users/eryn/.config/eryn/system_parameters.output.log</string> | ||||
|     <key>StandardErrorPath</key> | ||||
|     <string>/Users/eryn/.config/eryn/system_parameters.error.log</string> | ||||
|     <key>EnvironmentVariables</key> | ||||
|     <dict> | ||||
|       <key>PATH</key> | ||||
|       <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string> | ||||
|     </dict> | ||||
|     <key>RunAtLoad</key> | ||||
|     <true/> | ||||
|   </dict> | ||||
| </plist> | ||||
							
								
								
									
										169
									
								
								Python/eryntools/src/eryntools/dotfiles/system_parameters.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										169
									
								
								Python/eryntools/src/eryntools/dotfiles/system_parameters.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,169 @@ | |||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| import json | ||||
| import os.path | ||||
| import subprocess | ||||
| import sys | ||||
| from typing import Any, Optional, TextIO, Union | ||||
| 
 | ||||
| 
 | ||||
| ParameterValue = Union[str, int, float] | ||||
| ParametersObject = dict[str, Any] | ||||
| 
 | ||||
| 
 | ||||
| _PARAMETERS_FILE = "~/.config/eryn/system_parameters.json" | ||||
| 
 | ||||
| 
 | ||||
| class SystemParameters: | ||||
|     class _Keys: | ||||
|         DATA = 'data' | ||||
|         PARAMETERS = 'parameters' | ||||
|         VALUE = 'value' | ||||
| 
 | ||||
|     def __init__(self): | ||||
|         self._object: ParametersObject = {} | ||||
| 
 | ||||
|     @property | ||||
|     def parameters(self) -> dict: | ||||
|         if not self._object: | ||||
|             return {} | ||||
| 
 | ||||
|         return self._object[SystemParameters._Keys.PARAMETERS] | ||||
| 
 | ||||
|     def load_from_file(self, input_file: TextIO): | ||||
|         self._object = json.load(input_file) | ||||
| 
 | ||||
|     def write_to_file(self, file): | ||||
|         json.dump(self._object, file, indent=4, cls=_JSONEncoder) | ||||
| 
 | ||||
|     def __dir__(self): | ||||
|         return dir(self._object) | ||||
| 
 | ||||
|     def __getattr__(self, name: str) -> Optional[ParameterValue]: | ||||
|         if not self._object: | ||||
|             return None | ||||
| 
 | ||||
|         return self._object[SystemParameters._Keys.PARAMETERS][name][SystemParameters._Keys.VALUE] | ||||
| 
 | ||||
|     def __setattr__(self, name: str, value: 'Parameter'): | ||||
|         if not isinstance(value, Parameter): | ||||
|             super().__setattr__(name, value) | ||||
|             return | ||||
| 
 | ||||
|         parameter_value: ParametersObject = { | ||||
|             SystemParameters._Keys.VALUE: value.value, | ||||
|         } | ||||
| 
 | ||||
|         additional_data = value.additional_data | ||||
|         if additional_data: | ||||
|             parameter_value[SystemParameters._Keys.DATA] = additional_data | ||||
| 
 | ||||
|         self._object[name] = parameter_value | ||||
| 
 | ||||
| 
 | ||||
| class Parameter: | ||||
|     @property | ||||
|     def value(self) -> str: | ||||
|         '''The value of this parameter.''' | ||||
|         raise NotImplementedError() | ||||
| 
 | ||||
|     @property | ||||
|     def additional_data(self) -> Optional[dict[str, ParametersObject]]: | ||||
|         '''Optional additional data to include in the parameter structure.''' | ||||
|         return None | ||||
| 
 | ||||
| 
 | ||||
| class CommandParameter(Parameter): | ||||
|     class _Keys: | ||||
|         CODE = 'code' | ||||
|         COMMAND = 'command' | ||||
|         RESULT = 'result' | ||||
|         STDOUT = 'stdout' | ||||
|         STDERR = 'stderr' | ||||
| 
 | ||||
|     def __init__(self, command_arguments: list): | ||||
|         self.command = command_arguments | ||||
|         self.result: Optional[subprocess.CompletedProcess] = None | ||||
| 
 | ||||
|     @property | ||||
|     def value(self) -> str: | ||||
|         self() | ||||
|         return self.standard_output.strip() | ||||
| 
 | ||||
|     @property | ||||
|     def standard_output(self) -> str: | ||||
|         if not self.result or not self.result.stdout: | ||||
|             return '' | ||||
| 
 | ||||
|         return self.result.stdout.decode('utf-8') | ||||
| 
 | ||||
|     @property | ||||
|     def standard_error(self) -> str: | ||||
|         if not self.result or not self.result.stderr: | ||||
|             return '' | ||||
| 
 | ||||
|         return self.result.stderr.decode('utf-8') | ||||
| 
 | ||||
|     @property | ||||
|     def additional_data(self) -> Optional[dict]: | ||||
|         self() | ||||
|         assert self.result is not None | ||||
| 
 | ||||
|         obj = { | ||||
|             CommandParameter._Keys.COMMAND: self.result.args, | ||||
|             CommandParameter._Keys.RESULT: { | ||||
|                 CommandParameter._Keys.CODE: self.result.returncode, | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         stdout = self.standard_output | ||||
|         if stdout: | ||||
|             obj[CommandParameter._Keys.RESULT][CommandParameter._Keys.STDOUT] = stdout.strip() | ||||
| 
 | ||||
|         stderr = self.standard_error | ||||
|         if stderr: | ||||
|             obj[CommandParameter._Keys.RESULT][CommandParameter._Keys.STDERR] = stderr.strip() | ||||
| 
 | ||||
|         return obj | ||||
| 
 | ||||
|     def __call__(self) -> 'CommandParameter': | ||||
|         if not self.result: | ||||
|             self.result = subprocess.run( | ||||
|                 self.command, | ||||
|                 stdout=subprocess.PIPE, | ||||
|                 stderr=subprocess.STDOUT | ||||
|             ) | ||||
| 
 | ||||
|         return self | ||||
| 
 | ||||
| 
 | ||||
| class _JSONEncoder(json.JSONEncoder): | ||||
|     def default(self, o: Any) -> Any: | ||||
|         if isinstance(o, SystemParameters): | ||||
|             return super().default(o._object) | ||||
| 
 | ||||
|         return super().default(o) | ||||
| 
 | ||||
| 
 | ||||
| def main(argv) -> Optional[int]: | ||||
|     import argparse | ||||
| 
 | ||||
|     parser = argparse.ArgumentParser(prog=argv[0]) | ||||
|     parser.add_argument( | ||||
|         'parameters_file', | ||||
|         default=os.path.abspath(os.path.expanduser(_PARAMETERS_FILE)), | ||||
|         nargs='?', | ||||
|     ) | ||||
|     parser.add_argument('name') | ||||
|     arguments = parser.parse_args(argv[1:]) | ||||
| 
 | ||||
|     parameters = SystemParameters() | ||||
|     with open(arguments.parameters_file) as f: | ||||
|         parameters.load_from_file(f) | ||||
| 
 | ||||
|     print(getattr(parameters, arguments.name)) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     import sys | ||||
|     sys.exit(main(sys.argv) or 0) | ||||
							
								
								
									
										41
									
								
								bin/system-parameters
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										41
									
								
								bin/system-parameters
									
										
									
									
									
										Executable file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| #!/usr/bin/env python3 | ||||
| 
 | ||||
| import argparse | ||||
| from eryntools.dotfiles.system_parameters import CommandParameter, SystemParameters | ||||
| 
 | ||||
| 
 | ||||
| class HomebrewPrefix(CommandParameter): | ||||
|     def __init__(self): | ||||
|         super().__init__(['brew', '--prefix']) | ||||
| 
 | ||||
| 
 | ||||
| class XcodeSelectPrintPath(CommandParameter): | ||||
|     def __init__(self): | ||||
|         super().__init__(['xcode-select', '-p']) | ||||
| 
 | ||||
| 
 | ||||
| def main(argv): | ||||
|     parser = argparse.ArgumentParser(prog=argv[0]) | ||||
|     parser.add_argument('-f', '--file', type=argparse.FileType('r')) | ||||
|     parser.add_argument('-o', '--output', type=argparse.FileType('w'), default=sys.stdout) | ||||
|     arguments = parser.parse_args(argv[1:]) | ||||
| 
 | ||||
|     output_parameters = SystemParameters() | ||||
| 
 | ||||
|     if arguments.file: | ||||
|         output_parameters.load_from_file(arguments.file) | ||||
| 
 | ||||
|     parameters = { | ||||
|         'homebrew_prefix': HomebrewPrefix(), | ||||
|         'xcode_path': XcodeSelectPrintPath(), | ||||
|     } | ||||
| 
 | ||||
|     for name, parameter in parameters.items(): | ||||
|         setattr(output_parameters, name, parameter) | ||||
| 
 | ||||
|     output_parameters.write_to_file(arguments.output) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     import sys | ||||
|     sys.exit(main(sys.argv) or 0) | ||||
							
								
								
									
										15
									
								
								zsh/func/init_system_parameters
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								zsh/func/init_system_parameters
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,15 @@ | |||
| #!/usr/bin/env zsh | ||||
| # Eryn Wells <eryn@erynwells.me> | ||||
| 
 | ||||
| function init_system_parameters | ||||
| { | ||||
|     local PARAMETERS_FILE="$HOME/.config/eryn/system_parameters" | ||||
| 
 | ||||
|     if [[ ! -e "$PARAMETERS_FILE" ]]; then | ||||
|         return | ||||
|     fi | ||||
| 
 | ||||
|     export SYSTEM_PARAMETERS_FILE="$PARAMETERS_FILE" | ||||
| } | ||||
| 
 | ||||
| init_system_parameters "$@" | ||||
							
								
								
									
										1
									
								
								zshenv
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								zshenv
									
										
									
									
									
								
							|  | @ -22,6 +22,7 @@ autoload -Uz do_init_functions | |||
| 
 | ||||
| typeset -a zsh_init_env_functions=( \ | ||||
|     init_path \ | ||||
|     init_system_parameters \ | ||||
|     init_env \ | ||||
|     init_env_aliases \ | ||||
|     init_env_python \ | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue