diff --git a/deploy_utils/deploy.js b/deploy_utils/deploy.js new file mode 100644 index 0000000..f041d09 --- /dev/null +++ b/deploy_utils/deploy.js @@ -0,0 +1,76 @@ +const fs = require('fs') +const path = require('path') + +module.exports = { + /** + * 发布静态化的站点 + * @param {String} source 源位置 + * @param {String} target 目标位置 + * @param {Boolean} copyRoot 是否拷贝根目录 + */ + async exec(source, target, copyRoot) { + await new Promise((resolve, reject) => { + console.log(`删除${target}目录中的文件`) + this._deleteFolderRecursive(target, true) + resolve() + }) + console.log(`拷贝${source}所有文件 -> ${target}`) + this._copyFolderRecursive(source, target, copyRoot) + }, + + /** + * 递归删除目录以及子目录中的所有文件 + * @param {String} curPath 要递归删除的目录 + * @param {Boolean} retainRoot 是否保留根目录不删除 + */ + _deleteFolderRecursive(curPath, retainRoot) { + fs.readdirSync(curPath).forEach(file => { + var nextPath = path.resolve(curPath, file) + if(fs.statSync(nextPath).isDirectory()) { // recurse + this._deleteFolderRecursive(nextPath) + } else { + fs.unlinkSync(nextPath) + } + }) + if(!retainRoot) { // 根目录保留 + fs.rmdirSync(curPath) + } + }, + /** + * 递归拷贝目录 + * @param {String} source 源位置 + * @param {String} target 目标位置 + */ + _copyFolderRecursive(source, target) { + let files = fs.readdirSync(source); //同步读取当前目录 + files.forEach(file => { + var _src = path.resolve(source, file) + var _target = path.resolve(target, file) + fs.stat(_src,(err,stats) => { //stats 该对象 包含文件属性 + if (err) throw err + if (stats.isFile()) { //如果是个文件则拷贝 + let readable = fs.createReadStream(_src) //创建读取流 + let writable = fs.createWriteStream(_target) //创建写入流 + readable.pipe(writable); + } else if (stats.isDirectory()) { //是目录则 递归 + this._checkDirectory(_src, _target, this._copyFolderRecursive) + } + }) + }) + }, + + /** + * 校验目标目录是否存在 + * @param {String} src 源目录 + * @param {String} target 目标目录 + * @param {Function} callback 回调函数 + */ + _checkDirectory (src,target,callback) { + fs.access(target, fs.constants.F_OK, err => { + if (err) { + fs.mkdirSync(target) + } + callback.call(this, src, target) + }) + } +} \ No newline at end of file diff --git a/image_sync/image_synchronize.js b/deploy_utils/image_synchronize.js similarity index 68% rename from image_sync/image_synchronize.js rename to deploy_utils/image_synchronize.js index 77c1cdd..0f35951 100644 --- a/image_sync/image_synchronize.js +++ b/deploy_utils/image_synchronize.js @@ -32,43 +32,44 @@ class ImageSynchronizer { * @param {Function} uploadCallback 处理待上传文件的回调函数 * @param {Function} deleteCallback 处理待删除文件的回调函数 */ - _queryObjects(params, uploadCallback, deleteCallback) { + async _queryObjects(params, uploadCallback, deleteCallback) { // 列出所有已存储的对象 - return this.client.listObject(params).then(ret => { - // ret 包括 items(元素),limit(请求的数量),nextMarker(下一个标记) - let storageItems = ret.items.filter((item) => { - return /^images.+?\.(png|jpe?g|gif)$/.test(item.key) - }).sort((item1, item2) => { - if(item1.key > item2.key) { - return 1 - } else if(item1.key < item2.key) { - return -1 - } - return 0 - }) - // 待上传的文件列表 - let pendingUploadFiles = this.imagesList.filter(item => { - let index = this._binarySearch(storageItems, item.name, 'key', 0, storageItems.length-1) - if(index === -1) { - // 文件名不存在, 代表是新文件 - item.type = 'new' - return true - } else if(storageItems[index].eTag !== item.md5) { - // 文件名存在, 但是hash值不同, 代表有变化 - item.type = 'change' - return true - } - return false - }) - // 处理待上传的文件 - uploadCallback.call(this, pendingUploadFiles) - // 待删除的文件列表( 仓库中存在, 本地不存在 ) - let pendingDeleteFiles = storageItems.filter(item => { - return this._binarySearch(this.imagesList, item.key, 'name', 0, this.imagesList.length-1) === -1 - }) - // 处理待删除的文件 - deleteCallback.call(this, pendingDeleteFiles.map(item => item.key)) + const ret = await this.client.listObject(params) + // ret 包括 items(元素),limit(请求的数量),nextMarker(下一个标记) + let storageItems = ret.items.filter(item => { + return /^images.+?\.(png|jpe?g|gif)$/.test(item.key) + }).sort((item1, item2) => { + if (item1.key > item2.key) { + return 1 + } + else if (item1.key < item2.key) { + return -1 + } + return 0 + }); + // 待上传的文件列表 + let pendingUploadFiles = this.imagesList.filter(item => { + let index = this._binarySearch(storageItems, item.name, 'key', 0, storageItems.length - 1) + if (index === -1) { + // 文件名不存在, 代表是新文件 + item.type = 'new' + return true + } + else if (storageItems[index].eTag !== item.md5) { + // 文件名存在, 但是hash值不同, 代表有变化 + item.type = 'change' + return true + } + return false + }); + // 处理待上传的文件 + uploadCallback.call(this, pendingUploadFiles); + // 待删除的文件列表( 仓库中存在, 本地不存在 ) + let pendingDeleteFiles = storageItems.filter(item => { + return this._binarySearch(this.imagesList, item.key, 'name', 0, this.imagesList.length - 1) === -1; }) + // 处理待删除的文件 + deleteCallback.call(this, pendingDeleteFiles.map(item => item.key)) } /** * 上传文件对象 diff --git a/image_sync/list_images.js b/deploy_utils/list_images.js similarity index 100% rename from image_sync/list_images.js rename to deploy_utils/list_images.js diff --git a/gulpfile.js b/gulpfile.js index e63a1af..6c88103 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -4,6 +4,14 @@ const gulp = require('gulp'), plumber = require('gulp-plumber'), //容错组件(发生错误不跳出任务,并报出错误内容) Hexo = require('hexo') +// 程序执行的传参 +const argv = require('optimist') + .demand(['accessKey', 'accessSecret', 'deployPath']) + .describe('accessKey', '网易云对象存储key') + .describe('accessSecret', '网易云对象存储secret') + .describe('deployPath', '静态化后发布的目录') + .argv + const hexo = new Hexo(process.cwd(), {}) // 创建静态页面 (等同 hexo generate) @@ -45,16 +53,10 @@ gulp.task('compressHtml', () => { // 同步图片到对象存储仓库 gulp.task('syncImages', () => { - // 程序执行的传参 - var argv = require('optimist') - .usage('$0 --accessKey [string] --accessSecret [string]') - .demand(['accessKey', 'accessSecret']) - .argv - - const listImages = require('./image_sync/list_images') + const listImages = require('./deploy_utils/list_images') // 当前本地存在的所有图片 const imagesList = listImages(`${process.cwd()}/source/`, 'images/') - const ImageSynchronizer = require('./image_sync/image_synchronize') + const ImageSynchronizer = require('./deploy_utils/image_synchronize') const nosSetting = { defaultBucket: 'blog-cdn', endpoint: 'http://nos-eastchina1.126.net', @@ -65,7 +67,12 @@ gulp.task('syncImages', () => { return imageSynchronizer.synchronize('images/') }) +gulp.task('deploy', () => { + const deploy = require('./deploy_utils/deploy') + return deploy.exec('./public', argv.deployPath, false) +}) + // 默认任务 gulp.task('default', - gulp.series('generate', 'compressHtml', 'syncImages') // 串行执行任务 + gulp.series('generate', 'compressHtml', 'syncImages', 'deploy') // 串行执行任务 ) \ No newline at end of file