diff --git a/CHANGELOG.md b/CHANGELOG.md index 2274984ce..6cde7c8d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ IMPROVEMENTS: * builder/digitalocean: Retry on any pending event errors. * builder/openstack: Can now specify a project. [GH-382] * builder/virtualbox: Can now attach hard drive over SATA. [GH-391] +* provisioner/file: Can now upload directories. [GH-251] BUG FIXES: diff --git a/packer/communicator.go b/packer/communicator.go index 236d34633..159e5e380 100644 --- a/packer/communicator.go +++ b/packer/communicator.go @@ -67,7 +67,7 @@ type Communicator interface { // is a trailing slash on the source "/". For example: "/tmp/src" as // the source will create a "src" directory in the destination unless // a trailing slash is added. This is identical behavior to rsync(1). - UploadDir(string, string, []string) error + UploadDir(dst string, src string, exclude []string) error // Download downloads a file from the machine from the given remote path // with the contents writing to the given writer. This method will diff --git a/provisioner/file/provisioner.go b/provisioner/file/provisioner.go index 096b10437..c20cbd0f2 100644 --- a/provisioner/file/provisioner.go +++ b/provisioner/file/provisioner.go @@ -72,6 +72,17 @@ func (p *Provisioner) Prepare(raws ...interface{}) error { func (p *Provisioner) Provision(ui packer.Ui, comm packer.Communicator) error { ui.Say(fmt.Sprintf("Uploading %s => %s", p.config.Source, p.config.Destination)) + info, err := os.Stat(p.config.Source) + if err != nil { + return err + } + + // If we're uploading a directory, short circuit and do that + if info.IsDir() { + return comm.UploadDir(p.config.Destination, p.config.Source, nil) + } + + // We're uploading a file... f, err := os.Open(p.config.Source) if err != nil { return err diff --git a/website/source/docs/provisioners/file.html.markdown b/website/source/docs/provisioners/file.html.markdown index cf2a6081f..4dea52ad8 100644 --- a/website/source/docs/provisioners/file.html.markdown +++ b/website/source/docs/provisioners/file.html.markdown @@ -12,6 +12,8 @@ recommended usage of the file provisioner is to use it to upload files, and then use [shell provisioner](/docs/provisioners/shell.html) to move them to the proper place, set permissions, etc. +The file provisioner can upload both single files and complete directories. + ## Basic Example
@@ -26,10 +28,38 @@ them to the proper place, set permissions, etc. The available configuration options are listed below. All elements are required. -* `source` (string) - The path to a local file to upload to the machine. The - path can be absolute or relative. If it is relative, it is relative to the - working directory when Packer is executed. +* `source` (string) - The path to a local file or directory to upload to the + machine. The path can be absolute or relative. If it is relative, it is + relative to the working directory when Packer is executed. If this is a + directory, the existence of a trailing slash is important. Read below on + uploading directories. * `destination` (string) - The path where the file will be uploaded to in the machine. This value must be a writable location and any parent directories must already exist. + +## Directory Uploads + +The file provisioner is also able to upload a complete directory to the +remote machine. When uploading a directory, there are a few important things +you should know. + +First, the destination directory must already exist. If you need to +create it, use a shell provisioner just prior to the file provisioner +in order to create the directory. + +Next, the existence of a trailing slash on the source path will determine +whether the directory name will be embedded within the destination, or +whether the destination will be created. An example explains this best: + +If the source is `/foo` (no trailing slash), and the destination is +`/tmp`, then the contents of `/foo` on the local machine will be uploaded +to `/tmp/foo` on the remote machine. The `foo` directory on the remote +machine will be created by Packer. + +If the source, however, is `/foo/` (a trailing slash is present), and +the destination is `/tmp`, then the contents of `/foo` will be uploaded +directly into `/tmp` directly. + +This behavior was adopted from the standard behavior of rsync. Note that +under the covers, rsync may or may not be used.