Skip to content

Commit

Permalink
add link and symlink. closes #65
Browse files Browse the repository at this point in the history
  • Loading branch information
tomerfiliba committed May 25, 2013
1 parent da9a6fb commit d63be39
Show file tree
Hide file tree
Showing 8 changed files with 112 additions and 5 deletions.
38 changes: 35 additions & 3 deletions plumbum/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ def shquote(text):
if not text:
return "''"
text = str(text)
if not text:
return "''"
for c in text:
if c not in _safechars:
break
Expand Down Expand Up @@ -124,9 +126,25 @@ def _timeout_thread():
except EnvironmentError:
pass

thd = Thread(target = _timeout_thread, name = "PlumbumTimeoutThread")
thd.setDaemon(True)
thd.start()
thd1 = Thread(target = _timeout_thread, name = "PlumbumTimeoutThread")
thd1.setDaemon(True)
thd1.start()

_bg_processes = []

def _output_collector_thread():
while True:
num_producing_procs = 1
for proc in _bg_processes:
proc.stdout_data += proc.stdout.read(1000)
proc.stderr_data += proc.stderr.read(1000)

time.sleep(min(1.0 / num_producing_procs, 0.1))

thd2 = Thread(target = _output_collector_thread, name = "PlumbumTimeoutThread")
thd2.setDaemon(True)
thd2.start()


def run_proc(proc, retcode, timeout = None):
"""Waits for the given process to terminate, with the expected exit code
Expand Down Expand Up @@ -634,4 +652,18 @@ def __rand__(self, cmd):
vim & FG(7) # run vim in the foreground, expecting an exit code of 7
"""

class Tee(object):
def __init__(self, *streams):
self.streams = streams












1 change: 1 addition & 0 deletions plumbum/lib.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ def pop(self):
def peek(self):
return self._items[0]


24 changes: 24 additions & 0 deletions plumbum/local_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,30 @@ def chmod(self, mode):
raise OSError("os.chmod() not supported")
os.chmod(str(self), mode)

@_setdoc(Path)
def link(self, dst):
if isinstance(dst, RemotePath):
raise TypeError("Cannot create a hardlink from local path %s to %r" % (self, dst))
if hasattr(os, "link"):
os.link(str(self), str(dst))
else:
# windows: use mklink
if self.isdir():
local["cmd"]("/C", "mklink", "/D", "/H", str(dst), str(self))
else:
local["cmd"]("/C", "mklink", "/H", str(dst), str(self))
@_setdoc(Path)
def symlink(self, dst):
if isinstance(dst, RemotePath):
raise TypeError("Cannot create a symlink from local path %s to %r" % (self, dst))
if hasattr(os, "symlink"):
os.symlink(str(self), str(dst))
else:
# windows: use mklink
if self.isdir():
local["cmd"]("/C", "mklink", "/D", str(dst), str(self))
else:
local["cmd"]("/C", "mklink", str(dst), str(self))

class Workdir(LocalPath):
"""Working directory manipulator"""
Expand Down
15 changes: 15 additions & 0 deletions plumbum/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,4 +173,19 @@ def chmod(self, mode):
:param mode: file mode as for os.chmod
"""
raise NotImplementedError()

def link(self, dst):
"""Creates a hard link from ``self`` to ``dst``
:param dst: the destination path
"""
raise NotImplementedError()
def symlink(self, dst):
"""Creates a symbolic link from ``self`` to ``dst``
:param dst: the destination path
"""
raise NotImplementedError()



3 changes: 3 additions & 0 deletions plumbum/remote_machine.py
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,9 @@ def _path_write(self, fn, data):
f.flush()
f.seek(0)
self.upload(f.name, fn)

def _path_link(self, src, dst, symlink):
self._session.run("ln -s %s %s" % ("-s" if symlink else "", shquote(src), shquote(dst)))


class SshTunnel(object):
Expand Down
21 changes: 20 additions & 1 deletion plumbum/remote_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,26 @@ def chown(self, owner=None, group=None, recursive=None):
@_setdoc(Path)
def chmod(self, mode):
self.remote._path_chmod(mode, self)


@_setdoc(Path)
def link(self, dst):
if isinstance(dst, RemotePath):
if dst.remote is not self.remote:
raise TypeError("dst points to a different remote machine")
elif not isinstance(dst, six.string_types):
raise TypeError("dst must be a string or a RemotePath (to the same remote machine), "
"got %r" % (dst,))
self.remote._path_link(self, dst, False)

@_setdoc(Path)
def symlink(self, dst):
if isinstance(dst, RemotePath):
if dst.remote is not self.remote:
raise TypeError("dst points to a different remote machine")
elif not isinstance(dst, six.string_types):
raise TypeError("dst must be a string or a RemotePath (to the same remote machine), "
"got %r" % (dst,))
self.remote._path_link(self, dst, True)



Expand Down
2 changes: 1 addition & 1 deletion plumbum/version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
version = (1, 2, 0)
version_string = "1.2.0"
release_date = "2013.05.01"
release_date = "2013.07.01"
13 changes: 13 additions & 0 deletions tests/test_local.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,19 @@ def test_read_write(self):
data = "hello world"
(tmp / "foo.txt").write(data)
self.assertEqual((tmp / "foo.txt").read(), data)

def test_links(self):
with local.tempdir() as tmp:
src = tmp / "foo.txt"
dst1 = tmp / "bar.txt"
dst2 = tmp / "spam.txt"
data = "hello world"
src.write(data)
src.link(dst1)
self.assertEqual(data, dst1.read())
src.symlink(dst2)
self.assertEqual(data, dst2.read())



if __name__ == "__main__":
Expand Down

0 comments on commit d63be39

Please sign in to comment.