mecano
Version:
Common functions for system deployment.
165 lines (142 loc) • 5.65 kB
Markdown
Copy a file. The behavior is similar to the one of the `cp`
Unix utility. Copying a file over an existing file will
overwrite it.
* `source`
The file or directory to copy.
* `destination`
Where the file or directory is copied.
* `gid`
Group name or id who owns the file.
* `not_if_exists`
Equals destination if true.
* `mode`
Permissions of the file or the parent directory.
* `ssh` (object|ssh2)
Run the action on a remote server using SSH, an ssh2 instance or an
configuration object used to initialize the SSH connection.
* `stdout` (stream.Writable)
Writable EventEmitter in which the standard output of executed commands will
be piped.
* `stderr` (stream.Writable)
Writable EventEmitter in which the standard error output of executed command
will be piped.
* `uid`
User name or id who owns the file.
* `err`
Error object if any.
* `copied`
Number of copy actions with modifications.
* Apply permissions to directories
* Handle symlinks
* Handle globing
* Preserve permissions if `mode` is `true`
```js
require('mecano').copy({
source: '/etc/passwd',
destination: '/etc/passwd.bck',
uid: 'my_user'
gid: 'my_group'
mode: '0755'
}, function(err, copied){
console.log(err ? err.message : 'File was copied: ' + copied);
});
```
module.exports = (options, callback) ->
return callback new Error 'Missing source' unless options.source
return callback new Error 'Missing destination' unless options.destination
modified = false
srcStat = null
dstStat = null
options.log? "Mecano `copy`: stat source file"
fs.stat options.ssh, options.source, (err, stat) ->
return callback err if err
srcStat = stat
options.log? "Mecano `copy`: stat destination file"
fs.stat options.ssh, options.destination, (err, stat) ->
return callback err if err and err.code isnt 'ENOENT'
dstStat = stat
sourceEndWithSlash = options.source.lastIndexOf('/') is options.source.length - 1
if srcStat.isDirectory() and dstStat and not sourceEndWithSlash
options.destination = path.resolve options.destination, path.basename options.source
if srcStat.isDirectory()
then do_directory options.source, (err) -> callback err, modified
else do_copy options.source, (err) -> callback err, modified
do_directory = (dir, callback) ->
options.log? "Source is a directory"
glob options.ssh, "#{dir}/**", dot: true, (err, files) ->
return callback err if err
each files
.run (file, callback) ->
do_copy file, callback
.then callback
do_copy = (source, callback) =>
if srcStat.isDirectory()
destination = path.resolve options.destination, path.relative options.source, source
else if not srcStat.isDirectory() and dstStat?.isDirectory()
destination = path.resolve options.destination, path.basename source
else
destination = options.destination
fs.stat options.ssh, source, (err, stat) ->
return callback err if err
if stat.isDirectory()
then do_copy_dir source, destination
else do_copy_file source, destination
do_copy_dir = (source, destination) ->
options.log? "Mecano `copy`: create directory #{destination}"
fs.mkdir options.ssh, destination, (err) ->
return callback() if err?.code is 'EEXIST'
return callback err if err
modified = true
do_end()
# Copy a file
do_copy_file = (source, destination) ->
misc.file.compare options.ssh, [source, destination], (err, md5) ->
return callback err if err and err.message.indexOf('Does not exist') isnt 0
return do_chown_chmod destination if md5
options.log? "Mecano `copy`: Copy file from #{source} into #{destination}"
misc.file.copyFile options.ssh, source, destination, (err) ->
return callback err if err
modified = true
do_chown_chmod destination
do_chown_chmod = (destination) =>
@
.chown
destination: destination
uid: options.uid
gid: options.gid
if: options.uid? or options.gid?
.chmod
destination: destination
mode: options.mode
if: options.mode?
.then (err, status) ->
return callback err if err
modified = true if status
do_end()
do_end = ->
options.log? "Mecano `copy`: copy file #{source}" if modified
callback null, modified
fs = require 'ssh2-fs'
path = require 'path'
each = require 'each'
misc = require './misc'
glob = require './misc/glob'