mirror of
https://github.com/beetbox/beets.git
synced 2025-12-30 12:32:33 +01:00
Add config command
This commit is contained in:
parent
d0e5b411cf
commit
c8e32f6bef
4 changed files with 197 additions and 1 deletions
|
|
@ -23,6 +23,8 @@ import time
|
|||
import itertools
|
||||
import codecs
|
||||
from datetime import datetime
|
||||
import yaml
|
||||
import platform
|
||||
|
||||
import beets
|
||||
from beets import ui
|
||||
|
|
@ -35,6 +37,7 @@ from beets import importer
|
|||
from beets import util
|
||||
from beets.util import syspath, normpath, ancestry, displayable_path
|
||||
from beets.util.functemplate import Template
|
||||
from beets.util.confit import ConfigTypeError
|
||||
from beets import library
|
||||
from beets import config
|
||||
|
||||
|
|
@ -1286,3 +1289,58 @@ def write_func(lib, opts, args):
|
|||
write_items(lib, decargs(args), opts.pretend)
|
||||
write_cmd.func = write_func
|
||||
default_commands.append(write_cmd)
|
||||
|
||||
|
||||
config_cmd = ui.Subcommand('config', help='show or edit the user configuration')
|
||||
config_cmd.parser.add_option('-p', '--paths', action='store_true',
|
||||
help='show files that configuration was loaded from')
|
||||
config_cmd.parser.add_option('-e', '--edit', action='store_true',
|
||||
help='edit user configuration with $EDITOR')
|
||||
config_cmd.parser.add_option('-d', '--defaults', action='store_true',
|
||||
help='include the default configuration')
|
||||
def _config_get(view):
|
||||
try:
|
||||
keys = view.keys()
|
||||
except ConfigTypeError:
|
||||
return view.get()
|
||||
else:
|
||||
return dict((key, _config_get(view[key])) for key in view.keys())
|
||||
def config_func(lib, opts, args):
|
||||
# Make sure lazy configuration is loaded
|
||||
config.resolve()
|
||||
|
||||
if not opts.defaults:
|
||||
# Remove default source
|
||||
config.sources = [source for source in config.sources if not source.default]
|
||||
|
||||
if opts.paths:
|
||||
for source in config.sources:
|
||||
if source.filename:
|
||||
print(source.filename)
|
||||
elif opts.edit:
|
||||
path = config.user_config_path()
|
||||
|
||||
if 'EDITOR' in os.environ:
|
||||
editor = os.environ['EDITOR']
|
||||
args = [editor, editor, path]
|
||||
elif platform.system() == 'Darwin':
|
||||
args = ['open', 'open', '-n', path]
|
||||
elif platform.system() == 'Windows':
|
||||
# On windows we can execute arbitrary files. The os will
|
||||
# take care of starting an appropriate application
|
||||
args = [path, path]
|
||||
else:
|
||||
# Assume Unix
|
||||
args = ['xdg-open', 'xdg-open', path]
|
||||
|
||||
try:
|
||||
os.execlp(*args)
|
||||
except OSError:
|
||||
raise ui.UserError("Could not edit configuration. Please"
|
||||
"set the EDITOR environment variable.")
|
||||
else:
|
||||
config_dict = _config_get(config)
|
||||
print(yaml.safe_dump(config_dict, default_flow_style=False))
|
||||
|
||||
config_cmd.func = config_func
|
||||
default_commands.append(config_cmd)
|
||||
|
|
|
|||
|
|
@ -621,11 +621,18 @@ class Configuration(RootView):
|
|||
if read:
|
||||
self.read()
|
||||
|
||||
def user_config_path(self):
|
||||
"""Points to the location of the user configuration.
|
||||
|
||||
The file may not exist.
|
||||
"""
|
||||
return os.path.join(self.config_dir(), CONFIG_FILENAME)
|
||||
|
||||
def _add_user_source(self):
|
||||
"""Add ``ConfigSource`` for the configuration file in
|
||||
``config_dir()`` if it exists.
|
||||
"""
|
||||
filename = os.path.join(self.config_dir(), CONFIG_FILENAME)
|
||||
filename = self.user_config_path()
|
||||
if os.path.isfile(filename):
|
||||
self.add(ConfigSource(load_yaml(filename) or {}, filename))
|
||||
|
||||
|
|
@ -720,3 +727,9 @@ class LazyConfig(Configuration):
|
|||
# Buffer additions to beginning.
|
||||
self._lazy_prefix[:0] = self.sources
|
||||
del self.sources[:]
|
||||
|
||||
def clear(self):
|
||||
"""Remove all sources from this configuration."""
|
||||
del self.sources[:]
|
||||
self._lazy_suffix = []
|
||||
self._lazy_prefix = []
|
||||
|
|
|
|||
|
|
@ -268,3 +268,13 @@ def platform_posix():
|
|||
os.path = posixpath
|
||||
yield
|
||||
os.path = old_path
|
||||
|
||||
@contextmanager
|
||||
def system_mock(name):
|
||||
import platform
|
||||
old_system = platform.system
|
||||
platform.system = lambda: name
|
||||
try:
|
||||
yield
|
||||
finally:
|
||||
platform.system = old_system
|
||||
|
|
|
|||
115
test/test_config_command.py
Normal file
115
test/test_config_command.py
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import os
|
||||
import yaml
|
||||
|
||||
from beets import ui
|
||||
from beets import config
|
||||
|
||||
import _common
|
||||
|
||||
|
||||
class ConfigCommandTest(_common.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ConfigCommandTest, self).setUp()
|
||||
self.io.install()
|
||||
|
||||
if 'EDITOR' in os.environ:
|
||||
del os.environ['EDITOR']
|
||||
|
||||
os.environ['BEETSDIR'] = self.temp_dir
|
||||
self.config_path = os.path.join(self.temp_dir, 'config.yaml')
|
||||
with open(self.config_path, 'w') as file:
|
||||
file.write('library: lib\n')
|
||||
file.write('option: value')
|
||||
|
||||
self.cli_config_path = os.path.join(self.temp_dir, 'cli_config.yaml')
|
||||
with open(self.cli_config_path, 'w') as file:
|
||||
file.write('option: cli overwrite')
|
||||
|
||||
config.clear()
|
||||
config._materialized = False
|
||||
|
||||
def tearDown(self):
|
||||
super(ConfigCommandTest, self).tearDown()
|
||||
self.execlp_restore()
|
||||
|
||||
def test_show_user_config(self):
|
||||
ui._raw_main(['config'])
|
||||
output = yaml.load(self.io.getoutput())
|
||||
self.assertEqual(output['option'], 'value')
|
||||
|
||||
def test_show_user_config_with_defaults(self):
|
||||
ui._raw_main(['config', '-d'])
|
||||
output = yaml.load(self.io.getoutput())
|
||||
self.assertEqual(output['option'], 'value')
|
||||
self.assertEqual(output['library'], 'lib')
|
||||
self.assertEqual(output['import']['timid'], False)
|
||||
|
||||
def test_show_user_config_with_cli(self):
|
||||
ui._raw_main(['--config', self.cli_config_path, 'config'])
|
||||
output = yaml.load(self.io.getoutput())
|
||||
self.assertEqual(output['library'], 'lib')
|
||||
self.assertEqual(output['option'], 'cli overwrite')
|
||||
|
||||
def test_config_paths(self):
|
||||
ui._raw_main(['config', '-p'])
|
||||
paths = self.io.getoutput().split('\n')
|
||||
self.assertEqual(len(paths), 2)
|
||||
self.assertEqual(paths[0], self.config_path)
|
||||
|
||||
def test_config_paths_with_cli(self):
|
||||
ui._raw_main(['--config', self.cli_config_path, 'config', '-p'])
|
||||
paths = self.io.getoutput().split('\n')
|
||||
self.assertEqual(len(paths), 3)
|
||||
self.assertEqual(paths[0], self.cli_config_path)
|
||||
|
||||
def test_edit_config_with_editor_env(self):
|
||||
self.execlp_stub()
|
||||
os.environ['EDITOR'] = 'myeditor'
|
||||
|
||||
ui._raw_main(['config', '-e'])
|
||||
self.assertEqual(self._execlp_call, ['myeditor', self.config_path])
|
||||
|
||||
def test_edit_config_with_open(self):
|
||||
self.execlp_stub()
|
||||
|
||||
with _common.system_mock('Darwin'):
|
||||
ui._raw_main(['config', '-e'])
|
||||
self.assertEqual(self._execlp_call, ['open', '-n', self.config_path])
|
||||
|
||||
|
||||
def test_edit_config_with_xdg_open(self):
|
||||
self.execlp_stub()
|
||||
|
||||
with _common.system_mock('Linux'):
|
||||
ui._raw_main(['config', '-e'])
|
||||
self.assertEqual(self._execlp_call, ['xdg-open', self.config_path])
|
||||
|
||||
def test_edit_config_with_windows_exec(self):
|
||||
self.execlp_stub()
|
||||
|
||||
with _common.system_mock('Windows'):
|
||||
ui._raw_main(['config', '-e'])
|
||||
self.assertEqual(self._execlp_call, [self.config_path])
|
||||
|
||||
def test_config_editor_not_found(self):
|
||||
def raise_os_error(*args):
|
||||
raise OSError
|
||||
os.execlp = raise_os_error
|
||||
with self.assertRaises(ui.UserError) as user_error:
|
||||
ui._raw_main(['config', '-e'])
|
||||
self.assertIn('Could not edit configuration',
|
||||
str(user_error.exception.args[0]))
|
||||
|
||||
|
||||
def execlp_stub(self):
|
||||
self._execlp_call = None
|
||||
def _execlp_stub(file, *args):
|
||||
self._execlp_call = [file] + list(args[1:])
|
||||
|
||||
self._orig_execlp = os.execlp
|
||||
os.execlp = _execlp_stub
|
||||
|
||||
def execlp_restore(self):
|
||||
if hasattr(self, '_orig_execlp'):
|
||||
os.execlp = self._orig_execlp
|
||||
Loading…
Reference in a new issue