82

I have a directory on my local machine that I would like to copy to a remote machine (and rename it) using Fabric. I know I can copy file using put(), but what about a directory. I know it's easy enough using scp, but I would prefer to do it from within my fabfile.py if possible.

tshepang
  • 12,111
  • 21
  • 91
  • 136
gaviscon_man
  • 963
  • 1
  • 8
  • 8

3 Answers3

115

You can use put for that as well (at least in 1.0.0):

local_path may be a relative or absolute local file or directory path, and may contain shell-style wildcards, as understood by the Python glob module. Tilde expansion (as implemented by os.path.expanduser) is also performed.

See: http://docs.fabfile.org/en/1.0.0/api/core/operations.html#fabric.operations.put


Update: This example works fine (for me) on 1.0.0.:

from fabric.api import env
from fabric.operations import run, put

env.hosts = ['frodo@middleearth.com']

def copy():
    # make sure the directory is there!
    run('mkdir -p /home/frodo/tmp')

    # our local 'testdirectory' - it may contain files or subdirectories ...
    put('testdirectory', '/home/frodo/tmp')

# [frodo@middleearth.com] Executing task 'copy'
# [frodo@middleearth.com] run: mkdir -p /home/frodo/tmp
# [frodo@middleearth.com] put: testdirectory/HELLO -> \
#     /home/frodo/tmp/testdirectory/HELLO
# [frodo@middleearth.com] put: testdirectory/WORLD -> \
#     /home/frodo/tmp/testdirectory/WORLD
# ...
miku
  • 181,842
  • 47
  • 306
  • 310
  • Thanks. I'm getting an exception (Is a directory) any chance of an example? – gaviscon_man Mar 15 '11 at 16:42
  • @gaviscon_man: Added a (tested) example, but really it's just vanilla `fab`, no tricks. You'll get errors, if the target directories aren't in place already - so I included a simple `mkdir -p` before the `put`. (But other subdirectories, which are below the `testdirectory` will automatically created on the remote machine). – miku Mar 15 '11 at 16:59
  • `put` is working. Will it support copying of folder with compress at source machine and decompress at remote machine. – Ram Idavalapati Sep 07 '18 at 12:50
33

I would also look at the Project Tools module: fabric.contrib.project Documentation

This has an upload_project function which takes a source and target directory. Even better, there is an rsync_project function that uses rsync. This is nice because it only updates the files that have changed and it accepts extra args like "exclude" which is nice for doing things like excluding your .git directory.

For example:

from fabric.contrib.project import rsync_project

def _deploy_ec2(loc):

    rsync_project(local_dir=loc, remote_dir='/var/www', exclude='.git')
jfs
  • 399,953
  • 195
  • 994
  • 1,670
Seth Gottlieb
  • 451
  • 4
  • 3
  • 2
    `fabric.contrib.project` docs for latest version: http://docs.fabfile.org/en/latest/api/contrib/project.html – lsh Apr 01 '16 at 16:14
  • way better than `put/get`. also works perfectly for fetching user uploads from live websites, for example (`upload=False`, it's not obvious that it works in both ways). – benzkji Jan 17 '17 at 09:24
  • i had to wrap the excluded dir in a list to get this to work: `exclude=['.git']` – ryantuck May 16 '17 at 20:05
  • This has been transfered to the `patchwork` library now: https://fabric-patchwork.readthedocs.io/en/latest/api/transfers.html See the other answer for details: https://stackoverflow.com/a/54667814/10190810 – David Jun 17 '22 at 12:33
27

For those using Fabric 2, put can no longer upload directories, only files. Also, rsync_project is no longer part of the main Fabric package. The contrib package has been removed, as explained here. Now, rsync_project has been renamed to rsync, and you need to install another package in order to be able to use it:

pip install patchwork

Now, assuming you already have created a connection to your server:

cxn = fabric.Connection('username@server:22')

You can use rsync as below:

import patchwork.transfers
patchwork.transfers.rsync(cxn, '/my/local/dir', target, exclude='.git')

Please refer to the fabric-patchwork documentation for more information.

BitParser
  • 3,748
  • 26
  • 42
  • is there a way to provide automatic password to rsync? – pg2455 Mar 19 '19 at 18:34
  • 3
    @pg2455 Yes, using `connect_kwargs`. For example: `cxn = fabric.Connection('username@server:22', connect_kwargs=dict(password='yourpass'))` – BitParser Mar 19 '19 at 21:48
  • @TGO Can you share any example on using put option to transfer file? – Anish Sep 26 '19 at 20:37
  • @Anish `put` can not upload in Fabric 2. If you're using Fabric 1, then please refer to the accepted answer. With Fabric 2 I use the example provided in the answer, using `rsync`. – BitParser Sep 27 '19 at 21:08