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=( \
|
typeset -a zsh_init_env_functions=( \
|
||||||
init_path \
|
init_path \
|
||||||
|
init_system_parameters \
|
||||||
init_env \
|
init_env \
|
||||||
init_env_aliases \
|
init_env_aliases \
|
||||||
init_env_python \
|
init_env_python \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue