一、安装rsync
在官网下载安装rsync
二、配置环境变量
window 配置环境变量,编辑完,重启客户端
三、使用 1、rsync链接的服务器是没办法使用命令创建多层目录, 所以需要一个创建本地文件夹的目录,本地文件夹目录格式与远程一样,在上传文件到远程失败的时候,先上传一次模板目录
createTemplate.js 在E盘创建一个 服务器的新目录结构,用于rsync 创建新的平级目录包
import fs from 'fs'
import { exec } from 'child_process'
const platformList = ['m', 'xxx']
// 创建发布ftp目录模板
export const createTemplate = async () => {
// 创建manage 目录
fs.mkdirSync(`E:/release/tempate/manage/`, { recursive: true })
fs.mkdirSync(`E:/release/tempate/cdn/`, { recursive: true })
// 创建 pc目录
fs.mkdirSync(`E:/release/tempate/www/`, { recursive: true })
// 创建 www下其他项目的,不需要的时候可以为空
for (let i = 0; i < platformList.length; i++) {
fs.mkdirSync(`E:/release/tempate/www/${platformList[i]}/`, { recursive: true })
}
return `E:/release/tempate/`
}
2、配置全局环境变量
const __filename = fileURLToPath(import.meta.url)
let dirPath = path.dirname(__filename)
const dirName = path.basename(dirPath)
// 环境配置
const useName = 'xxx
const moduleName = 'xxxx'
// 本地密码地址 ftp
const passwordPath = '/cygdrive/d/xxx/xxx.pwd'
// 远程服务器地址
const serverPath = xxx.xxx.xxx.xxx
// 本地目录模版文件夹地址
const templatePath = 'E:/release/tempate'
3、声明一下前置处理函数
// 判断文件夹是否存在
const folderExists = (path) => {
try {
return fs.existsSync(path) && fs.statSync(path).isDirectory()
} catch (err) {
return false
}
}
// 运行命令
const runCommand = (commandRow) => {
return new Promise((resolve, reject) => {
const child = exec(commandRow, (error, stdout, stderr) => {
if (error) {
console.error(`执行命令时出错:${error.message}`)
reject(false)
return
}
console.log('命令的标准输出', stdout)
resolve(stdout)
})
// 监听子进程的标准输出
child.stdout.on('data', (data) => {
console.log('命令运行中', data)
})
})
}
// 获取对应的 rsync文件路径,把window的 路径转 rsync需要的路径格式,像D盘虚转为/cygdrive/d/
const getRsyncFolderPath = (path) => {
let driveLetter = path.charAt(0).toLowerCase()
const cygwinPath = path.replace(/\\/g, '/').replace(/^([A-Za-z]):/, `/cygdrive/${driveLetter}`)
return cygwinPath
}
4、获取运行 rsync 运行命令
// 生成rsync提交命令
// --password-file='/cygdrive/d/xxx/xxx/xxx.pwd' /cygdrive/d/xx/xx/rsync.pwd ftp密码存放地址
// e/xxx/xxx/ 本地代码地址
// xxx@xxx.xxx.xxx.xxx::xxx/xxx/ 服务器地址路径 例如 useNme68.100.100::modeulename/test1/
const updateCommand = (releaseName = 'dev') => {
// 项目对应的服务器 游戏商 gbshtml 游戏大厅 bshtml
// 项目打包后的文件夹名称路径
let dirpathStr = path.join(dirPath, './dist/')
let commandStr = `rsync -av --progress --delete --password-file='/cygdrive/d/xxx/xxx/xxx.pwd' '${getRsyncFolderPath(dirpathStr)}' `
switch (dirName) {
case 'admin':
commandStr += `${useName}@${serverPath}::moduleName}/${releaseName}/manage/`
break
case 'pc':
// 删除的时候,忽略m文件夹,xxx文件夹
commandStr = `rsync -av --progress --delete --exclude 'm/' --exclude 'xxx --password-file=${passwordPath}'${getRsyncFolderPath(dirpathStr)}' ${useName}@${serverPath}::${moduleName}/${releaseName}/www/`
break
case 'm':
commandStr += `${useName}@${serverPath}::${moduleName}/${releaseName}/www/m/`
break
}
return commandStr
}
5、运行rsync命令操作 因为ftp服务器可能不存在对应发布的文件夹,所以加了一个try catch,运行失败的时候,把模板文件夹上传到ftp服务器,再重新上传文件
// 上传代码到服务器
// -- recursive 递归创建文件夹
// serverName项目名称
const releaseToFrom = async (serverName) => {
const releaseCommand = updateCommand(serverName)
// 如果远程文件目录存在
try {
const data = await runCommand(releaseCommand)
console.log('提交服务器', data)
} catch {
// 如果远程文件目录不存在
// 生成远程服务器的部署文件目录格式的本地目录
let sourcePath = `E:/release/tempate/`
// 如果本地目录不存在,那么生成模板目录
if (!folderExists(sourcePath)) {
await createTemplate(platform)
}
// 把模板目录部署到远程服务器
let commandStr = `rsync -av --progress --delete --recursive --password-file=${passwordPath} '${getRsyncFolderPath(sourcePath)}' ${useName}@${serverPath}::${moduleName}/${serverName}`
let result= await runCommand(commandStr)
console.log('创建远程模板文件夹', result)
// 创建完成继续提交代码
releaseToFrom(serverName)
return
}
}
6、updateToRelease.js代码内容
import path from 'path'
// 用于运行命令
import { exec } from 'child_process'
// 生成本地模板目录文件夹
import { createTemplate } from './createTemplateRelease.js'
import { fileURLToPath } from 'url'
import fs from 'fs'
const __filename = fileURLToPath(import.meta.url)
let dirPath = path.dirname(__filename)
const dirName = path.basename(dirPath)
// 环境配置
const useName = 'xxx
const moduleName = 'xxxx'
// 本地密码地址 ftp
const passwordPath = '/cygdrive/d/xxx/xxx.pwd'
// 远程服务器地址
const serverPath = xxx.xxx.xxx.xxx
// 本地目录模版文件夹地址
const templatePath = 'E:/release/tempate'
// 判断文件夹是否存在
const folderExists = (path) => {
try {
return fs.existsSync(path) && fs.statSync(path).isDirectory()
} catch (err) {
return false
}
}
// 运行命令
const runCommand = (commandRow) => {
return new Promise((resolve, reject) => {
const child = exec(commandRow, (error, stdout, stderr) => {
if (error) {
console.error(`执行命令时出错:${error.message}`)
reject(false)
return
}
console.log('命令的标准输出', stdout)
resolve(stdout)
})
// 监听子进程的标准输出
child.stdout.on('data', (data) => {
console.log('命令运行中', data)
})
})
}
// 获取对应的 ftp本地文件路径,把window的 路径转 rsync需要的路径格式,像D盘虚转为/cygdrive/d/
const getRsyncFolderPath = (path) => {
let driveLetter = path.charAt(0).toLowerCase()
const cygwinPath = path.replace(/\\/g, '/').replace(/^([A-Za-z]):/, `/cygdrive/${driveLetter}`)
return cygwinPath
}
// 生成rsync提交命令
// --password-file='/cygdrive/d/xxx/xxx/xxx.pwd' /cygdrive/d/xx/xx/rsync.pwd ftp密码存放地址
// e/xxx/xxx/ 本地代码地址
// xxx@xxx.xxx.xxx.xxx::xxx/xxx/ 服务器地址路径 例如 useNme68.100.100::modeulename/test1/
const updateCommand = (releaseName = 'dev') => {
// 项目对应的服务器 游戏商 gbshtml 游戏大厅 bshtml
// 项目打包后的文件夹名称路径
let dirpathStr = path.join(dirPath, './dist/')
let commandStr = `rsync -av --progress --delete --password-file='/cygdrive/d/xxx/xxx/xxx.pwd' '${getRsyncFolderPath(dirpathStr)}' `
switch (dirName) {
case 'admin':
commandStr += `${useName}@${serverPath}::moduleName}/${releaseName}/manage/`
break
case 'pc':
// 删除的时候,忽略m文件夹,xxx文件夹
commandStr = `rsync -av --progress --delete --exclude 'm/' --exclude 'xxx --password-file=${passwordPath}'${getRsyncFolderPath(dirpathStr)}' ${useName}@${serverPath}::${moduleName}/${releaseName}/www/`
break
case 'm':
commandStr += `${useName}@${serverPath}::${moduleName}/${releaseName}/www/m/`
break
}
return commandStr
}
// 上传代码到服务器
// -- recursive 递归创建文件夹
// serverName项目名称
const releaseToFrom = async (serverName) => {
const releaseCommand = updateCommand(serverName)
// 如果远程文件目录存在
try {
const data = await runCommand(releaseCommand)
console.log('提交服务器', data)
} catch {
// 如果远程文件目录不存在
// 生成远程服务器的部署文件目录格式的本地目录
let sourcePath = `E:/release/tempate/`
// 如果本地目录不存在,那么生成模板目录
if (!folderExists(sourcePath)) {
await createTemplate(platform)
}
// 把模板目录部署到远程服务器
let commandStr = `rsync -av --progress --delete --recursive --password-file=${passwordPath} '${getRsyncFolderPath(sourcePath)}' ${useName}@${serverPath}::${moduleName}/${serverName}`
let result= await runCommand(commandStr)
console.log('创建远程模板文件夹', result)
// 创建完成继续提交代码
releaseToFrom(serverName)
return
}
}