Don't fail if config dir not writeable (close #738)

This commit is contained in:
Jakub Roztocil 2019-08-29 14:05:00 +02:00
parent d998013655
commit 9bd8b4e8f7
5 changed files with 25 additions and 42 deletions

View File

@ -14,11 +14,12 @@ This project adheres to `Semantic Versioning <http://semver.org/>`_.
* Added ``--max-headers`` to allow setting the max header limit. * Added ``--max-headers`` to allow setting the max header limit.
* Added ``--compress``. * Added ``--compress``.
* Added ``https`` alias command with ``https://`` as the default scheme. * Added ``https`` alias command with ``https://`` as the default scheme.
* Fixed an exception when ``stdin`` was a closed fd. * Fixed an error when ``stdin`` was a closed fd.
* Fixed an error when the config directory was not writeable.
`1.0.3`_ (2019-08-26) `1.0.3`_ (2019-08-26)
------------------------- ---------------------
* Fixed CVE-2019-10751 — the way the output filename is generated for * Fixed CVE-2019-10751 — the way the output filename is generated for
``--download`` requests without ``--output`` resulting in a redirect has ``--download`` requests without ``--output`` resulting in a redirect has

View File

@ -55,7 +55,7 @@ class BaseConfigDict(dict):
if e.errno != errno.ENOENT: if e.errno != errno.ENOENT:
raise raise
def save(self): def save(self, fail_silently=False):
self['__meta__'] = { self['__meta__'] = {
'httpie': __version__ 'httpie': __version__
} }
@ -65,9 +65,13 @@ class BaseConfigDict(dict):
if self.about: if self.about:
self['__meta__']['about'] = self.about self['__meta__']['about'] = self.about
with open(self.path, 'w') as f: try:
json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True) with open(self.path, 'w') as f:
f.write('\n') json.dump(self, f, indent=4, sort_keys=True, ensure_ascii=True)
f.write('\n')
except IOError:
if not fail_silently:
raise
def delete(self): def delete(self):
try: try:
@ -92,21 +96,5 @@ class Config(BaseConfigDict):
self.update(self.DEFAULTS) self.update(self.DEFAULTS)
self.directory = directory self.directory = directory
def load(self):
super(Config, self).load()
self._migrate_implicit_content_type()
def _get_path(self): def _get_path(self):
return os.path.join(self.directory, self.name + '.json') return os.path.join(self.directory, self.name + '.json')
def _migrate_implicit_content_type(self):
"""Migrate the removed implicit_content_type config option"""
try:
implicit_content_type = self.pop('implicit_content_type')
except KeyError:
self.save()
else:
if implicit_content_type == 'form':
self['default_options'].insert(0, '--form')
self.save()
self.load()

View File

@ -82,7 +82,7 @@ class Environment(object):
if not hasattr(self, '_config'): if not hasattr(self, '_config'):
self._config = Config(directory=self.config_dir) self._config = Config(directory=self.config_dir)
if self._config.is_new(): if self._config.is_new():
self._config.save() self._config.save(fail_silently=True)
else: else:
self._config.load() self._config.load()
return self._config return self._config

View File

@ -1,5 +1,5 @@
from httpie import __version__ from httpie import __version__
from utils import MockEnvironment, http from utils import MockEnvironment, http, HTTP_OK
from httpie.context import Environment from httpie.context import Environment
@ -11,6 +11,14 @@ def test_default_options(httpbin):
assert r.json['form'] == {"foo": "bar"} assert r.json['form'] == {"foo": "bar"}
def test_config_dir_not_writeable(httpbin):
r = http(httpbin + '/get', env=MockEnvironment(
config_dir='/',
create_temp_config_dir=False,
))
assert HTTP_OK in r
def test_default_options_overwrite(httpbin): def test_default_options_overwrite(httpbin):
env = MockEnvironment() env = MockEnvironment()
env.config['default_options'] = ['--form'] env.config['default_options'] = ['--form']
@ -19,22 +27,6 @@ def test_default_options_overwrite(httpbin):
assert r.json['json'] == {"foo": "bar"} assert r.json['json'] == {"foo": "bar"}
def test_migrate_implicit_content_type():
config = MockEnvironment().config
config['implicit_content_type'] = 'json'
config.save()
config.load()
assert 'implicit_content_type' not in config
assert not config['default_options']
config['implicit_content_type'] = 'form'
config.save()
config.load()
assert 'implicit_content_type' not in config
assert config['default_options'] == ['--form']
def test_current_version(): def test_current_version():
version = Environment().config['__meta__']['httpie'] version = Environment().config['__meta__']['httpie']
assert version == __version__ assert version == __version__

View File

@ -39,7 +39,8 @@ class MockEnvironment(Environment):
stdout_isatty = True stdout_isatty = True
is_windows = False is_windows = False
def __init__(self, **kwargs): def __init__(self, create_temp_config_dir=True, **kwargs):
self.create_temp_config_dir = create_temp_config_dir
if 'stdout' not in kwargs: if 'stdout' not in kwargs:
kwargs['stdout'] = tempfile.TemporaryFile( kwargs['stdout'] = tempfile.TemporaryFile(
mode='w+b', mode='w+b',
@ -55,7 +56,8 @@ class MockEnvironment(Environment):
@property @property
def config(self): def config(self):
if not self.config_dir.startswith(tempfile.gettempdir()): if (self.create_temp_config_dir
and not self.config_dir.startswith(tempfile.gettempdir())):
self.config_dir = mk_config_dir() self.config_dir = mk_config_dir()
self._delete_config_dir = True self._delete_config_dir = True
return super(MockEnvironment, self).config return super(MockEnvironment, self).config