Miao-Yunzai/apps/update.ts

261 lines
6.8 KiB
TypeScript
Raw Normal View History

2024-06-15 13:47:54 +08:00
import { Plugin ,makeForwardMsg} from 'yunzai/core'
2024-06-11 21:03:42 +08:00
import lodash from 'lodash'
import fs from 'node:fs'
2024-06-15 13:47:54 +08:00
import { BOT_NAME } from 'yunzai/config'
import { exec, execSync } from 'child_process'
2024-06-11 21:03:42 +08:00
import { Restart } from './restart.js'
2024-06-11 22:10:46 +08:00
import { sleep } from 'yunzai/utils'
2024-06-11 21:03:42 +08:00
let uping = false
2024-06-12 10:47:19 +08:00
export class update extends Plugin {
2024-06-11 21:03:42 +08:00
typeName = BOT_NAME
messages = []
constructor() {
2024-06-15 13:47:54 +08:00
/**
*
name: '更新',
dsc: '#更新 #强制更新',
*/
2024-06-12 22:36:39 +08:00
super()
2024-06-15 13:47:54 +08:00
this.priority = 4000
this.rule = [
2024-06-12 22:36:39 +08:00
{
2024-06-15 11:18:45 +08:00
reg: /^#更新日志/,
2024-06-12 22:36:39 +08:00
fnc: this.updateLog.name
},
{
2024-06-15 11:18:45 +08:00
reg: /^#(强制)?更新/,
2024-06-12 22:36:39 +08:00
fnc: this.update.name
},
{
2024-06-15 11:18:45 +08:00
reg: /^#(静默)?全部(强制)?更新$/,
2024-06-12 22:36:39 +08:00
fnc: this.updateAll.name,
permission: 'master'
}
]
2024-06-11 21:03:42 +08:00
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
async update() {
if (!this.e.isMaster) return false
2024-06-15 13:47:54 +08:00
if (uping) return this.reply('已有命令更新中..请勿重复操作')
2024-06-11 21:03:42 +08:00
if (/详细|详情|面板|面版/.test(this.e.msg)) return false
/** 获取插件 */
2024-06-15 13:47:54 +08:00
let plugin = this.getPlugin()
if (plugin === false) return false
2024-06-11 21:03:42 +08:00
/** 执行更新 */
2024-06-15 13:47:54 +08:00
if (plugin === '') {
2024-06-11 21:03:42 +08:00
await this.runUpdate('')
await sleep(1000)
2024-06-15 13:47:54 +08:00
plugin = this.getPlugin('miao-plugin')
await this.runUpdate(plugin)
2024-06-11 21:03:42 +08:00
} else {
2024-06-15 13:47:54 +08:00
await this.runUpdate(plugin)
2024-06-11 21:03:42 +08:00
}
/** 是否需要重启 */
if (this.isUp) {
// await this.reply('即将执行重启,以应用更新')
setTimeout(() => this.restart(), 2000)
}
}
2024-06-15 13:47:54 +08:00
getPlugin(plugin = '') {
if (!plugin) {
plugin = this.e.msg.replace(/#(强制)?更新(日志)?/, '')
if (!plugin) return ''
2024-06-11 21:03:42 +08:00
}
2024-06-15 13:47:54 +08:00
if (!fs.existsSync(`plugins/${plugin}/.git`)) return false
this.typeName = plugin
return plugin
2024-06-11 21:03:42 +08:00
}
async execSync(cmd) {
2024-06-15 13:47:54 +08:00
return new Promise((resolve, reject) => {
2024-06-11 21:03:42 +08:00
exec(cmd, { windowsHide: true }, (error, stdout, stderr) => {
resolve({ error, stdout, stderr })
})
})
}
2024-06-15 13:47:54 +08:00
async runUpdate(plugin = '') {
2024-06-11 21:03:42 +08:00
this.isNowUp = false
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
let cm = 'git pull --no-rebase'
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
let type = '更新'
if (this.e.msg.includes('强制')) {
type = '强制更新'
cm = `git reset --hard && git pull --rebase --allow-unrelated-histories`
}
2024-06-15 13:47:54 +08:00
if (plugin) cm = `cd "plugins/${plugin}" && ${cm}`
this.oldCommitId = await this.getcommitId(plugin)
2024-06-11 21:03:42 +08:00
logger.mark(`${this.e.logFnc} 开始${type}${this.typeName}`)
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
await this.reply(`开始${type} ${this.typeName}`)
uping = true
const ret = await this.execSync(cm)
uping = false
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
if (ret.error) {
logger.mark(`${this.e.logFnc} 更新失败:${this.typeName}`)
this.gitErr(ret.error, ret.stdout)
return false
}
2024-06-15 13:47:54 +08:00
const time = await this.getTime(plugin)
2024-06-11 21:03:42 +08:00
if (/Already up|已经是最新/g.test(ret.stdout)) {
await this.reply(`${this.typeName} 已是最新\n最后更新时间${time}`)
} else {
await this.reply(`${this.typeName} 更新成功\n更新时间${time}`)
this.isUp = true
2024-06-15 13:47:54 +08:00
await this.reply(await this.getLog(plugin))
2024-06-11 21:03:42 +08:00
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
logger.mark(`${this.e.logFnc} 最后更新时间:${time}`)
return true
}
2024-06-15 13:47:54 +08:00
async getcommitId(plugin = '') {
2024-06-11 21:03:42 +08:00
let cm = 'git rev-parse --short HEAD'
2024-06-15 13:47:54 +08:00
if (plugin) cm = `cd "plugins/${plugin}" && ${cm}`
2024-06-11 21:03:42 +08:00
const commitId = await execSync(cm, { encoding: 'utf-8' })
return lodash.trim(commitId)
}
2024-06-15 13:47:54 +08:00
async getTime(plugin = '') {
2024-06-11 21:03:42 +08:00
let cm = 'git log -1 --pretty=%cd --date=format:"%F %T"'
2024-06-15 13:47:54 +08:00
if (plugin) cm = `cd "plugins/${plugin}" && ${cm}`
2024-06-11 21:03:42 +08:00
let time = ''
try {
time = await execSync(cm, { encoding: 'utf-8' })
time = lodash.trim(time)
} catch (error) {
logger.error(error.toString())
time = '获取时间失败'
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
return time
}
async gitErr(err, stdout) {
const msg = '更新失败!'
const errMsg = err.toString()
stdout = stdout.toString()
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
if (errMsg.includes('Timed out')) {
const remote = errMsg.match(/'(.+?)'/g)[0].replace(/'/g, '')
return this.reply(`${msg}\n连接超时${remote}`)
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
if (/Failed to connect|unable to access/g.test(errMsg)) {
const remote = errMsg.match(/'(.+?)'/g)[0].replace(/'/g, '')
return this.reply(`${msg}\n连接失败${remote}`)
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
if (errMsg.includes('be overwritten by merge')) {
return this.reply(`${msg}\n存在冲突\n${errMsg}\n请解决冲突后再更新或者执行#强制更新,放弃本地修改`)
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
if (stdout.includes('CONFLICT')) {
return this.reply(`${msg}\n存在冲突\n${errMsg}${stdout}\n请解决冲突后再更新或者执行#强制更新,放弃本地修改`)
}
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
return this.reply([errMsg, stdout])
}
async updateAll() {
2024-06-15 13:47:54 +08:00
const dirs = fs.readdirSync('./plugins/')
2024-06-11 21:03:42 +08:00
const originalReply = this.reply
2024-06-15 13:47:54 +08:00
2024-06-11 21:03:42 +08:00
const testReg = /^#静默全部(强制)?更新$/.test(this.e.msg)
if (testReg) {
await this.reply(`开始执行静默全部更新,请稍等...`)
this.reply = (message) => {
this.messages.push(message)
}
}
await this.runUpdate()
for (let plu of dirs) {
plu = this.getPlugin(plu)
if (plu === false) continue
await sleep(1500)
await this.runUpdate(plu)
}
if (testReg) {
await this.reply(await makeForwardMsg(this.e, this.messages))
}
if (this.isUp) {
// await this.reply('即将执行重启,以应用更新')
setTimeout(() => this.restart(), 2000)
}
this.reply = originalReply
}
restart() {
new Restart(this.e).restart()
}
2024-06-15 13:47:54 +08:00
async getLog(plugin = '') {
2024-06-11 21:03:42 +08:00
let cm = 'git log -100 --pretty="%h||[%cd] %s" --date=format:"%F %T"'
2024-06-15 13:47:54 +08:00
if (plugin) cm = `cd "plugins/${plugin}" && ${cm}`
2024-06-11 21:03:42 +08:00
let logAll
try {
logAll = await execSync(cm, { encoding: 'utf-8' })
} catch (error) {
logger.error(error.toString())
await this.reply(error.toString())
}
if (!logAll) return false
logAll = logAll.trim().split('\n')
let log = []
for (let str of logAll) {
str = str.split('||')
if (str[0] == this.oldCommitId) break
if (str[1].includes('Merge branch')) continue
log.push(str[1])
}
let line = log.length
log = log.join('\n\n')
if (log.length <= 0) return ''
let end = ''
try {
cm = 'git config -l'
2024-06-15 13:47:54 +08:00
if (plugin) cm = `cd "plugins/${plugin}" && ${cm}`
2024-06-11 21:03:42 +08:00
end = await execSync(cm, { encoding: 'utf-8' })
end = end.match(/remote\..*\.url=.+/g).join('\n\n').replace(/remote\..*\.url=/g, '').replace(/\/\/([^@]+)@/, '//')
} catch (error) {
logger.error(error.toString())
await this.reply(error.toString())
}
2024-06-15 13:47:54 +08:00
return makeForwardMsg(this.e, [log, end], `${plugin || 'Miao-Yunzai'} 更新日志,共${line}`)
2024-06-11 21:03:42 +08:00
}
async updateLog() {
2024-06-15 13:47:54 +08:00
const plugin = this.getPlugin()
if (plugin === false) return false
return this.reply(await this.getLog(plugin))
2024-06-11 21:03:42 +08:00
}
}