import get from 'lodash-es/get.js'
import map from 'lodash-es/map.js'
import isestr from './isestr.mjs'
import strleft from './strleft.mjs'
import strdelleft from './strdelleft.mjs'
import ltdtDiffByKey from './ltdtDiffByKey.mjs'
import pmSeries from './pmSeries.mjs'
import fsCopyFileCore from './fsCopyFileCore.mjs'
import fsDeleteFileCore from './fsDeleteFileCore.mjs'
import fsIsFolderCore from './fsIsFolderCore.mjs'
import fsCopyFolderCore from './fsCopyFolderCore.mjs'
import fsDeleteFolderCore from './fsDeleteFolderCore.mjs'
import fsTreeFolderWithHashCore from './fsTreeFolderWithHashCore.mjs'
/**
* 後端nodejs針對新舊資料夾進行差異同步
*
* Unit Test: {@link https://github.com/yuda-lyu/wsemi/blob/master/test/fsSyncFolderCore.test.mjs Github}
* @memberOf wsemi
* @param {String} fdSrc 輸入來源資料夾字串
* @param {String} fdTar 輸入目標資料夾字串
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {String} [opt.type='md5'] 輸入計算HASH方法字串,預設'md5'
* @returns {Promise} 回傳Promise,resolve代表同步成功,reject代表回傳錯誤訊息
* @example
* //need test in nodejs
*
* //see fsSyncFolder
*
*/
async function fsSyncFolderCore(fdSrc, fdTar, opt = {}) {
let levelLimit = null
//path, fs, crypto
let path = get(opt, 'path')
let fs = get(opt, 'fs')
let crypto = get(opt, 'crypto')
//type
let type = get(opt, 'type', '')
if (!isestr(type)) {
type = 'md5'
}
//check
if (!fsIsFolderCore(fdSrc, { fs })) {
throw new Error(`fdSrc[${fdSrc}] is not a folder`)
}
//check
if (!fsIsFolderCore(fdTar, { fs })) {
await fsCopyFolderCore(fdSrc, fdTar, { path, fs, useSync: false })
return
}
//dlm, ndlm
let dlm = path.sep
let ndlm = path.sep.length
//cv
let cv = (v, fpRep) => {
let ftype = v.isFolder ? 'folder' : 'file'
let rpath = v.path.replace(fpRep, '')
if (strleft(rpath, ndlm) === dlm) {
rpath = strdelleft(rpath, ndlm)
}
rpath = rpath.replaceAll('\\', '/')
let vv = {
id: `${ftype}|${rpath}`, //可能檔名與資料夾名相同, 故須給予ftype做區分
isFolder: v.isFolder,
name: v.name,
rpath,
hash: v.hash,
}
return vv
}
//cvs
let cvs = (vs, fpRep) => {
vs = map(vs, (v) => {
return cv(v, fpRep)
})
return vs
}
//vfpsSrc
let vfpsSrc = await fsTreeFolderWithHashCore(fdSrc, levelLimit, { path, fs, crypto, type, forFile: true, forFolder: false })
vfpsSrc = cvs(vfpsSrc, path.resolve(fdSrc))
// console.log('vfpsSrc', vfpsSrc)
//vfpsTar
let vfpsTar = await fsTreeFolderWithHashCore(fdTar, levelLimit, { path, fs, crypto, type, forFile: true, forFolder: false })
vfpsTar = cvs(vfpsTar, path.resolve(fdTar))
// console.log('vfpsTar', vfpsTar)
//ltdtDiffByKey
let r = ltdtDiffByKey(vfpsTar, vfpsSrc, 'id', { withInfor: false })
// console.log('ltdtDiffByKey', r)
// del: [ {...} ],
// add: [ {...} ],
// same: [ {...} ],
// diff: [ {...} ],
//先針對fdTar內刪除已消失之資料夾
await pmSeries(r.del, async(v) => {
if (v.isFolder) {
let fpTar = path.resolve(fdTar, v.rpath)
// console.log('del folder', fpTar)
fsDeleteFolderCore(fpTar, { fs })
}
})
//再針對fdTar內刪除已消失之檔案, 可能有些檔案已於前階段刪除資料夾時已被刪除, 故不能偵測error報錯
await pmSeries(r.del, async(v) => {
if (!v.isFolder) {
let fpTar = path.resolve(fdTar, v.rpath)
// console.log('del file', fpTar)
fsDeleteFileCore(fpTar, { fs })
}
})
//再針對fdSrc內新增或變更的檔案進行複製過去fdTar
await pmSeries([...r.add, ...r.diff], async(v) => {
if (!v.isFolder) {
let fpSrc = path.resolve(fdSrc, v.rpath)
let fpTar = path.resolve(fdTar, v.rpath)
// console.log('copy file', fpSrc, fpTar)
await fsCopyFileCore(fpSrc, fpTar, { path, fs, useSync: false })
}
})
}
export default fsSyncFolderCore