new: add a cli.config_dir
This commit is contained in:
parent
c1592e19a9
commit
4e2a63ae76
5 changed files with 47 additions and 23 deletions
8
ci_tests
8
ci_tests
|
|
@ -8,7 +8,7 @@ PYTHON_ARGCOMPLETE_OK
|
|||
import os
|
||||
from pathlib import Path
|
||||
from shutil import rmtree
|
||||
from subprocess import CalledProcessError, run
|
||||
from subprocess import CalledProcessError, DEVNULL, run
|
||||
|
||||
from milc import set_metadata
|
||||
|
||||
|
|
@ -26,19 +26,19 @@ def main(cli):
|
|||
|
||||
cli.log.info('Running nose2 tests...')
|
||||
cmd = ['nose2']
|
||||
result = run(cmd)
|
||||
result = run(cmd, stdin=DEVNULL)
|
||||
if result.returncode != 0:
|
||||
build_ok = False
|
||||
|
||||
cli.log.info('Running flake8...')
|
||||
cmd = ['flake8']
|
||||
result = run(cmd)
|
||||
result = run(cmd, stdin=DEVNULL)
|
||||
if result.returncode != 0:
|
||||
build_ok = False
|
||||
|
||||
cli.log.info('Running yapf...')
|
||||
cmd = ['yapf', '-q', '-r', '.']
|
||||
result = run(cmd)
|
||||
result = run(cmd, stdin=DEVNULL)
|
||||
if result.returncode != 0:
|
||||
build_ok = False
|
||||
cli.log.error('Improperly formatted code. Please run this: yapf -i -r .')
|
||||
|
|
|
|||
|
|
@ -32,16 +32,19 @@ Use `cli.save_config()` to save the user's configuration file. It will be writte
|
|||
|
||||
# Configuration File Location
|
||||
|
||||
MILC uses [appdirs](https://github.com/ActiveState/appdirs) to determine the configuration file location. You can set your application's name and author by setting environment variables:
|
||||
MILC uses [appdirs](https://github.com/ActiveState/appdirs) to determine the configuration file location. You can set your application's name and author by using `milc.set_metadata`:
|
||||
|
||||
os.environ['MILC_APP_NAME'] = 'hello'
|
||||
os.environ['MILC_AUTHOR_NAME'] = 'Hello Author'
|
||||
```python
|
||||
from milc import set_metadata
|
||||
|
||||
set_metadata('Florzelbop', '1.0.0', 'Jane Doe')
|
||||
```
|
||||
|
||||
This will (usually) result in the following config file locations:
|
||||
|
||||
* Linux: `~/.local/share/hello`
|
||||
* macOS: `~/Library/Application Support/hello`
|
||||
* Windows: `C:\Documents and Settings\<User>\Application Data\Local Settings\Hello Author\hello`
|
||||
* Linux: `~/.local/share/Florzelbop`
|
||||
* macOS: `~/Library/Application Support/Florzelbop`
|
||||
* Windows: `C:\Documents and Settings\<User>\Application Data\Local Settings\Florzelbop Jane Doe\hello`
|
||||
|
||||
# Where Did A Value Come From?
|
||||
|
||||
|
|
|
|||
6
example
6
example
|
|
@ -68,5 +68,11 @@ def goodbye(cli):
|
|||
cli.echo('{fg_blue}Goodbye, %s!', cli.config.general.name)
|
||||
|
||||
|
||||
@cli.subcommand('Show the configured config file and directory.')
|
||||
def config_file(cli):
|
||||
cli.echo(f'cli.config_file={cli.config_file}')
|
||||
cli.echo(f'cli.config_dir={cli.config_dir}')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
cli()
|
||||
|
|
|
|||
28
milc/milc.py
28
milc/milc.py
|
|
@ -7,6 +7,7 @@ import subprocess
|
|||
import shlex
|
||||
import sys
|
||||
from decimal import Decimal
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from platform import platform
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
|
@ -44,6 +45,7 @@ class MILC(object):
|
|||
|
||||
# Define some basic info
|
||||
self.acquire_lock()
|
||||
self.prog_name = name
|
||||
self.version = version
|
||||
self.author = author
|
||||
self._config_store_true = []
|
||||
|
|
@ -55,10 +57,9 @@ class MILC(object):
|
|||
self._inside_context_manager = False
|
||||
self.ansi = ansi_colors
|
||||
self.arg_only = {}
|
||||
self.config_file = None
|
||||
self.config_file = self.find_config_file()
|
||||
self.default_arguments = {}
|
||||
self.platform = platform()
|
||||
self.prog_name = name
|
||||
self.interactive = sys.stdin.isatty()
|
||||
self.release_lock()
|
||||
self._deprecated_arguments = {}
|
||||
|
|
@ -69,6 +70,10 @@ class MILC(object):
|
|||
self.initialize_argparse()
|
||||
self.initialize_logging()
|
||||
|
||||
@property
|
||||
def config_dir(self):
|
||||
return self.config_file.parent
|
||||
|
||||
@property
|
||||
def description(self):
|
||||
return self._description
|
||||
|
|
@ -267,6 +272,7 @@ class MILC(object):
|
|||
if self._lock:
|
||||
self._lock.release()
|
||||
|
||||
@lru_cache(maxsize=None)
|
||||
def find_config_file(self):
|
||||
"""Locate the config file.
|
||||
"""
|
||||
|
|
@ -343,15 +349,15 @@ class MILC(object):
|
|||
|
||||
self.release_lock()
|
||||
|
||||
def read_config_file(self, config_file):
|
||||
def read_config_file(self):
|
||||
"""Read in the configuration file and return Configuration objects for it and the config_source.
|
||||
"""
|
||||
config = Configuration()
|
||||
config_source = Configuration()
|
||||
|
||||
if config_file.exists():
|
||||
if self.config_file.exists():
|
||||
raw_config = RawConfigParser()
|
||||
raw_config.read(str(config_file))
|
||||
raw_config.read(str(self.config_file))
|
||||
|
||||
# Iterate over the config file options and write them into config
|
||||
for section in raw_config.sections():
|
||||
|
|
@ -380,8 +386,7 @@ class MILC(object):
|
|||
"""Read in the configuration file and store it in self.config.
|
||||
"""
|
||||
self.acquire_lock()
|
||||
self.config_file = self.find_config_file()
|
||||
self.config, self.config_source = self.read_config_file(self.config_file)
|
||||
self.config, self.config_source = self.read_config_file()
|
||||
self.release_lock()
|
||||
|
||||
def merge_args_into_config(self):
|
||||
|
|
@ -435,13 +440,12 @@ class MILC(object):
|
|||
if self.config_source[section_name][option_name] == 'config_file' and value is not None:
|
||||
sane_config.set(section_name, option_name, str(value))
|
||||
|
||||
config_dir = self.config_file.parent
|
||||
if not config_dir.exists():
|
||||
config_dir.mkdir(parents=True, exist_ok=True)
|
||||
if not self.config_dir.exists():
|
||||
self.config_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Write the config file atomically.
|
||||
self.acquire_lock()
|
||||
with NamedTemporaryFile(mode='w', dir=str(config_dir), delete=False) as tmpfile:
|
||||
with NamedTemporaryFile(mode='w', dir=str(self.config_dir), delete=False) as tmpfile:
|
||||
sane_config.write(tmpfile)
|
||||
|
||||
if os.path.getsize(tmpfile.name) > 0:
|
||||
|
|
@ -457,7 +461,7 @@ class MILC(object):
|
|||
self.log.warning('%s.config_file not set, not saving config!', self.__class__.__name__)
|
||||
return
|
||||
|
||||
config, config_source = self.read_config_file(self.config_file)
|
||||
config, config_source = self.read_config_file()
|
||||
|
||||
if section in config and option in config[section] and config[section][option] is None:
|
||||
del config[section][option]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ from .common import check_assert, check_command, check_returncode
|
|||
def test_example():
|
||||
result = check_command('./example', '-h')
|
||||
check_returncode(result)
|
||||
check_assert(result, '{config,dashed-hello,hello,goodbye}' in result.stdout)
|
||||
check_assert(result, '{config,dashed-hello,hello,goodbye,config-file}' in result.stdout)
|
||||
|
||||
|
||||
def test_example_version():
|
||||
|
|
@ -91,3 +91,14 @@ def test_example_dashed_hello_dashed_name():
|
|||
result = check_command('./example', 'dashed-hello', '--dashed-name', 'Tester')
|
||||
check_returncode(result)
|
||||
check_assert(result, result.stdout == 'Hello, dashed-subcommand Tester!\n')
|
||||
|
||||
|
||||
def test_example_config_file():
|
||||
result = check_command('./example', 'config-file')
|
||||
check_returncode(result)
|
||||
lines = result.stdout.split('\n')
|
||||
filename = lines[0].split('=', 1)[1]
|
||||
filedir = lines[1].split('=', 1)[1]
|
||||
check_assert(result, len(lines) == 3)
|
||||
check_assert(result, filename.endswith('example.ini'))
|
||||
check_assert(result, filename.startswith(filedir))
|
||||
|
|
|
|||
Loading…
Reference in a new issue