Skip to content

Commit

Permalink
support --update
Browse files Browse the repository at this point in the history
  • Loading branch information
Karmenzind committed Dec 30, 2023
1 parent f9bba7b commit 9ec3fa1
Show file tree
Hide file tree
Showing 12 changed files with 357 additions and 133 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/release-tags.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ jobs:
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}

- name: echo changelog
run: echo ${{steps.build_changelog.outputs.changelog}}

# - name: Generate Changelog
# run: echo "由changelog生成" > ${{ github.workspace }}-CHANGELOG.txt

Expand All @@ -57,7 +60,7 @@ jobs:
body: ${{steps.build_changelog.outputs.changelog}}
fail_on_unmatched_files: true
# tag_name: v0.0.1
prerelease: true
prerelease: false
files: build/*

- name: info
Expand Down
110 changes: 48 additions & 62 deletions cmd/kd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import (
"os/exec"
"os/user"
"runtime"
"strconv"
"strings"
"syscall"

"github.com/Karmenzind/kd/config"
"github.com/Karmenzind/kd/internal"
Expand All @@ -24,6 +22,8 @@ import (
"go.uber.org/zap"
)

var VERSION = "v0.0.2"

func showPrompt() {
exename, err := pkg.GetExecutableBasename()
if err != nil {
Expand All @@ -48,52 +48,6 @@ var um = map[string]string{
"status": "show running status 展示运行信息",
}

func KillDaemonIfRunning() error {
p, err := daemon.FindServerProcess()
var trySysKill bool
if err == nil {
if p == nil {
d.EchoOkay("未发现守护进程,无需停止")
return nil
} else if runtime.GOOS != "windows" {
zap.S().Infof("Found running daemon PID: %d,", p.Pid)
errSig := p.SendSignal(syscall.SIGINT)
if errSig != nil {
zap.S().Warnf("Failed to stop PID %d with syscall.SIGINT: %s", p.Pid, errSig)
trySysKill = true
}
} else {
trySysKill = true
}
} else {
zap.S().Warnf("[process] Failed to find daemon: %s", err)
trySysKill = true
}
pidStr := strconv.Itoa(int(p.Pid))

if trySysKill {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("taskkill", "/F", "/T", "/PID", pidStr)
// cmd = exec.Command("taskkill", "/im", "kd", "/T", "/F")
case "linux":
cmd = exec.Command("kill", "-9", pidStr)
// cmd = exec.Command("killall", "kd")
}
output, err := cmd.Output()
zap.S().Infof("Executed '%s'. Output %s", cmd, output)
if err != nil {
zap.S().Warnf("Failed to kill daemon with system command. Error: %s", output, err)
}
}
if err == nil {
zap.S().Info("Terminated daemon process.")
d.EchoOkay("守护进程已经停止")
}
return err
}

// -----------------------------------------------------------------------------
// cli flag actions
// -----------------------------------------------------------------------------
Expand Down Expand Up @@ -121,25 +75,51 @@ func flagDaemon(*cli.Context, bool) error {
}

func flagStop(*cli.Context, bool) error {
err := KillDaemonIfRunning()
err := daemon.KillDaemonIfRunning()
if err != nil {
d.EchoFatal(err.Error())
}
return nil
}

func flagUpdate(*cli.Context, bool) error {
if pkg.GetLinuxDistro() == "arch" {
d.EchoFine("您在使用ArchLinux,推荐通过AUR安装/升级,更方便省心")
func flagUpdate(ctx *cli.Context, _ bool) (err error) {
if runtime.GOOS == "windows" {
d.EchoWrong("Windows暂不支持一键更新,请手动到release页面下载")
}
var ver string
// if pkg.GetLinuxDistro() == "arch" {
// d.EchoFine("您在使用ArchLinux,推荐通过AUR安装/升级,更方便省心")
// }
force := ctx.Bool("force")
if force {
d.EchoRun("强制更新")
}
if pkg.AskYN("Update kd binary file?") {
emoji.Println(":lightning: Let's update now")
update.UpdateBinary()
} else {
fmt.Println("Canceled.", d.B(d.Green(":)")))
doUpdate := force
if !doUpdate {
ver, err = update.GetNewerVersion(VERSION)
if err != nil {
d.EchoError(err.Error())
return
}
if ver != "" {
prompt := fmt.Sprintf("Found new version (%s). Update?", ver)
if pkg.AskYN(prompt) {
doUpdate = true
} else {
fmt.Println("Canceled.", d.B(d.Green(":)")))
return nil
}
} else {
fmt.Println("You're using the latest version.")
return nil
}
}
return nil

if doUpdate {
emoji.Println(":lightning: Let's update now")
err = update.UpdateBinary(VERSION)
}
return err
}

func flagGenerateConfig(*cli.Context, bool) error {
Expand Down Expand Up @@ -191,6 +171,11 @@ func flagStatus(*cli.Context, bool) error {
fmt.Printf(" Daemon PID:%d\n", di.PID)
fmt.Printf(" 配置文件地址:%s\n", config.CONFIG_PATH)
fmt.Printf(" 数据文件目录:%s\n", cache.CACHE_ROOT_PATH)
kdpath, err := pkg.GetExecutablePath()
if err == nil {
fmt.Printf(" Binary地址:%s\n", kdpath)
}

return nil
}

Expand Down Expand Up @@ -223,7 +208,7 @@ func main() {
app := &cli.App{
Suggest: true, // XXX
Name: "kd",
Version: "v0.0.1",
Version: VERSION,
Usage: "A crystal clean command-line dictionary.",
HideHelpCommand: true,
// EnableBashCompletion: true,
Expand All @@ -234,16 +219,17 @@ func main() {
&cli.BoolFlag{Name: "text", Aliases: []string{"t"}, Hidden: true, Usage: um["text"]},
&cli.BoolFlag{Name: "nocache", Aliases: []string{"n"}, DisableDefaultText: true, Usage: um["nocache"]},
&cli.StringFlag{Name: "theme", Aliases: []string{"T"}, DefaultText: "temp", Usage: um["theme"]},
&cli.BoolFlag{Name: "force", Aliases: []string{"f"}, DisableDefaultText: true, Hidden: true},

// BoolFlags as commands
&cli.BoolFlag{Name: "init", DisableDefaultText: true, Hidden: true, Usage: um["init"]},
&cli.BoolFlag{Name: "server", DisableDefaultText: true, Action: flagServer, Usage: um["server"]},
&cli.BoolFlag{Name: "server", DisableDefaultText: true, Action: flagServer, Hidden: true, Usage: um["server"]},
&cli.BoolFlag{Name: "daemon", DisableDefaultText: true, Action: flagDaemon, Usage: um["daemon"]},
&cli.BoolFlag{Name: "stop", DisableDefaultText: true, Hidden: true, Action: flagStop, Usage: um["stop"]},
&cli.BoolFlag{Name: "update", DisableDefaultText: true, Action: flagUpdate, Usage: um["update"]},
&cli.BoolFlag{Name: "generate-config", DisableDefaultText: true, Action: flagGenerateConfig, Usage: um["generate-config"]},
&cli.BoolFlag{Name: "edit-config", DisableDefaultText: true, Action: flagEditConfig, Usage: um["edit-config"]},
&cli.BoolFlag{Name: "status", DisableDefaultText: true, Action: flagStatus, Usage: um["status"]},
&cli.BoolFlag{Name: "status", DisableDefaultText: true, Hidden: true, Action: flagStatus, Usage: um["status"]},
},
Action: func(cCtx *cli.Context) error {
// 除了--text外,其他的BoolFlag都当subcommand用
Expand Down Expand Up @@ -274,7 +260,7 @@ func main() {

qstr := strings.Join(cCtx.Args().Slice(), " ")

r, err := internal.Query(qstr, cCtx.Bool("nocache"))
r, err := internal.Query(qstr, cCtx.Bool("nocache"), cCtx.Bool("text"))
if cfg.FreqAlert {
if h := <-r.History; h > 3 {
d.EchoWarn(fmt.Sprintf("本月第%d次查询`%s`", h, r.Query))
Expand Down
11 changes: 9 additions & 2 deletions internal/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,10 @@ func ensureDaemon(running chan bool) {
running <- true
}

func Query(query string, noCache bool) (r *model.Result, err error) {
func Query(query string, noCache bool, longText bool) (r *model.Result, err error) {
query = strings.ToLower(strings.Trim(query, " "))

r = &model.Result{Query: query}
r = &model.Result{Query: query, IsLongText: longText}
r.History = make(chan int, 1)

daemonRunning := make(chan bool)
Expand All @@ -53,6 +53,13 @@ func Query(query string, noCache bool) (r *model.Result, err error) {
return
}


if longText {
r.Found = false
r.Prompt = "暂不支持长句翻译"
return
}

var inNotFound bool
line, err := cache.CheckNotFound(r.Query)
if err != nil {
Expand Down
50 changes: 49 additions & 1 deletion internal/daemon/process.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"fmt"
"os/exec"
"runtime"
"strconv"
"strings"
"syscall"
"time"

"github.com/Karmenzind/kd/pkg"
Expand Down Expand Up @@ -39,7 +41,7 @@ func FindServerProcess() (*process.Process, error) {
return nil, err
}
for _, p := range processes {
// XXX err
// XXX err
n, _ := p.Name()
if n == "kd" || (runtime.GOOS == "windows" && n == "kd.exe") {
cmd, _ := p.Cmdline()
Expand Down Expand Up @@ -86,3 +88,49 @@ func StartDaemonProcess() error {
}
return nil
}

func KillDaemonIfRunning() error {
p, err := FindServerProcess()
var trySysKill bool
if err == nil {
if p == nil {
d.EchoOkay("未发现守护进程,无需停止")
return nil
} else if runtime.GOOS != "windows" {
zap.S().Infof("Found running daemon PID: %d,", p.Pid)
errSig := p.SendSignal(syscall.SIGINT)
if errSig != nil {
zap.S().Warnf("Failed to stop PID %d with syscall.SIGINT: %s", p.Pid, errSig)
trySysKill = true
}
} else {
trySysKill = true
}
} else {
zap.S().Warnf("[process] Failed to find daemon: %s", err)
trySysKill = true
}
pidStr := strconv.Itoa(int(p.Pid))

if trySysKill {
var cmd *exec.Cmd
switch runtime.GOOS {
case "windows":
cmd = exec.Command("taskkill", "/F", "/T", "/PID", pidStr)
// cmd = exec.Command("taskkill", "/im", "kd", "/T", "/F")
case "linux":
cmd = exec.Command("kill", "-9", pidStr)
// cmd = exec.Command("killall", "kd")
}
output, err := cmd.Output()
zap.S().Infof("Executed '%s'. Output %s", cmd, output)
if err != nil {
zap.S().Warnf("Failed to kill daemon with system command. Error: %s", output, err)
}
}
if err == nil {
zap.S().Info("Terminated daemon process.")
d.EchoOkay("守护进程已经停止")
}
return err
}
27 changes: 14 additions & 13 deletions internal/model/dataobj.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ type CollinsItem struct {
}

type Result struct {
Found bool `json:"-"`
Prompt string `json:"-"`
IsEN bool `json:"-"`
IsPhrase bool `json:"-"`
Query string `json:"-"`
Found bool `json:"-"`
Prompt string `json:"-"`
IsEN bool `json:"-"`
IsPhrase bool `json:"-"`
IsLongText bool `json:"-"`
Query string `json:"-"`

Keyword string `json:"k"`
Pronounce map[string]string `json:"pron"`
Expand Down Expand Up @@ -139,9 +140,9 @@ func (r *Result) PrettyFormat(onlyEN bool) string {
if r.Collins.ViaRank != "" {
rankParts = append(rankParts, d.Rank(r.Collins.ViaRank))
}
if r.Collins.AdditionalPattern != "" {
if r.Collins.AdditionalPattern != "" {
rankParts = append(rankParts, d.Rank(r.Collins.AdditionalPattern))
}
}
if len(rankParts) > 0 {
s = append(s, strings.Join(rankParts, " "))
}
Expand All @@ -160,12 +161,12 @@ func (r *Result) PrettyFormat(onlyEN bool) string {
}

var piece string
piece = fmt.Sprintf("%s. ", d.Idx(idx + 1))
if i.Additional != "" {
piece += d.Addi("("+i.Additional+")")
}
piece += d.CollinsPara(transExpr)
s = append(s, piece)
piece = fmt.Sprintf("%s. ", d.Idx(idx+1))
if i.Additional != "" {
piece += d.Addi("(" + i.Additional + ")")
}
piece += d.CollinsPara(transExpr)
s = append(s, piece)

for _, ePair := range i.ExampleLists {
var eRepr string
Expand Down
10 changes: 7 additions & 3 deletions internal/model/request.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ type QueryDaemon struct {
}

type DaemonResponse struct {
R *Result
Error string
Found bool
R *Result

Error string
Found bool

// 需要通过Tcp传递,又不能入库的字段
IsLongText bool
}
26 changes: 13 additions & 13 deletions internal/query/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,22 +34,22 @@ func FetchCached(r *model.Result) (err error) {

func QueryDaemon(addr string, r *model.Result) error {
conn, err := net.Dial("tcp", addr)
if err != nil {
d.EchoFatal("与守护进程通信失败,请尝试执行`kd --daemon`,如果无法解决问题,请提交issue并上传日志")
}
if err != nil {
d.EchoFatal("与守护进程通信失败,请尝试执行`kd --daemon`,如果无法解决问题,请提交issue并上传日志")
}
fmt.Fprint(conn, r.Query)

message, _ := bufio.NewReader(conn).ReadBytes('\n')

dr := model.DaemonResponse{R: r}
dr := model.DaemonResponse{R: r, IsLongText: r.IsLongText}
err = json.Unmarshal(message, &dr)
r.Found = dr.Found
zap.S().Debugf("Message from server: %s", string(message))
if err != nil {
return fmt.Errorf("解析daemon返回结果失败: %s", err)
}
if dr.Error != "" {
return fmt.Errorf(dr.Error)
}
return nil
r.Found = dr.Found
zap.S().Debugf("Message from server: %s", string(message))
if err != nil {
return fmt.Errorf("解析daemon返回结果失败: %s", err)
}
if dr.Error != "" {
return fmt.Errorf(dr.Error)
}
return nil
}
Loading

0 comments on commit 9ec3fa1

Please sign in to comment.