// import process from 'process'
import path from 'path'
import fs from 'fs'
import JSON5 from 'json5'
import dayjs from 'dayjs'
import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import split from 'lodash-es/split.js'
import join from 'lodash-es/join.js'
import genPm from 'wsemi/src/genPm.mjs'
import cint from 'wsemi/src/cint.mjs'
import cstr from 'wsemi/src/cstr.mjs'
import isearr from 'wsemi/src/isearr.mjs'
import isstr from 'wsemi/src/isstr.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import isbol from 'wsemi/src/isbol.mjs'
import isint from 'wsemi/src/isint.mjs'
import pmSeries from 'wsemi/src/pmSeries.mjs'
import fsGetFilesInFolder from 'wsemi/src/fsGetFilesInFolder.mjs'
import fsIsFile from 'wsemi/src/fsIsFile.mjs'
import fsIsFolder from 'wsemi/src/fsIsFolder.mjs'
import replace from 'wsemi/src/replace.mjs'
import now2str from 'wsemi/src/now2str.mjs'
import now2strp from 'wsemi/src/now2strp.mjs'
import strright from 'wsemi/src/strright.mjs'
import o2j from 'wsemi/src/o2j.mjs'
import fsCreateFolder from 'wsemi/src/fsCreateFolder.mjs'
import fsCopyFolder from 'wsemi/src/fsCopyFolder.mjs'
// import mZip from 'w-zip/src/mZip.mjs'
import m7z from 'w-zip/src/m7z.mjs'
let logFd = '' //若由排程呼叫且不給logFd絕對路徑時, 預設是位於C:\Windows\system32
let logWhenSuccess = false
let logWhenError = true
function rep(c) {
// let c
// c = `{today}`
// console.log(c, rep(c))
// => {today} 20200617
// c = `{todayYYYY-MM-DD}`
// console.log(c, rep(c))
// => {todayYYYY-MM-DD} 2020-06-17
// c = `{yesterday}`
// console.log(c, rep(c))
// => {yesterday} 20200617
// c = `{yesterdayYYYY-MM-DD}`
// console.log(c, rep(c))
// => {yesterdayYYYY-MM-DD} 2020-06-17
// c = `api.{yesterdayYYYY-MM-DD}.log`
// console.log(c, rep(c))
// => api.{yesterdayYYYY-MM-DD}.log api.2020-06-17.log
//d
let d = dayjs()
function cvBasic(c, name) {
//若為{today},{yesterday}
if (c.indexOf(`{${name}}`) >= 0) {
//fmt
let fmt = 'YYYYMMDD'
//day
let day
if (name === 'yesterday') {
day = d.add(-1, 'days').format(fmt)
}
else {
day = d.format(fmt)
}
//replace
c = replace(c, `{${name}}`, day)
}
return c
}
function cvAdv(c, name) {
//若還有{today
let j = c.indexOf(`{${name}`)
if (j >= 0) {
//indStart, indEnd
let indStart = j + 1
let indEnd = null
for (let i = indStart + 5; i < c.length; i++) {
let r = c.substring(i, i + 1)
if (r === '}') {
indEnd = i
break
}
}
//tag, 取回例如todayYYYY-MM-DD
let tag = c.substring(indStart, indEnd)
//fmt, 取得例如YYYY-MM-DD
let fmt = replace(tag, name, '')
//day
let day = d.format(fmt)
if (name === 'yesterday') {
day = d.add(-1, 'days').format(fmt)
}
else {
day = d.format(fmt)
}
//split and join
let s = split(c, `{${tag}}`)
c = join(s, day)
}
return c
}
function core(c) {
let changed = false
let t = c
c = cvBasic(c, 'today')
changed = changed || c !== t
t = c
c = cvBasic(c, 'yesterday')
changed = changed || c !== t
t = c
c = cvAdv(c, 'today')
changed = changed || c !== t
t = c
c = cvAdv(c, 'yesterday')
changed = changed || c !== t
return {
c,
changed,
}
}
while (true) {
let r = core(c)
c = r.c
if (!r.changed) {
break
}
}
return c
}
function ck7z(r) {
let state = get(r, 'state', '')
state = cstr(state)
let msg7z = get(r, 'msg7z', '')
msg7z = cstr(msg7z)
if (isestr(msg7z)) {
//採用7z
if (msg7z.indexOf('Everything is Ok') >= 0) {
return state.replace('finish:', 'done:')
}
else {
return msg7z
}
}
else {
//採用zip
return r
}
}
async function unzip(v) {
//params
let src = get(v, 'src', null)
let tar = get(v, 'tar', null)
//check
if (!src) {
return Promise.reject('invalid src')
}
if (!tar) {
return Promise.reject('invalid tar')
}
//rep
src = rep(src)
tar = rep(tar)
//check
if (!fsIsFile(src)) {
return Promise.reject('src is not file: ' + src)
}
//unzip
let r = await m7z.unzip(src, tar)
//ck7z
r = ck7z(r)
return r
}
async function copyFile(v) {
//params
let src = get(v, 'src', null)
let tar = get(v, 'tar', null)
//check
if (!src) {
return Promise.reject('invalid src')
}
if (!tar) {
return Promise.reject('invalid tar')
}
//rep
src = rep(src)
tar = rep(tar)
//check
if (!fsIsFile(src)) {
return Promise.reject('src is not file: ' + src)
}
//copyFileSync
try {
fs.copyFileSync(src, tar)
}
catch (err) {
return Promise.reject(err)
}
return 'done: ' + tar
}
async function zipFile(v) {
//params
let src = get(v, 'src', null)
let tar = get(v, 'tar', null)
//check
if (!src) {
return Promise.reject('invalid src')
}
if (!tar) {
return Promise.reject('invalid tar')
}
//rep
src = rep(src)
tar = rep(tar)
//check
if (!fsIsFile(src)) {
return Promise.reject('src is not file: ' + src)
}
//level
let level = get(v, 'level', 1)
if (!isint(level)) {
level = 1
}
level = cint(level)
if (level < 0 || level > 9) {
level = 1
}
//pw
let pw = get(v, 'pw', '')
if (!isstr(pw)) {
pw = ''
}
//opt
let opt = {
level,
pw,
}
//zipFile
let r = await m7z.zipFile(src, tar, opt)
//ck7z
r = ck7z(r)
return r
}
async function copyFolder(v) {
//params
let src = get(v, 'src', null)
let tar = get(v, 'tar', null)
//check
if (!src) {
return Promise.reject('invalid src')
}
if (!tar) {
return Promise.reject('invalid tar')
}
//rep
src = rep(src)
tar = rep(tar)
//check
if (!fsIsFolder(src)) {
return Promise.reject('src is not folder: ' + src)
}
//fsCopyFolder
let r = fsCopyFolder(src, tar)
//check
if (r.error) {
return Promise.reject(r.error)
}
return 'done: ' + tar
}
async function zipFolder(v) {
//params
let src = get(v, 'src', null)
let tar = get(v, 'tar', null)
//check
if (!src) {
return Promise.reject('invalid src')
}
if (!tar) {
return Promise.reject('invalid tar')
}
//rep
src = rep(src)
tar = rep(tar)
//check
if (!fsIsFolder(src)) {
return Promise.reject('src is not folder: ' + src)
}
//level
let level = get(v, 'level', 1)
if (!isint(level)) {
level = 1
}
level = cint(level)
if (level < 0 || level > 9) {
level = 1
}
//pw
let pw = get(v, 'pw', '')
if (!isstr(pw)) {
pw = ''
}
//opt
let opt = {
level,
pw,
}
//zipFolder
let r = await m7z.zipFolder(src, tar, opt)
//ck7z
r = ck7z(r)
return r
}
async function keepFiles(v) {
//params
let src = get(v, 'src', null)
let fileType = get(v, 'fileType', null)
let dayLimit = get(v, 'dayLimit', null)
let fmt = get(v, 'format', null)
//check
if (!src) {
return Promise.reject('invalid src')
}
if (!fsIsFolder(src)) {
return Promise.reject('src is not folder: ' + src)
}
if (!fileType) {
return Promise.reject('invalid fileType')
}
if (!dayLimit) {
return Promise.reject('invalid dayLimit')
}
dayLimit = cint(dayLimit)
if (dayLimit <= 0) {
return Promise.reject('dayLimit <= 0')
}
if (isestr(fmt)) {
fmt = 'YYYYMMDD'
}
//fsGetFilesInFolder
let rs = fsGetFilesInFolder(src)
//dNow
let dNow = dayjs(dayjs().format('YYYYMMDD'), 'YYYYMMDD') //取完全日, 不含時分秒
//each
let errs = []
each(rs, (v) => {
//namePure
let namePure = path.basename(v, `.${fileType}`)
try {
//dFd
let dFd = dayjs(namePure, fmt)
//diff
let i = dNow.diff(dFd, 'days')
if (i > dayLimit) {
try {
fs.unlinkSync(v)
//console.log('delete: ' + v)
}
catch (err) {
errs.push(err)
}
}
}
catch (err) {
errs.push(err)
}
})
//check
if (errs.length > 0) {
return Promise.reject(join(errs, ', '))
}
return 'done: ' + src
}
async function readSetting(fpSetting) {
//check
if (!fsIsFile(fpSetting)) {
return Promise.reject('input path is not file')
}
//read and parse
let r = null
try {
//readFileSync
let c = fs.readFileSync(fpSetting, 'utf8')
//parse
r = JSON5.parse(c)
}
catch (err) {
return Promise.reject(err)
}
return r
}
/**
* 檔案或資料夾備份
*
* @class
* @param {Array|String} inp 輸入設定陣列或設定檔名稱字串
* @returns {Promise} 回傳通訊物件,可監聽事件open、error、clientChange、execute、broadcast、deliver,可使用函數broadcast
* @example
* import fs from 'fs'
* import w from 'wsemi'
* import wb from 'w-backup'
*
* let fpSetting = './setting-zip.json'
* let fpBackup = './testData/output'
* let fpKeep = './testData/outputList'
*
* //fsDeleteFolder
* w.fsDeleteFolder(fpBackup)
*
* //fsCreateFolder
* w.fsCreateFolder(fpKeep)
* fs.writeFileSync(fpKeep + '/20200101.zip', 'a1', 'utf8')
* fs.writeFileSync(fpKeep + '/20200115.zip', 'a2', 'utf8')
* fs.writeFileSync(fpKeep + '/20200201.zip', 'b1', 'utf8')
* fs.writeFileSync(fpKeep + '/20200215.zip', 'b2', 'utf8')
* fs.writeFileSync(fpKeep + '/20200301.zip', 'c1', 'utf8')
* fs.writeFileSync(fpKeep + '/20200315.zip', 'c2', 'utf8')
* fs.writeFileSync(fpKeep + '/20200401.zip', 'd1', 'utf8')
* fs.writeFileSync(fpKeep + '/20200415.zip', 'd2', 'utf8')
*
* //use setting.json
* wb(fpSetting)
* .then((msg) => {
* console.log(msg)
* })
* .catch((err) => {
* console.log(err)
* })
*
* // then => [
* // 'done: ./testData/output/20200425/test1.zip',
* // 'done: ./testData/output/20200425/test2.zip',
* // 'done: ./testData/output/20200425/test3.zip',
* // 'done: ./testData/output/20200425/unzip/test1',
* // 'done: ./testData/output/20200425/unzip/test2',
* // 'done: ./testData/output/20200425/unzip/test3',
* // 'done: ./testData/outputList',
* // 'finish at 20200425'
* // ]
*/
async function WBackup(inp) {
async function core(inp) {
let s
//check
if (isearr(inp)) {
s = inp
}
else if (isestr(inp)) {
s = await readSetting(inp)
}
else {
return Promise.reject('input is not settings(Array) or json file path(String) for settings')
}
let msg = []
try {
//pmSeries, 需循序操作
let r
await pmSeries(s, async (v) => {
//settings
let settings = get(v, 'settings', null)
if (settings !== null) {
//logFd
let _logFd = get(settings, 'logFd', null)
if (isestr(_logFd)) {
logFd = _logFd
}
//logWhenSuccess
let _logWhenSuccess = get(settings, 'logWhenSuccess', null)
if (isbol(_logWhenSuccess)) {
logWhenSuccess = _logWhenSuccess
}
//logWhenError
let _logWhenError = get(settings, 'logWhenError', null)
if (isbol(_logWhenError)) {
logWhenError = _logWhenError
}
//path7zexe
let _path7zexe = get(settings, 'path7zexe', null)
if (fsIsFile(_path7zexe)) {
m7z.setProg(_path7zexe)
}
return
}
//func
let func = get(v, 'func', null)
if (func === 'unzip') {
r = await unzip(v)
}
else if (func === 'zipFile') {
r = await zipFile(v)
}
else if (func === 'zipFolder') {
r = await zipFolder(v)
}
else if (func === 'keepFiles') {
r = await keepFiles(v)
}
else if (func === 'copyFile') {
r = await copyFile(v)
}
else if (func === 'copyFolder') {
r = await copyFolder(v)
}
else {
r = 'error: invalid func'
}
msg.push(`${func} ${r}`)
})
}
catch (err) {
return Promise.reject(err)
}
//finish
let r = `finish at ${now2str()}`
msg.push(r)
return msg
}
function logMsg(type, msg) {
if (logFd !== '') {
//logFd
if (strright(logFd, 1) !== path.sep) {
logFd += path.sep
}
//check
fsCreateFolder(logFd)
//fn
let fn = `${type}-${now2strp()}.log`
fn = logFd + fn
console.log(`output ${type} to: ${path.resolve(fn)}`)
//msg
msg = o2j(msg, true)
//write
fs.writeFileSync(fn, msg, 'utf8')
}
}
//pm
let pm = genPm()
//core
core(inp)
.then((msg) => {
//console.log('then', msg)
if (logWhenSuccess) {
logMsg('success', msg)
}
pm.resolve(msg)
})
.catch((err) => {
//console.log('catch', err)
if (logWhenError) {
logMsg('error', err)
}
pm.reject(err)
})
return pm
}
export default WBackup