Skip to content

Commit

Permalink
Support for relative start_directory when loading outside of cwd (wor…
Browse files Browse the repository at this point in the history
…k in progress

- behavior of .expand to honor os.path.expanduser at the time of expansion, rather than when building.
- expandpath function
- tests, docs
  • Loading branch information
tony committed Aug 6, 2014
1 parent 3887bdc commit f994684
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 12 deletions.
9 changes: 9 additions & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ Here you can find the recent changes to tmuxp.

- [config] :meth:`config.expand` now resolves directories in configuration
via :py:func:`os.path.expanduser` and :py:func:`os.path.expandvars`.
- [config] :meth:`config.expandpath` for helping resolve paths.
- [builder] [cli] improved support for loading tmuxp project files from
outside current working directory. e.g.

.. code-block:: bash
$ tmuxp load /path/to/my/project/.tmuxp.yaml
Will behave better with relative directories.

0.1.11
------
Expand Down
2 changes: 2 additions & 0 deletions doc/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ Import and export

.. automethod:: tmuxp.config.validate_schema

.. automethod:: tmuxp.config.expandpath

.. automethod:: tmuxp.config.expand

.. automethod:: tmuxp.config.inline
Expand Down
28 changes: 25 additions & 3 deletions tmuxp/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,18 @@ def in_cwd():

return configs

def expandpath(_path):
"""Return expanded path based on user's ``$HOME`` and ``env``.
:py:func:`os.path.expanduser` and :py:func:`os.path.expandvars`
:param _path: path to expand
:type _path: string
:returns: expanded path
:rtype: string
"""
return os.path.expandvars(os.path.expanduser(_path))

def inline(sconf):
""" Return config in inline form, opposite of :meth:`config.expand`.
Expand Down Expand Up @@ -139,7 +151,7 @@ def inline(sconf):
return sconf


def expand(sconf, cwd=None):
def expand(sconf, cwd=None, parent=None):
"""Return config with shorthand and inline properties expanded.
This is necessary to keep the code in the :class:`WorkspaceBuilder` clean
Expand Down Expand Up @@ -172,11 +184,21 @@ def expand(sconf, cwd=None):
# Any config section, session, window, pane that can contain the
# 'shell_command' value
if 'start_directory' in sconf:
sconf['start_directory'] = expandpath(sconf['start_directory'])
start_path = sconf['start_directory']
if any(start_path.startswith(a) for a in ['.', './']):
# if window has a session, or pane has a window with a
# start_directory of . or ./, make sure the start_directory can be
# relative to the parent.
#
# This is for the case where you may be loading a config from
# outside your shell current directory.
if parent:
cwd = parent['start_directory']
start_path = os.path.normpath(os.path.join(cwd, start_path))
sconf['start_directory'] = start_path


if 'before_script' in sconf:
before_script = sconf['before_script']
if any(before_script.startswith(a) for a in ['.', './']):
Expand All @@ -198,7 +220,7 @@ def expand(sconf, cwd=None):
# recurse into window and pane config items
if 'windows' in sconf:
sconf['windows'] = [
expand(window) for window in sconf['windows']
expand(window, parent=sconf) for window in sconf['windows']
]
elif 'panes' in sconf:

Expand Down Expand Up @@ -235,7 +257,7 @@ def expand(sconf, cwd=None):
p['shell_command'] = []

pconf.update(p)
sconf['panes'] = [expand(pane) for pane in sconf['panes']]
sconf['panes'] = [expand(pane, parent=sconf) for pane in sconf['panes']]

return sconf

Expand Down
18 changes: 10 additions & 8 deletions tmuxp/testsuite/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ class ExpandTest(TestCase):

after_config = {
'session_name': 'sampleconfig',
'start_directory': '~',
'start_directory': os.path.expanduser('~'),
'windows': [
{
'window_name': 'editor',
Expand Down Expand Up @@ -246,19 +246,19 @@ class ExpandTest(TestCase):
]
},
{
'start_directory': os.path.abspath('./'),
'start_directory': os.path.normpath(os.path.join(os.path.join(os.path.expanduser('~'), './'))),
'panes': [
{'shell_command': ['pwd']}
]
},
{
'start_directory': os.path.abspath('./asdf/'),
'start_directory': os.path.normpath(os.path.join(os.path.join(os.path.expanduser('~'), './asdf'))),
'panes': [
{'shell_command': ['pwd']}
]
},
{
'start_directory': os.path.abspath('../'),
'start_directory': os.path.normpath(os.path.join(os.path.expanduser('~'), '../')),
'panes': [
{'shell_command': ['pwd']}
]
Expand Down Expand Up @@ -317,7 +317,7 @@ def test_no_window_name(self):

expanded_yaml = """
session_name: sampleconfig
start_directory: '~'
start_directory: {HOME}
windows:
- window_name: focused window
layout: main-horizontal
Expand Down Expand Up @@ -348,7 +348,9 @@ def test_no_window_name(self):
focus: true
- shell_command: []
- shell_command: []
"""
""".format(
HOME=os.path.expanduser('~')
)

self.maxDiff = None

Expand Down Expand Up @@ -622,7 +624,7 @@ class ShellCommandBeforeTest(TestCase):
'windows': [
{
'window_name': 'editor',
'start_directory': '~',
'start_directory': os.path.expanduser('~'),
'shell_command_before': ['source .env/bin/activate'],
'panes': [
{
Expand Down Expand Up @@ -676,7 +678,7 @@ class ShellCommandBeforeTest(TestCase):
'windows': [
{
'window_name': 'editor',
'start_directory': '~',
'start_directory': os.path.expanduser('~'),
'shell_command_before': ['source .env/bin/activate'],
'panes': [
{
Expand Down
115 changes: 114 additions & 1 deletion tmuxp/testsuite/workspacebuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,8 @@ def tearDown(self):

def test_start_directory(self):

start_directory = os.getcwd()

sconfig = kaptan.Kaptan(handler='yaml')
sconfig = sconfig.import_config(self.yaml_config).get()
sconfig = config.expand(sconfig)
Expand All @@ -441,7 +443,117 @@ def test_start_directory(self):
builder.build(session=self.session)

assert(self.session == builder.session)
dirs = ['/usr/bin', '/dev', '/tmp/foo bar', '/usr', os.getcwd()]
dirs = ['/usr/bin', '/dev', '/tmp/foo bar', '/usr', '/usr']
for path, window in zip(dirs, self.session.windows):
for p in window.panes:
for i in range(60):
p.server._update_panes()
if p.get('pane_current_path') == path:
break
time.sleep(.2)

self.assertEqual(p.get('pane_current_path'), path)


class StartDirectoryRelativeTest(TmuxTestCase):
"""Same as above test, but with relative start directory, mimicing
loading it from a location of project file. Like::
$ tmuxp load ~/workspace/myproject/.tmuxp.yaml
instead of::
$ cd ~/workspace/myproject/.tmuxp.yaml
$ tmuxp load .
"""

yaml_config = """
session_name: sampleconfig
start_directory: ./
windows:
- window_name: supposed to be /usr/bin
start_directory: '/usr/bin'
layout: main-horizontal
options:
main-pane-height: 50
panes:
- shell_command:
- echo "hey"
- shell_command:
- echo "moo"
- window_name: support to be /dev
start_directory: '/dev'
layout: main-horizontal
panes:
- shell_command:
- pwd
- shell_command:
- echo "hey"
- shell_command:
- echo "moo"
- window_name: cwd containing a space
start_directory: /tmp/foo bar
layout: main-horizontal
panes:
- shell_command:
- pwd
- shell_command:
- echo "hey"
- shell_command:
- echo "moo"
- window_name: testsa3
layout: main-horizontal
panes:
- shell_command:
- pwd
- shell_command:
- echo "hey"
- shell_command:
- echo "moo3"
- window_name: cwd relative to config file
layout: main-horizontal
start_directory: ./
panes:
- shell_command:
- pwd
- shell_command:
- echo "hey"
- shell_command:
- echo "moo3"
"""

def setUp(self):
super(StartDirectoryRelativeTest, self).setUp()
if not os.path.exists('/tmp/foo bar') and not os.path.exists('/tmp/testRelConfigDir'):
os.mkdir('/tmp/foo bar')
os.mkdir('/tmp/testRelConfigDir')
self._temp_dir_created = True
else:
self._temp_dir_created = False

def tearDown(self):
super(StartDirectoryRelativeTest, self).tearDown()
if self._temp_dir_created:
os.rmdir('/tmp/foo bar')
os.rmdir('/tmp/testRelConfigDir')

def test_start_directory(self):

start_directory = os.getcwd()

sconfig = kaptan.Kaptan(handler='yaml')
sconfig = sconfig.import_config(self.yaml_config).get()
# the second argument of os.getcwd() mimics the behavior
# the CLI loader will do, but it passes in the config file's location.
sconfig = config.expand(sconfig, '/tmp/testRelConfigDir')
sconfig = config.trickle(sconfig)

builder = WorkspaceBuilder(sconf=sconfig)
builder.build(session=self.session)

assert(self.session == builder.session)
dirs = ['/usr/bin', '/dev', '/tmp/foo bar', '/tmp/testRelConfigDir']
for path, window in zip(dirs, self.session.windows):
for p in window.panes:
for i in range(60):
Expand Down Expand Up @@ -660,6 +772,7 @@ def suite():
suite.addTest(unittest.makeSuite(FocusAndPaneIndexTest))
suite.addTest(unittest.makeSuite(PaneOrderingTest))
suite.addTest(unittest.makeSuite(StartDirectoryTest))
suite.addTest(unittest.makeSuite(StartDirectoryRelativeTest))
suite.addTest(unittest.makeSuite(ThreePaneTest))
suite.addTest(unittest.makeSuite(TwoPaneTest))
suite.addTest(unittest.makeSuite(WindowAutomaticRename))
Expand Down

0 comments on commit f994684

Please sign in to comment.