Skip to content

Commit

Permalink
Make scripts in config.yml relative to config.yml
Browse files Browse the repository at this point in the history
Make the paths to scripts found in config.yml relative to
the directory where config.yml is instead of where the command
is ran.
  • Loading branch information
Lucas FICHEUX committed Oct 13, 2021
1 parent 8b6345e commit ee31f1b
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 2 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -12,6 +12,7 @@
* New content view which handles gRPC/protobuf. Allows to apply custom definitions to visualize different field decodings.
Includes example addon which applies custom definitions for selected gRPC traffic (@mame82)
* Fix a crash caused when editing string option (#4852, @rbdixon)
* Scripts with relative paths are now loaded relative to the config file and not where the command is ran

## 28 September 2021: mitmproxy 7.0.4

Expand Down
26 changes: 24 additions & 2 deletions mitmproxy/optmanager.py
Expand Up @@ -505,12 +505,17 @@ def parse(text):
return data


def load(opts: OptManager, text: str) -> None:
def load(opts: OptManager, text: str, config_path: str=None) -> None:
"""
Load configuration from text, over-writing options already set in
this object. May raise OptionsError if the config file is invalid.
"""
data = parse(text)

scripts = data.get('scripts')
if scripts is not None and config_path is not None:
data['scripts'] = [compute_path(path, config_path) for path in scripts]

opts.update_defer(**data)


Expand All @@ -531,7 +536,7 @@ def load_paths(opts: OptManager, *paths: str) -> None:
f"Error reading {p}: {e}"
)
try:
load(opts, txt)
load(opts, txt, config_path=p)
except exceptions.OptionsError as e:
raise exceptions.OptionsError(
f"Error reading {p}: {e}"
Expand Down Expand Up @@ -580,3 +585,20 @@ def save(opts: OptManager, path: str, defaults: bool =False) -> None:

with open(path, "wt", encoding="utf8") as f:
serialize(opts, f, data, defaults)


def compute_path(script_path: str, config_path: str) -> str:
"""
Make relative paths found in config files relative to said config file,
instead of relative to where the command is ran.
"""
if os.path.isabs(script_path):
return script_path
if script_path != os.path.expanduser(script_path):
return script_path
return os.path.abspath(
os.path.join(
os.path.dirname(config_path),
script_path
)
)
96 changes: 96 additions & 0 deletions test/mitmproxy/test_optmanager.py
@@ -1,9 +1,12 @@
import copy
import io
import os
import pytest
import typing
import argparse

import ruamel.yaml

from mitmproxy import options
from mitmproxy import optmanager
from mitmproxy import exceptions
Expand Down Expand Up @@ -39,6 +42,13 @@ def __init__(self):
self.add_option("one", typing.Optional[str], None, "help")


class TS(optmanager.OptManager):
def __init__(self):
super().__init__()
self.add_option("scripts", typing.Sequence[str], [], "help")
self.add_option("not_scripts", typing.Sequence[str], [], "help")


def test_defaults():
o = TD2()
defaults = {
Expand Down Expand Up @@ -459,3 +469,89 @@ def test_set():
opts.process_deferred()
assert "deferredsequenceoption" not in opts.deferred
assert opts.deferredsequenceoption == ["a", "b"]


def test_relative_script_path(tmpdir):
opts = TS()
conf_path = os.path.join(tmpdir, 'config.yaml')

conf = {'not_scripts': ['abc', ]}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']

conf = {'not_scripts': ['~/abc', ]}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']

conf = {'not_scripts': ['/abc', ]}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']

conf = {'not_scripts': ['./abc', ]}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']

conf = {
'not_scripts': ['abc', ],
'scripts': ['abc', ],
}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']
assert opts.scripts[0] == os.path.abspath(os.path.join(tmpdir, conf['scripts'][0]))

conf = {
'not_scripts': ['~/abc', ],
'scripts': ['~/abc', ],
}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']
assert opts.scripts == conf['scripts']

conf = {
'not_scripts': ['/abc', ],
'scripts': ['/abc', ],
}

with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']
assert opts.scripts == conf['scripts']

conf = {
'not_scripts': ['./abc', ],
'scripts': ['./abc'],
}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.not_scripts == conf['not_scripts']
assert opts.scripts[0] == os.path.abspath(os.path.join(tmpdir, conf['scripts'][0]))

conf = {
'scripts': [
'abc',
'~/abc',
'/abc',
'./abc',
]
}
with open(conf_path, 'w') as f:
ruamel.yaml.YAML().dump(conf, f)
optmanager.load_paths(opts, conf_path)
assert opts.scripts[0] == os.path.abspath(os.path.join(tmpdir, conf['scripts'][0]))
assert opts.scripts[1] == conf['scripts'][1]
assert opts.scripts[2] == conf['scripts'][2]
assert opts.scripts[3] == os.path.abspath(os.path.join(tmpdir, conf['scripts'][3]))

0 comments on commit ee31f1b

Please sign in to comment.