Skip to content

Commit

Permalink
通过检查MD5值增加增量同步的功能,同时支持同步删除功能
Browse files Browse the repository at this point in the history
  • Loading branch information
RuanXinyu committed Sep 30, 2018
1 parent 595f897 commit a3809a2
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 169 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,8 @@ jspm_packages
# Custom
.idea
deployer.test.js
.vscode
package-lock.json


# End of https://www.gitignore.io/api/osx,linux,webstorm,sublimetext,node
45 changes: 28 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,43 @@

Huaweicloud obs deployer plugin for [Hexo](http://hexo.io/).

## Installation
## 特性说明

1. 支持增量同步本地文件目录到华为云OBS文件夹
1. 支持设置是否同步删除OBS文件和目录
1. 支持指定OBS同步目录
1. 支持设置本地过滤文件和OBS过滤文件

## 安装

``` bash
$ npm install hexo-deployer-huaweicloud-obs --save
```

## Options

You can configure this plugin in `_config.yml`. If `sync_deleted` is set to `yes`, the obs files while not in local directory will be deleted.
首先在 `_config.yml`做如下的配置:

``` yaml
# You can use this:
deploy:
type: huaweicloud-obs
server : <https://yourdomainname>(e.g. https://obs.cn-north-1.myhwclouds.com)
bucket: <your bucket name>(e.g. obs-2f97)
obs_dir_prefix: <dir prefix without />(e.g. "")
access_key_id: <access key>(e.g. R7DYQD3DQRRLTDWYtE3S)
secret_access_key: <secret access key>(e.g. TERHf0NGpDrbhsbc1h3xymB9w22wK8lLgOFkgjCB2)
sync_deleted: <yes|no>(e.g. yes)
type: "huaweicloud-obs"
server : "https://obs.cn-north-1.myhwclouds.com"
bucket: "obs-2f97"
accessKeyId: "R7DYQD3DQRRLTDWYttE3S"
secretAccessKey: "TERHf0NGpDrbhsbc1h3xymB9w22wK8lLgOhdgFkgjCB2"
localFilesIgnorePattern: "^\\..*"
remoteDir: "/"
syncDeletedFiles: "yes"
syncDeletedFilesIgnorePattern: "^\\..*"
```
## Release Log
## Known Issues
Huaweicloud obs only finds `index.html` in root. This is [detail](https://support.huaweicloud.com/bestpractice-obs/obs_05_0620.html)

So you must set full url in your hexo blog codes like `/archives/index.html` except the root path.
| 名称 | 必选 | 默认值 | 描述 |
| -- | -- | -- |-- |
| server | 必填 | null | OBS服务器地址,以`https://`开头,不包含桶名称 <br>比如`https://obs.cn-north-1.myhwclouds.com` |
| bucket |必填 | null | OBS桶名称 |
| accessKeyId | 必填 | null | 访问OBS的accessKeyId |
| secretAccessKey | 必填 | null | 访问OBS的secretAccessKey |
| localFilesIgnorePattern | 可选 | "^\\..*" | 本地忽略文件的正则表达式 <br>与文件相对于`public`的相对路径相匹配,路径分隔符为`/` <br> 比如: `img/avast.png` |
| remoteDir | 可选 | / | 同步到远端的目录,路径分隔符为`/` |
| syncDeletedFiles | 可选 | yes | `yes`或者`no`, 除`syncDeletedFilesIgnorePattern`匹配上的文件外 <br>如果是`yes`,则本地文件删除后,OBS中的文件也会对应删除 |
| syncDeletedFilesIgnorePattern | 可选 | "^\\..*" | 远端忽略文件的正则表达式 <br>与文件相对于`remoteDir`的相对路径相匹配,路径分隔符为`/` <br> 比如: `img/avast.png` |
168 changes: 23 additions & 145 deletions deployer.js
Original file line number Diff line number Diff line change
@@ -1,168 +1,46 @@
'use strict';


var fs = require('fs');
var ObsClient = require('./lib/obs');
var Promise = require('bluebird');
var crypto = require('crypto');
var hexofs = require('hexo-fs');
var urlencode = require('urlencode');
var request = require('request');
var xml2js = require('xml2js');

var obsSync = require('huaweicloud-obs-sync');

module.exports = function (args, callback) {
var publicDir = this.public_dir;
var updatedFileList = [];
var deletedFileList = [];

if (!args.server || !args.bucket || !args.access_key_id || !args.secret_access_key || !args.sync_deleted || !args.obs_dir_prefix) {
if (!args.server || !args.bucket || !args.accessKeyId || !args.secretAccessKey) {
var help = [
'You should argsure deployment settings in _config.yml first!',
'',
'Example:',
' deploy:',
' type: huaweicloud-obs',
' server : <https://yourdomainname>(e.g. https://obs.cn-north-1.myhwclouds.com)',
' bucket: <your bucket name>(e.g. obs-2f97)',
' obs_dir_prefix: <dir prefix without />(e.g. "")',
' access_key_id: <access key>(e.g. R7DYQD3DQRRLTDWYtE3S)',
' secret_access_key: <secret access key>(e.g. TERHf0NGpDrbhsbc1h3xymB9w22wK8lLgOFkgjCB2)',
' sync_deleted: <yes|no>(e.g. yes)',
'type: "huaweicloud-obs"',
'server : "https://obs.cn-north-1.myhwclouds.com"',
'bucket: "obs-2f97"',
'accessKeyId: "R7DYQD3DQRRLTDWYttE3S"',
'secretAccessKey: "TERHf0NGpDrbhsbc1h3xymB9w22wK8lLgOhdgFkgjCB2"',
'localFilesIgnorePattern: "^\\..*"',
'remoteDir: "/"',
'syncDeletedFiles: "yes"',
'syncDeletedFilesIgnorePattern: "^\\..*"',
'',
'For more help, you can check the docs: http://hexo.io/docs/deployment.html and https://support.huaweicloud.com/bestpractice-obs/obs_05_0620.html'
];
console.log(help.join('\n'));
console.error('=====> config error');
return;
}

args.obs_dir_prefix = args.obs_dir_prefix.replace(/(^\/*)|(\/*$)/g, "").replace(/(^\s*)|(\s*$)/g, "")

let obsClient = new ObsClient({
access_key_id: args.access_key_id,
secret_access_key: args.secret_access_key,
server : args.server
});

let getOBSFileList = async () => {
let baseUrl = args.server.replace("https://", "https://" + args.bucket + ".") + "?max-keys=1000&prefix=" + urlencode(args.obs_dir_prefix);
let marker = "";
let result = [];
console.log("get remote obs file list ...");
while (true) {
let data = await new Promise((resolver, reject) => {
let url = marker == "" ? baseUrl : baseUrl + "&marker=" + urlencode(marker);
console.log(url);
request(url, (error, response, body) => {
if (error) reject(error);
xml2js.parseString(body, (error, result) => {
resolver(result);
});
});
});
if (data.ListBucketResult.Contents != undefined) {
result = result.concat(data.ListBucketResult.Contents);
}
if (data.ListBucketResult.NextMarker == "" || data.ListBucketResult.NextMarker == undefined) {
break;
}
marker = data.ListBucketResult.NextMarker;
}
console.log("get remote obs file list success, total file " + result.length);
return result;
}

let uploadFiles = async () => {
console.log("uploading files ...");
await Promise.all(updatedFileList.map(function (item) {
return new Promise((resolver, reject) => {
obsClient.putObject({
Bucket : args.bucket,
Key : item.obsKey,
SourceFile : publicDir + item.filename,
ContentMD5: item.base64MD5
}, (err, result) => {
if(err){
console.error('upload file--> ' + item.obsKey + ', error, ' + err);
reject(err);
}else{
console.error('upload file--> ' + item.obsKey + ', ' + result.CommonMsg.Status);
resolver(result.CommonMsg.Status);
}
});
});
}));
console.log("uploading files finished...");

if (args.sync_deleted=="yes") {
console.log("deleting files ...");
await Promise.all(deletedFileList.map(function (item) {
return new Promise((resolver, reject) => {
obsClient.deleteObject({
Bucket : args.bucket,
Key : item.Key[0]
}, (err, result) => {
if(err){
console.error('delete file--> ' + item.Key[0] + ', error, ' + err);
reject(err);
}else{
console.error('delete file --> ' + item.Key[0] + ', response code: ' + result.CommonMsg.Status);
resolver(result.CommonMsg.Status);
}
});
});
}));
console.log("deleting files finished...");
}
obsClient.close();
console.log("=================sync files finished================================");
}

return getOBSFileList().then(remoteFileList => {
console.log("=================sync files start================================");
console.log("get local file list ...");
let localFileList = hexofs.listDirSync(publicDir).map(item => {
let data = fs.readFileSync(publicDir + item);
let result = {
filename: item,
obsKey: args.obs_dir_prefix == "" ? item.replace(/\\/g, "/") : args.obs_dir_prefix + "/" + item.replace(/\\/g, "/"),
md5: crypto.createHash('md5').update(data).digest('hex'),
base64MD5: crypto.createHash('md5').update(data).digest("base64")
};
return result;
})
console.log("get local file list success, total file " + localFileList.length);

console.log("calculate changed local file list ...");
for (var i = 0; i < localFileList.length; i++) {
let isUpdated = true;
for (var j = 0; j < remoteFileList.length; j++) {
if (remoteFileList[j].Key[0] == localFileList[i].obsKey) {
if (remoteFileList[j].ETag[0].replace(/"/g, "") == localFileList[i].md5) {
isUpdated = false;
}
break;
}
}
if (isUpdated) {
updatedFileList.push(localFileList[i]);
}
}
console.log("calculate changed local file list success, total changed file " + updatedFileList.length);

console.log("calculate deleted local file list ...");
for (var i = 0; i < remoteFileList.length; i++) {
let isExist = false;
for (var j = 0; j < localFileList.length; j++) {
if (remoteFileList[i].Key[0] == localFileList[j].obsKey) {
isExist = true;
break;
}
}
if (!isExist) {
deletedFileList.push(remoteFileList[i]);
}
}
console.log("calculate deleted local file list success, total changed file " + deletedFileList.length);
}).then(uploadFiles);
return obsSync.syncFolderToOBS({
server : args.server,
bucket: args.bucket,
accessKeyId: args.accessKeyId,
secretAccessKey: args.secretAccessKey,
localDir: this.public_dir,
localFilesIgnorePattern: args.localFilesIgnorePattern == undefined ? "^\\..*" : args.localFilesIgnorePattern,
remoteDir: args.remoteDir == undefined ? "/" : args.remoteDir,
syncDeletedFiles: args.syncDeletedFiles == undefined ? "yes" : args.syncDeletedFiles,
syncDeletedFilesIgnorePattern: args.syncDeletedFilesIgnorePattern == undefined ? "^Blog/.*" : args.syncDeletedFilesIgnorePattern,
})
};
9 changes: 2 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hexo-deployer-huaweicloud-obs",
"version": "0.1.0",
"version": "1.0.0",
"description": "huaweicloud obs deployer plugin of Hexo.",
"repository": {
"type": "git",
Expand All @@ -17,12 +17,7 @@
"author": "ruanxinyu",
"license": "MIT",
"dependencies": {
"bluebird": "^3.4.7",
"hexo-fs": "^0.1.6",
"log4js": "^1.1.1",
"xml2js": "^0.4.19",
"request": "^2.88.0",
"urlencode": "^1.1.0"
"huaweicloud-obs-sync": "^1.0.0"
},
"bugs": {
"url": "https://github.com/ruanxinyu/hexo-deployer-huaweicloud-obs/issues"
Expand Down

0 comments on commit a3809a2

Please sign in to comment.