0

In fabric, the cd context manager works like

with cd("dir"):
    run("command")

and the command will be run after changing to the dir directory. This works fine, but the issue is that it uses a global state. For example, suppose I have a helper function, which needs to use cd:

def helper():
    with cd("foo"):
        run("some command")

If I call helper from another function like

def main_function():
    helper()
    ...

it works fine. But if I do something like

def main_function():
    with cd("bar"):
        helper()

it breaks, because the run("come command") from helper is now run from bar/foo instead of just foo.

Any tips on how to get around this? I tried using absolute paths in cd, but that didn't work. What I really want is for the cd context to only extend to the function scope.

asmeurer
  • 86,894
  • 26
  • 169
  • 240
  • 1
    Saying `cd` uses global state is a bit misleading. It modifies the working directory, which is global state anyway, and an unexpected `cd` is only one of several ways commands relying on the working directory can break. If you want around that, use absolute paths. –  Jul 06 '13 at 18:15
  • OK, I see what happened. I thought that absolute paths did not work, but my paths weren't completely absolute. They had a `~` in them. Preliminary testing indicates that absolute paths do indeed work if they are truly absolute. – asmeurer Jul 06 '13 at 18:21
  • Should this maybe be considered a bug in fabric? – asmeurer Jul 06 '13 at 18:23
  • @asmeurer, far from being a bug, this is by design, check the [nested cd example in the documentation](http://docs.fabfile.org/en/1.6/api/core/context_managers.html) – iruvar Jul 06 '13 at 21:29
  • I mean the ~ thing should be considered a bug. I get that the rest is expected behavior. – asmeurer Jul 06 '13 at 23:45

1 Answers1

0

So apparently absolute paths do work. The issue is that paths with ~ do not work (they are treated like relative paths, which IMHO is a bug in fabric), and that was what I was trying. So you have to do (e.g., if you are using vagrant) cd('/home/vagrant/foo').

Probably you can get away with relative paths in nested context managers

def func():
    with cd("/home/vagrant/foo"):
        stuff()
        with cd("bar"): # cd /home/vagrant/foo/bar
            more_stuff()

because you know exactly what the current working directory is when you call the cd('bar'). But for top-level cds, if the function can ever be called from within another function (not just directly from fab), you should use absolute paths.

asmeurer
  • 86,894
  • 26
  • 169
  • 240