Tools/檔案同步助手
阿新 • • 發佈:2020-07-17
檔案同步助手(本地)
檔案
- sync.js
const fs=require('fs'); const crypto=require('crypto'); let config,to_config,from_config; function test_ignore(path){ if(config.ignore){ for(let reg of config.ignore){ if(reg.test(path)){ return true; } } } return false; } function get_keyword(path){ if(!config.type){ return 0; } return new Promise((resolve)=>{ let file=fs.createReadStream(path); let hash=crypto.createHash(config.type); file.on('data',(data)=>{ hash.update(data); }); file.on('end',()=>{ resolve(hash.digest('hex')); }); }); } async function scan_path(base,path=''){ process.title=`${base}${path}`; let res={ d:{}, f:{} }; let now_list=fs.readdirSync(`${base}${path}`); for(let now_path of now_list){ if(test_ignore(`${base}${path}/${now_path}`)){ continue; } if(fs.statSync(`${base}${path}/${now_path}`).isDirectory()){ res.d[now_path]=await scan_path(base,`${path}/${now_path}`); } else{ res.f[now_path]=await get_keyword(`${base}${path}/${now_path}`); } } return res; } function remove_dir(base,path,res){ for(let dir in res.d){ remove_dir(base,`${path}/${dir}`,res.d[dir]); fs.rmdirSync(`${base}${path}/${dir}`); } for(let file in res.f){ fs.unlinkSync(`${base}${path}/${file}`); } } async function compare_path(from,to,path=''){ //-- compare to for(let dir in to.d){ if(from.d[dir]){ compare_path(from.d[dir],to.d[dir],`${path}/${dir}`); } else{ remove_dir(config.to,`${path}/${dir}`,to.d[dir]); console.log(`-td`,`${config.to}${path}/${dir}`); fs.rmdirSync(`${config.to}${path}/${dir}`); delete to.d[dir]; } } for(let file in to.f){ if(!from.f[file]){ console.log(`-tf`,`${config.to}${path}/${file}`); fs.unlinkSync(`${config.to}${path}/${file}`); delete to.f[file]; } } //-- compare from for(let dir in from.d){ if(!to.d[dir]){ console.log(`+fd`,`${config.to}${path}/${dir}`); fs.mkdirSync(`${config.to}${path}/${dir}`); to.d[dir]={ d:{}, f:{} }; } compare_path(from.d[dir],to.d[dir],`${path}/${dir}`); } for(let file in from.f){ if(to.f[file]&&to.f[file]!=from.f[file]){ console.log(`-ff`,`${config.to}${path}/${file}`); fs.unlinkSync(`${config.to}${path}/${file}`); delete to.f[file]; } if(!to.f[file]){ console.log(`+ff`,`${config.to}${path}/${file}`); fs.copyFileSync(`${config.from}${path}/${file}`,`${config.to}${path}/${file}`); to.f[file]=from.f[file]; } } } async function __main(){ const config_path=process.argv[2].replace(/\\/g,'/'); if(!fs.existsSync(config_path)){ throw new Error(`no such config file`); } config=JSON.parse(fs.readFileSync(config_path)); const to_config_path=`${config.to}/sync_config.json`; if(config.ignore){ for(let i=0;i<config.ignore.length;i++){ config.ignore[i]=new RegExp(...config.ignore[i]); } } from_config=await scan_path(config.from); if(fs.existsSync(to_config_path)){ to_config=JSON.parse(fs.readFileSync(to_config_path)); } else{ to_config=await scan_path(config.to); } compare_path(from_config,to_config); fs.writeFileSync(to_config_path,JSON.stringify(to_config)); } __main();
- sync.bat //啟動器
node sync.js %*
pause
- config.json //例子
{
"from":"C:/Users/fhs/Documents/tools-fl",
"to":"R:/dev",
"ignore":[
[".vscode"],
["node_modules"]
],
"type":"md5"
}
config.json
from //要備份的資料夾(必須)
to //要備份的目標目錄(必須)
ignore //匹配忽略的資料夾
[
["www\\.\d+","ig"]
]
type //hash模式 不填寫則直接比較檔案