gulp-webdav-sync
Advanced tools
Comparing version 0.5.0 to 1.0.0
520
index.js
var chalk = require( 'chalk' ) | ||
var gutil = require( 'gulp-util' ) | ||
var http = require( 'http' ) | ||
var https = require( 'https' ) | ||
var path = require( 'path' ) | ||
@@ -37,7 +38,2 @@ var Stream = require( 'stream' ) | ||
} | ||
var underscore = { | ||
extend: function () { | ||
return Object.assign.apply( null, arguments ) | ||
} | ||
} | ||
var url = require( 'url' ) | ||
@@ -47,2 +43,3 @@ var xml2js = require( 'xml2js' ) | ||
const PLUGIN_NAME = 'gulp-webdav-sync' | ||
const VERSION = require( './package.json' ).version | ||
var stream | ||
@@ -53,8 +50,11 @@ var _options | ||
var _string | ||
var codes = [] | ||
_options = { | ||
'agent': false | ||
'base': process.cwd() | ||
, 'clean': false | ||
, 'headers': { 'User-Agent': PLUGIN_NAME + '/' + VERSION } | ||
, 'list': 'target' | ||
, 'log': 'error' | ||
, 'logAuth': false | ||
, 'parent': process.cwd() | ||
, 'uselastmodified': 1000 | ||
} | ||
@@ -66,3 +66,3 @@ for ( var i in arguments ) { | ||
if ( typeof arguments[i] === 'object' && arguments[i] ) { | ||
_options = underscore.extend( _options, arguments[i] ) | ||
Object.assign( _options, arguments[i] ) | ||
} | ||
@@ -92,58 +92,143 @@ } | ||
href = _string | ||
} else | ||
if ( url.format( _options ) !== '' ) { | ||
href = url.format( _options ) | ||
} else { | ||
href = url.format( _options ) | ||
href = 'http://localhost/' | ||
} | ||
_info_target( href ) | ||
if ( _options.agent === undefined ) { | ||
var agent = url.parse( href ).protocol === 'https:' | ||
? new https.Agent( _options ) | ||
: new http.Agent( { 'keepAlive': true } ) | ||
_options.agent = agent | ||
} | ||
function filter_on_href( list, urlpath ) { | ||
return list | ||
.filter( function ( element ) { | ||
if ( element.href ) { | ||
var w_slash = url.resolve( href, element.href ) === urlpath + '/' | ||
var wo_slash = url.resolve( href, element.href ) === urlpath | ||
if ( w_slash || wo_slash ) { | ||
return true | ||
} | ||
} | ||
return false | ||
} ) | ||
} | ||
stream = new Stream.Transform( { objectMode: true } ) | ||
stream._transform = function ( vinyl, encoding, callback ) { | ||
const FN_NAME = '#main' | ||
if ( vinyl.event ) { | ||
log.log( _gulp_prefix( FN_NAME + '$vinyl.event' ), vinyl.event ) | ||
log.var( '$vinyl.event', vinyl.event ) | ||
} else { | ||
vinyl.event = null | ||
} | ||
init() | ||
var target_url | ||
var target_stem | ||
var target_propfind = {} | ||
var server_date | ||
try { | ||
target_url = _splice_target( | ||
vinyl.path | ||
, path.resolve( _options.base ) | ||
, href | ||
) | ||
target_stem = _splice_target_stem( | ||
vinyl.path | ||
, path.resolve( _options.base ) | ||
, href | ||
) | ||
} catch ( error ) { | ||
_on_error( error ) | ||
callback( null, vinyl ) | ||
return | ||
} | ||
log.var( '$target_url', _strip_url_auth( target_url ) ) | ||
if ( _options.list === 'target' ) { | ||
_propfind( target_url, 0, function ( res, dom ) { | ||
if ( res.statusCode === 207 ) { | ||
target_propfind = _xml_parse( dom )[0] | ||
log.var( '$target_propfind' ) | ||
log.var( ' .getcontentlength', target_propfind.getcontentlength ) | ||
log.var( ' .getlastmodified', target_propfind.getlastmodified ) | ||
log.var( ' .stat', target_propfind.stat ) | ||
log.var( ' .resourcetype', target_propfind.resourcetype ) | ||
} | ||
if ( res.headers.date ) { | ||
server_date = new Date( res.headers.date ) | ||
} | ||
init() | ||
} ) | ||
} else { | ||
init() | ||
} | ||
function init() { | ||
const FN_NAME = '#main#init' | ||
var target_uri | ||
var target_stem | ||
try { | ||
log.log( _gulp_prefix( FN_NAME + '$href' ), href ) | ||
target_uri = _splice_target( | ||
vinyl.path | ||
, path.resolve( _options.parent ) | ||
, href | ||
) | ||
target_stem = _splice_target_stem( | ||
vinyl.path | ||
, path.resolve( _options.parent ) | ||
, href | ||
) | ||
} catch ( error ) { | ||
_on_error( error ) | ||
callback( null, vinyl ) | ||
return | ||
function times_are_comparable() { | ||
return target_propfind.getlastmodified && vinyl.stat && vinyl.stat.ctime | ||
} | ||
log.log( _gulp_prefix( FN_NAME + '$target_uri' ), target_uri ) | ||
_info_path( target_stem ) | ||
if ( vinyl.event === 'unlink' ) { | ||
_delete( target_uri, resume ) | ||
return | ||
function server_is_synchronized() { | ||
var now = new Date() | ||
var tolerance = _options.uselastmodified | ||
var interval_end = new Date( server_date.getTime() + tolerance ) | ||
var within_interval = interval_end.getTime() > now.getTime() | ||
log.var( '$server_date', server_date.getTime() ) | ||
log.var( '$now ', now.getTime() ) | ||
log.var( '$within_interval', within_interval ) | ||
return within_interval | ||
} | ||
if ( _options.clean ) { | ||
_delete( target_uri, resume ) | ||
function ctime_is_newer() { | ||
var tolerance = _options.uselastmodified | ||
var ctime = vinyl.stat | ||
? vinyl.stat.ctime.getTime() | ||
: null | ||
var lastmodified = target_propfind.getlastmodified | ||
? target_propfind.getlastmodified.getTime() | ||
: null | ||
var newer = ctime > lastmodified | ||
log.var( '$ctime', ctime ) | ||
log.var( '$lastmodified', lastmodified ) | ||
log.var( '$newer', newer ) | ||
return newer | ||
} | ||
var list = target_propfind ? [ target_propfind ] : [] | ||
var path_ | ||
if ( target_url === href ) { | ||
callback() | ||
return | ||
} | ||
if ( vinyl.isBuffer() ) { | ||
_put( target_uri, vinyl, resume ) | ||
if ( vinyl.event === 'unlink' || _options.clean ) { | ||
_delete( target_url, resume ) | ||
return | ||
} | ||
if ( vinyl.isNull() ) { | ||
_mkcol( target_uri, resume ) | ||
target_stem += '/' | ||
if ( vinyl.stat && !vinyl.stat.isDirectory() ) { | ||
log.warn( | ||
_gulp_prefix( 'warn' ) | ||
, vinyl.path + ' is not a directory.' | ||
) | ||
} | ||
path_ = filter_on_href( list, target_url ) | ||
if ( path_.length === 1 ) { | ||
resume( { statusCode: path_[0].stat } ) | ||
} else { | ||
_mkcol( target_url, resume ) | ||
} | ||
return | ||
} | ||
if ( vinyl.isStream() ) { | ||
_put( target_uri, vinyl, resume ) | ||
return | ||
if ( vinyl.isBuffer() || vinyl.isStream() ) { | ||
if ( _options.uselastmodified && times_are_comparable() ) { | ||
if ( server_is_synchronized() && ctime_is_newer() ) { | ||
_put( target_url, vinyl, resume ) | ||
return | ||
} else { | ||
resume( { statusCode: target_propfind.stat } ) | ||
return | ||
} | ||
} else { | ||
_put( target_url, vinyl, resume ) | ||
return | ||
} | ||
} | ||
@@ -155,3 +240,6 @@ callback( null, vinyl ) | ||
if ( res ) { | ||
_info_status( res.statusCode ) | ||
if ( codes.indexOf( res.statusCode ) === -1 ) { | ||
codes.push( res.statusCode ) | ||
} | ||
_info_status( res.statusCode, target_stem ) | ||
} | ||
@@ -162,4 +250,3 @@ callback() | ||
} | ||
stream.watch = function ( glob_watcher, cb ) { | ||
const FN_NAME = '#watch' | ||
stream.watch = function ( glob_watcher, callback ) { | ||
if ( typeof glob_watcher !== 'object' | ||
@@ -171,7 +258,7 @@ || !glob_watcher.type | ||
} | ||
log.log( _gulp_prefix( FN_NAME + '$arguments[0].path' ), glob_watcher.path ) | ||
log.var( 'glob_watcher.path', glob_watcher.path ) | ||
if ( glob_watcher.type === 'deleted' ) { | ||
var target_uri = _splice_target( | ||
var target_url = _splice_target( | ||
glob_watcher.path | ||
, path.resolve( _options.parent ) | ||
, path.resolve( _options.base ) | ||
, href | ||
@@ -181,57 +268,57 @@ ) | ||
glob_watcher.path | ||
, path.resolve( _options.parent ) | ||
, path.resolve( _options.base ) | ||
, href | ||
) | ||
_info_path( target_stem ) | ||
_delete( target_uri, function ( res ) { | ||
_info_status( res.statusCode ) | ||
if ( cb && typeof cb === 'function' ) { | ||
cb() | ||
_delete( target_url, function ( res ) { | ||
if ( codes.indexOf( res.statusCode ) === -1 ) { | ||
codes.push( res.statusCode ) | ||
} | ||
_info_status( res.statusCode, target_stem ) | ||
if ( callback && typeof callback === 'function' ) { | ||
callback() | ||
} | ||
} ) | ||
} else { | ||
if ( cb && typeof cb === 'function' ) { | ||
cb() | ||
if ( callback && typeof callback === 'function' ) { | ||
callback() | ||
} | ||
} | ||
} | ||
stream.clean = function ( cb ) { | ||
const FN_NAME = '#main#clean' | ||
var target_uri | ||
if ( _string ) { | ||
target_uri = _string | ||
} else { | ||
target_uri = url.parse( _options ) | ||
} | ||
log.log( _gulp_prefix( FN_NAME + '$target_uri' ), target_uri ) | ||
_options = underscore.extend( _options, { 'headers': { 'Depth': 1 } } ) | ||
_propfind( target_uri, function ( dom ) { | ||
var urls = _xml_to_url_a( dom ) | ||
urls = urls.map( | ||
function ( e ) { | ||
return url.resolve( target_uri, e ) | ||
stream.clean = function ( callback ) { | ||
_propfind( href, 1, function ( res, dom ) { | ||
var url_paths = _xml_to_url_a( dom ) | ||
url_paths = url_paths.filter( | ||
function ( url_path ) { | ||
return url.resolve( href, url_path ) !== href | ||
} | ||
).filter( | ||
function ( e ) { | ||
return e !== target_uri | ||
} | ||
) | ||
log.log( 'postmap', urls ) | ||
function d( urls ) { | ||
if ( urls.length > 0 ) { | ||
_delete( urls.pop() | ||
function recursive_delete( url_paths ) { | ||
if ( url_paths.length > 0 ) { | ||
var element = url_paths.pop() | ||
_delete( url.resolve( href, element ) | ||
, function ( res ) { | ||
_info_status( res.statusCode ) | ||
d( urls ) | ||
if ( codes.indexOf( res.statusCode ) === -1 ) { | ||
codes.push( res.statusCode ) | ||
} | ||
_info_status( res.statusCode, element ) | ||
recursive_delete( url_paths ) | ||
} | ||
) | ||
} else { | ||
if ( cb ) { | ||
cb() | ||
if ( callback ) { | ||
callback() | ||
} | ||
} | ||
} | ||
d( urls ) | ||
recursive_delete( url_paths ) | ||
} ) | ||
} | ||
stream.on( 'finish', function () { | ||
codes = codes.filter( function ( code ) { | ||
return !( code === 200 || code === 404 ) | ||
} ) | ||
codes.sort().forEach( function ( element ) { | ||
_info_code( element ) | ||
} ) | ||
} ) | ||
return stream | ||
@@ -245,5 +332,7 @@ } | ||
case 200: | ||
return chalk.bgWhite.black | ||
case 201: | ||
return chalk.bgGreen.white | ||
case 204: | ||
return chalk.bgGreen.white | ||
return chalk.bgYellow.white | ||
case 207: | ||
@@ -273,5 +362,7 @@ return chalk.bgWhite.black | ||
case 200: | ||
return chalk.white | ||
case 201: | ||
return chalk.green | ||
case 204: | ||
return chalk.green | ||
return chalk.yellow | ||
case 207: | ||
@@ -296,11 +387,12 @@ return chalk.white | ||
function _delete( uri, callback ) { | ||
const FN_NAME = '#_delete' | ||
var options, req | ||
options = underscore.extend( | ||
_options | ||
, url.parse( uri ) | ||
function _delete( href, callback ) { | ||
var options, req, client | ||
options = Object.assign( | ||
{} | ||
, _options | ||
, url.parse( href ) | ||
, { method: 'DELETE' } | ||
) | ||
req = http.request( options, callback ) | ||
client = _if_tls( options.protocol ) | ||
req = client.request( options, callback ) | ||
req.on( 'error', _on_error ) | ||
@@ -310,34 +402,69 @@ req.end() | ||
function _get( uri, vinyl, callback ) { | ||
function _filter_collection( resrc ) { | ||
if ( resrc.resourcetype && resrc.resourcetype === 'collection' ) { | ||
return true | ||
} | ||
return false | ||
} | ||
function _get( href, callback ) { | ||
var options, req, client | ||
options = Object.assign( | ||
{} | ||
, _options | ||
, url.parse( href ) | ||
) | ||
client = _if_tls( options.protocol ) | ||
req = client.request( options, callback ) | ||
req.on( 'error', _on_error ) | ||
req.end() | ||
} | ||
function _gulp_prefix() { | ||
var name = '[' + chalk.grey( PLUGIN_NAME ) + ']' | ||
var item = '' | ||
for ( var i = 0 ; i < arguments.length ; i++ ) { | ||
item += chalk.grey( arguments[i] ) | ||
function bracket( string ) { | ||
if ( typeof string === 'string' ) { | ||
return '[' + chalk.grey( string ) + ']' | ||
} else { | ||
return '' | ||
} | ||
} | ||
return [ name, item ].join( ' ' ) | ||
return [ PLUGIN_NAME ] | ||
.concat( Array.prototype.slice.call( arguments ) ) | ||
.map( bracket ) | ||
.join( ' ' ) | ||
} | ||
function _info_path( string ) { | ||
var out = chalk.underline( string ) | ||
log.info( _gulp_prefix(), out ) | ||
function _if_tls( scheme ) { | ||
switch ( scheme ) { | ||
case 'http:': | ||
return http | ||
case 'https:': | ||
return https | ||
default: | ||
return http | ||
} | ||
} | ||
function _info_status( statusCode ) { | ||
function _info_status( statusCode, string ) { | ||
var code = | ||
_colorcode_statusCode_fn( statusCode ) | ||
.call( this, statusCode ) | ||
log.info( _gulp_prefix(), code, string ) | ||
} | ||
function _info_code( statusCode ) { | ||
var code = | ||
_colorcode_statusCode_fn( statusCode ) | ||
.call( this, statusCode ) | ||
var msg = | ||
_colorcode_statusMessage_fn( statusCode ) | ||
.call( this, http.STATUS_CODES[statusCode] ) | ||
log.info( ' ', code, msg ) | ||
log.info( _gulp_prefix(), code, msg ) | ||
} | ||
function _info_target( uri ) { | ||
function _info_target( href ) { | ||
if ( _options.logAuth !== true ) { | ||
uri = _strip_url_auth( uri ) | ||
href = _strip_url_auth( href ) | ||
} | ||
var to = chalk.underline.cyan( uri ) | ||
var to = chalk.blue( href ) | ||
log.info( _gulp_prefix(), to ) | ||
@@ -359,10 +486,18 @@ } | ||
function _mkcol( uri, callback ) { | ||
var options, req | ||
options = underscore.extend( | ||
_options | ||
, url.parse( uri ) | ||
log.var = function () { | ||
var args = Array.prototype.slice.call( arguments ) | ||
var last = args.length > 1 ? args.pop() : '' | ||
log.log( _gulp_prefix( 'log' ), chalk.grey( args.join( ' ' ) ), last ) | ||
} | ||
function _mkcol( href, callback ) { | ||
var options, req, client | ||
options = Object.assign( | ||
{} | ||
, _options | ||
, url.parse( href ) | ||
, { method: 'MKCOL' } | ||
) | ||
req = http.request( options, callback ) | ||
client = _if_tls( options.client ) | ||
req = client.request( options, callback ) | ||
req.on( 'error', _on_error ) | ||
@@ -376,23 +511,27 @@ req.end() | ||
function _propfind( uri, callback ) { | ||
var options, req | ||
options = underscore.extend( | ||
_options | ||
, url.parse( uri ) | ||
function _propfind( href, depth, callback ) { | ||
var options, req, client | ||
options = Object.assign( | ||
{} | ||
, _options | ||
, url.parse( href ) | ||
, { method: 'PROPFIND' } | ||
, { 'headers': { 'Depth': depth } } | ||
) | ||
req = http.request( options, function ( res ) { | ||
var body = '' | ||
client = _if_tls( options.protocol ) | ||
req = client.request( options, function ( res ) { | ||
var content = '' | ||
res.on( 'data', function ( chunk ) { | ||
body += chunk | ||
content += chunk | ||
} ) | ||
res.on( 'end', function () { | ||
var opt = { | ||
tagNameProcessors: [ xml2js.processors.stripPrefix ] | ||
explicitCharkey: true | ||
, tagNameProcessors: [ xml2js.processors.stripPrefix ] | ||
} | ||
xml2js.parseString( body, opt, function ( err, result ) { | ||
xml2js.parseString( content, opt, function ( err, result ) { | ||
if ( err ) { | ||
_on_error( err ) | ||
} | ||
callback( result ) | ||
callback( res, result ) | ||
} ) | ||
@@ -405,13 +544,47 @@ } ) | ||
function _proppatch( uri, props, callback ) { | ||
function _proppatch( href, props, callback ) { | ||
var options, xml, req | ||
options = Object.assign( | ||
{} | ||
, _options | ||
, url.parse( href ) | ||
, { method: 'PROPPATCH' } | ||
, { headers: { 'Content-Type': 'text/xml; charset="utf-8"' } } | ||
) | ||
xml = ( new xml2js.Builder() ).buildObject( props ) | ||
req = http.request( options, callback ) | ||
req.on( 'error', _on_error ) | ||
req.write( xml ) | ||
req.end() | ||
} | ||
function _put( uri, vinyl, callback ) { | ||
var options, req | ||
options = underscore.extend( | ||
_options | ||
, url.parse( uri ) | ||
function _proppatch_( href, date, cb ) { | ||
var dom = { | ||
'd:propertyupdate': { | ||
$: { | ||
'xmlns:d': 'DAV:' | ||
} | ||
, 'd:set': { | ||
'd:prop': { | ||
'd:creationdate': date.toJSON() | ||
, 'd:resourcetype': { 'd:collection': null } | ||
} | ||
} | ||
} | ||
} | ||
_proppatch( href, dom, function ( res ) { | ||
cb( res ) | ||
} ) | ||
} | ||
function _put( href, vinyl, callback ) { | ||
var options, req, client | ||
options = Object.assign( | ||
{} | ||
, _options | ||
, url.parse( href ) | ||
, { method: 'PUT' } | ||
) | ||
req = http.request( options, callback ) | ||
client = _if_tls( options.protocol ) | ||
req = client.request( options, callback ) | ||
vinyl.pipe( req ) | ||
@@ -421,32 +594,30 @@ req.on( 'error', _on_error ) | ||
function _splice_target( vinyl_path, parent_dir, href ) { | ||
const FN_NAME = '#_splice_target' | ||
function _splice_target( vinyl_path, base_dir, href ) { | ||
var error | ||
var target_stem = '' | ||
log.log( _gulp_prefix( FN_NAME + '$vinyl_path' ), vinyl_path ) | ||
log.log( _gulp_prefix( FN_NAME + '$parent_dir' ), parent_dir ) | ||
if ( vinyl_path.length < parent_dir.length ) { | ||
log.var( '$vinyl_path', vinyl_path ) | ||
log.var( '$base_dir', base_dir ) | ||
if ( vinyl_path.length < base_dir.length ) { | ||
error = new gutil.PluginError( | ||
PLUGIN_NAME | ||
, 'Incoherent Target: options.parent too long.\n' | ||
, 'Incoherent Target: options.base too long.\n' | ||
+ '\tpath is ' + chalk.red( vinyl_path ) + '\n' | ||
+ '\tparent is ' + chalk.red( parent_dir ) + '\n' | ||
+ '\tbase is ' + chalk.red( base_dir ) + '\n' | ||
) | ||
error.vinyl_path = vinyl_path | ||
error.parent = parent_dir | ||
error.base = base_dir | ||
throw error | ||
} | ||
target_stem = _splice_target_stem( vinyl_path, parent_dir, href ) | ||
target_stem = _splice_target_stem( vinyl_path, base_dir, href ) | ||
if ( !href ) { | ||
href = '' | ||
} | ||
return href + target_stem | ||
return url.resolve( href, target_stem ) | ||
} | ||
function _splice_target_stem( vinyl_path, parent_dir, href ) { | ||
const FN_NAME = '#_splice_target_stem' | ||
function _splice_target_stem( vinyl_path, base_dir, href ) { | ||
var error | ||
var target_stem | ||
if ( vinyl_path.substr( 0, parent_dir.length ) === parent_dir ) { | ||
target_stem = vinyl_path.substr( parent_dir.length+1 ) | ||
if ( vinyl_path.substr( 0, base_dir.length ) === base_dir ) { | ||
target_stem = vinyl_path.substr( base_dir.length+1 ) | ||
} else { | ||
@@ -457,6 +628,6 @@ error = new gutil.PluginError( | ||
+ '\tpath is ' + chalk.red( vinyl_path ) + '\n' | ||
+ '\tparent is ' + chalk.red( parent_dir ) + '\n' | ||
+ '\tbase is ' + chalk.red( base_dir ) + '\n' | ||
) | ||
error.vinyl_path = vinyl_path | ||
error.parent = parent_dir | ||
error.base = base_dir | ||
throw error | ||
@@ -474,11 +645,50 @@ } | ||
function _xml_to_url_a( dom ) { | ||
var a = [] | ||
function href( element ) { | ||
return element.href | ||
} | ||
return _xml_parse( dom ).map( href ) | ||
} | ||
function _xml_parse( dom ) { | ||
try { | ||
dom.multistatus.response.forEach( function ( e ) { | ||
a.push( e.href[0] ) | ||
return dom.multistatus.response.map( function ( response ) { | ||
var href = response.href[0] | ||
var propstat = response.propstat[0] | ||
var prop = response.propstat[0].prop[0] | ||
var getlastmodified = response.propstat[0].prop[0].getlastmodified[0] | ||
var stat = response.propstat[0].status[0] | ||
var resource = {} | ||
resource.href = href._ | ||
if ( propstat ) { | ||
if ( prop ) { | ||
var getcontentlength = response.propstat[0].prop[0].getcontentlength | ||
if ( getcontentlength ) { | ||
resource.getcontentlength = getcontentlength[0]._ | ||
} | ||
if ( getlastmodified ) { | ||
resource.getlastmodified = new Date( getlastmodified._ ) | ||
} | ||
var resourcetype = response.propstat[0].prop[0].resourcetype | ||
if ( resourcetype ) { | ||
if ( typeof resourcetype[0] === 'string' ) { | ||
resource.resourcetype = null | ||
} else | ||
if ( typeof resourcetype[0] === 'object' ) { | ||
resource.resourcetype = Object.keys( resourcetype[0] )[0] | ||
} | ||
} | ||
} | ||
if ( stat ) { | ||
resource.stat = http_status_to_int( stat._ ) | ||
} | ||
} | ||
return resource | ||
} ) | ||
} catch ( e ) { | ||
throw e | ||
} catch ( error ) { | ||
_on_error( error ) | ||
} | ||
return a | ||
return [] | ||
function http_status_to_int( string ) { | ||
return Number( /\d{3}/.exec( string ) ) | ||
} | ||
} |
{ | ||
"name": "gulp-webdav-sync", | ||
"version": "0.5.0", | ||
"version": "1.0.0", | ||
"description": "Put files and folders on a WebDAV server. Deploy with gulp", | ||
@@ -25,3 +25,2 @@ "repository": { | ||
"del": "~1.2.0", | ||
"event-stream": "~3.3.1", | ||
"gulp": "~3.9.0", | ||
@@ -28,0 +27,0 @@ "gulp-debug": "~2.0.1", |
105
README.md
# gulp-webdav-sync | ||
> Put files and folders to a WebDAV server. Deploy with [gulp](http://gulpjs.com/). | ||
> Put files and folders to a WebDAV server. Deploy with gulp. | ||
## Usage | ||
### URL String | ||
Nominally, pass a URL string. | ||
* [Targeting](#targeting) | ||
* [URL as String](#url-as-string) | ||
* [URL as Object](#url-as-object) | ||
* [Subdirectories](#subdirectories) | ||
* [Continuous Deploying: Creates, Updates, Deletes](#continuous-deploying-creates-updates-deletes) | ||
* [With gulp.watch](#with-gulpwatch) | ||
* [With gulp-watch](#with-gulp-watch) | ||
* [API](#api) | ||
* [webdav( [ href ] [, options ] )](#webdav--href---options--) | ||
* [webdav( [ href ] [, options ] ).clean( [ cb ] )](#webdav--href---options--clean--cb--) | ||
* [webdav( [ href ] [, options ] ).watch( event [, cb ] )](#webdav--href---options--watch-event--cb--) | ||
* [cb](#cb) | ||
* [event](#event) | ||
* [href](#href) | ||
* [options](#options) | ||
* [options.base](#optionsbase) | ||
* [options.clean](#optionsclean) | ||
* [options.log](#optionslog) | ||
* [options.logAuth](#optionslogauth) | ||
* [options.uselastmodified](#optionsuselastmodified) | ||
* [Development](#development) | ||
## Targeting | ||
Pass a URL argument indicating a directory/collection on a WebDAV server. Include any HTTP Basic authentication inline. HTTPS authentication must go in the options argument. | ||
### URL as String | ||
```js | ||
@@ -16,3 +38,3 @@ var webdav = require( 'gulp-webdav-sync' ) | ||
``` | ||
### URL Object | ||
### URL as Object | ||
Extend a [URL object](https://nodejs.org/api/url.html#url_url_format_urlobj). | ||
@@ -53,3 +75,3 @@ ```js | ||
use the `'parent'` option to constrain the localpath mapping, | ||
use the `'base'` option to constrain the localpath mapping, | ||
```js | ||
@@ -60,4 +82,4 @@ var webdav = require( 'gulp-webdav-sync' ) | ||
var options = { | ||
'log': 'info' | ||
, 'parent': 'dist' | ||
'base': 'dist' | ||
, 'log': 'info' | ||
, 'port': 8000 | ||
@@ -71,3 +93,3 @@ } | ||
* localhost:8000/ | ||
* dist/ | ||
* _dist/_ | ||
* css/ | ||
@@ -77,2 +99,8 @@ * images/ | ||
## Continuous Deploying: Creates, Updates, Deletes | ||
By combining methods, most cases can be satisfied, however deleting directories may be inconsistent. | ||
If any file changes or there is a creation in the path, then `gulp.watch` will re-stream all files. | ||
The [`uselastmodified` option](#optionsuselastmodified) ( default ) compares the local time to the server time so as to only upload updates. | ||
Deletes emit a different object; not in the stream, but with a `change` event. | ||
### With gulp.watch | ||
@@ -118,3 +146,5 @@ [browser-sync](http://www.browsersync.io/docs/gulp/), [npmconf](https://www.npmjs.com/package/npmconf), and [.npmrc](https://docs.npmjs.com/files/npmrc) for a save-sync-reload solution. | ||
### With gulp-watch | ||
[gulp-watch](https://www.npmjs.com/package/gulp-watch) re-emits created, modified, and deleted files for upload. | ||
[gulp-watch](https://www.npmjs.com/package/gulp-watch) uses a different strategy of extending the file objects in stream. | ||
It re-emits created, modified, and deleted files. | ||
Delete/`'unlink'` type events are attempted on the server as well. | ||
```js | ||
@@ -138,3 +168,3 @@ var watch = require( 'gulp-watch' ) | ||
### webdav( [ href ] [, options ] ) | ||
Target is a URL-type parameter whereto files are uploaded. It must specify a directory ( also known as a "collection" ). At a minimum this must be DAV root, but subdirectories may be included ( *e.g.* project name ). Part-wise definition across multiple arguments is undefined. Use the `http:` scheme, not `dav:`. | ||
Target is a URL-type parameter whereto files are uploaded. It must specify a directory ( also known as a "collection" ). At a minimum this must be DAV root, but subdirectories may be included ( *e.g.* project name ). Part-wise definition across multiple arguments is undefined. Use the `http:` or `https:` scheme, not `dav:`. | ||
@@ -147,2 +177,8 @@ ### webdav( [ href ] [, options ] ).clean( [ cb ] ) | ||
#### cb | ||
Optional, asynchronous, callback function. | ||
**Type:** `Function`</br> | ||
**Default:** `undefined` | ||
#### event | ||
@@ -160,15 +196,10 @@ [glob-watcher](https://github.com/wearefractal/glob-watcher/blob/master/index.js#L10) event. | ||
#### cb | ||
Optional, asynchronous, callback function. | ||
#### href | ||
**Type:** `Function`</br> | ||
**Default:** `undefined` | ||
## href | ||
**Type:** `String`</br> | ||
**Default:** `undefined` | ||
## options | ||
Superset of [http.request options parameter](https://nodejs.org/api/http.html#http_http_request_options_callback), and [url.object](https://nodejs.org/api/url.html#url_url_format_urlobj). If any URL properties are defined, then `protocol`, `hostname`, and `pathname` are assigned to `http://localhost/`. | ||
#### options | ||
Superset of [http.request options parameter](https://nodejs.org/api/http.html#http_http_request_options_callback), [https.request options parameter](https://nodejs.org/api/https.html#https_https_request_options_callback), and [url.object](https://nodejs.org/api/url.html#url_url_format_urlobj). If any URL properties are defined, then `protocol`, `hostname`, and `pathname` are assigned to `http://localhost/`. | ||
If `options.agent` is `undefined`, then a http[s] agent will be created for the stream. | ||
@@ -179,11 +210,18 @@ **Type:** `Object`</br> | ||
{ | ||
'agent': false | ||
, 'clean': false | ||
'clean': false | ||
, 'headers': { 'User-Agent': PLUGIN_NAME + '/' + VERSION } | ||
, 'log': 'error' | ||
, 'logAuth': false | ||
, 'parent': process.cwd() | ||
, 'base': process.cwd() | ||
, 'uselastmodified': 1000 | ||
} | ||
``` | ||
### options.clean | ||
##### options.base | ||
Relative or absolute path which halves the source path [`vinyl.path`] for appending the subsequent to the DAV target URI. Use with glob `**` to prevent super-directories from being created on the target. *e.g.* `gulp.src( 'dist/**' )`. | ||
**Type:** `String`</br> | ||
**Default:** `process.cwd()` | ||
##### options.clean | ||
Deletes corresponding resources on server instead of uploading. Note, glob star-star will delete directories before contents are pushed. | ||
@@ -194,3 +232,3 @@ | ||
### options.log | ||
##### options.log | ||
Logging threshold. Orthogonal to the `console` methods. | ||
@@ -208,3 +246,3 @@ | ||
### options.logAuth | ||
##### options.logAuth | ||
Display credentials in logged URLs. | ||
@@ -215,7 +253,10 @@ | ||
### options.parent | ||
Relative or absolute path which halves the source path [`vinyl.path`] for appending the subsequent to the DAV target URI. Use with glob `**` to prevent super-directories from being created on the target. *e.g.* `gulp.src( 'dist/**' )`. | ||
##### options.uselastmodified | ||
Compare remote `getlastmodified` versus local ( changed ) `ctime`. | ||
Only `PUT` if `ctime` is newer than `getlastmodified`. | ||
Numeric value in milliseconds is the tolerance interval for qualifying client-server synchronization. | ||
Set to false to disable. | ||
**Type:** `String`</br> | ||
**Default:** `process.cwd()` | ||
**Type:** `Number`</br> | ||
**Default:** `1000` ms | ||
@@ -226,2 +267,5 @@ ## Development | ||
npm install | ||
pushd test/assets | ||
./rekey.sh | ||
popd | ||
npm test | ||
@@ -232,1 +276,2 @@ npm set dav http://user:pass@localhost:8000/ | ||
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
11
1
263
0
26623
5
646
3