Skip to content

Latest commit

 

History

History
200 lines (161 loc) · 6.69 KB

blog.md

File metadata and controls

200 lines (161 loc) · 6.69 KB

以下是使用Go语言的cobra框架来实现满足你需求的命令行工具的示例代码,这个工具可以用来管理定时任务相关的操作(模拟类似 ecron的功能),以下是具体步骤:

1. 安装cobra框架

在命令行中执行以下命令来安装cobra

go install github.com/spf13/cobra-cli

2. 创建项目目录结构并初始化cobra项目

创建一个项目目录,比如叫 ecron,然后在该目录下打开命令行,执行以下命令初始化cobra项目:

cobra-cli init --pkg-name ecron

这会生成一些基础的文件和目录结构,包括 main.gocmd 目录等。

3. 编写命令相关代码

cmd 目录下创建各个具体功能对应的命令文件,这里以实现你提到的命令为例:

  • list.go 文件(实现 ecron list 命令)
package cmd

import (
    "fmt"

    "github.com/spf13/cobra"
)

// listCmd represents the list command
var listCmd = &cobra.Command{
    Use:   "list",
    Short: "List all scheduled tasks",
    Long:  `List all the currently scheduled tasks.`,
    Run: func(cmd *cobra.Command, args []string) {
        // 这里暂时只是模拟输出,实际中你可以从存储定时任务的地方获取并展示真正的任务列表
        fmt.Println("No tasks to display yet. Implement actual logic to list tasks.")
    },
}

func init() {
    // 将list命令添加到根命令下
    RootCmd.AddCommand(listCmd)
}
  • add.go 文件(实现各种 ecron add 相关命令)
package cmd

import (
    "fmt"
    "strings"

    "github.com/spf13/cobra"
)

// addCmd represents the add command
var addCmd = &cobra.Command{
    Use:   "add",
    Short: "Add a new scheduled task",
    Long:  `Add a new scheduled task with specified schedule options.`,
    Run: func(cmd *cobra.Command, args []string) {
        if len(args) < 1 {
            fmt.Println("Please provide a script path")
            return
        }
        scriptPath := args[0]

        minutely, _ := cmd.Flags().GetBool("minutely")
        hourly, _ := cmd.Flags().GetBool("hourly")
        daily, _ := cmd.Flags().GetBool("daily")
        weekly, _ := cmd.Flags().GetBool("weekly")
        expr, _ := cmd.Flags().GetString("expr")
        quarter, _ := cmd.Flags().GetString("quarter")
        at, _ := cmd.Flags().GetString("at")
        on, _ := cmd.Flags().GetString("on")

        schedule := ""
        if minutely {
            schedule = "*/1 * * * *"
        } else if hourly {
            if quarter!= "" {
                quarters := strings.Split(quarter, "/")
                // 简单拼接下季度的定时表达式示例,实际可能更复杂要校验等
                schedule = fmt.Sprintf("0 %s * * *", strings.Join(quarters, ","))
            } else {
                schedule = "0 * * * *"
            }
        } else if daily {
            if at!= "" {
                // 简单处理下时间转换为定时表达式示例,实际要严格校验格式等
                hour := strings.TrimSuffix(at, "am")
                hour = strings.TrimSuffix(hour, "pm")
                if strings.HasSuffix(at, "pm") {
                    hourInt := atoi(hour) + 12
                    hour = fmt.Sprintf("%d", hourInt)
                }
                schedule = fmt.Sprintf("0 %s * * *", hour)
            } else {
                schedule = "0 0 * * *"
            }
        } else if weekly {
            if on!= "" && at!= "" {
                // 同样是简单示例,要完善日期和时间到定时表达式转换逻辑
                dayNumber := getDayNumber(on)
                hour := strings.TrimSuffix(at, "am")
                hour = strings.TrimSuffix(hour, "pm")
                if strings.HasSuffix(at, "pm") {
                    hourInt := atoi(hour) + 12
                    hour = fmt.Sprintf("%d", hourInt)
                }
                schedule = fmt.Sprintf("0 %s * * %d", hour, dayNumber)
            } else {
                fmt.Println("For weekly schedule, --on and --at flags are required")
                return
            }
        } else if expr!= "" {
            schedule = expr
        }

        // 这里暂时只是模拟打印出最终要添加的定时任务相关信息,实际中要将任务保存到合适的地方
        fmt.Printf("Adding task with schedule '%s' for script '%s'\n", schedule, scriptPath)
    },
}

func init() {
    // 将add命令添加到根命令下
    RootCmd.AddCommand(addCmd)

    addCmd.Flags().Bool("minutely", false, "Run the script every minute")
    addCmd.Flags().Bool("hourly", false, "Run the script every hour")
    addCmd.Flags().Bool("daily", false, "Run the script every day")
    addCmd.Flags().Bool("weekly", false, "Run the script every week")
    addCmd.Flags().String("expr", "", "Custom cron expression for the script")
    addCmd.Flags().String("quarter", "", "Quarters of the hour for hourly schedule (e.g., 0/1/2/3)")
    addCmd.Flags().String("at", "", "Specific time for daily or weekly schedule (e.g., 1am or 12pm)")
    addCmd.Flags().String("on", "", "Day of the week for weekly schedule (e.g., monday)")
}

func atoi(s string) int {
    var n int
    _, err := fmt.Sscanf(s, "%d", &n)
    if err!= nil {
        return 0
    }
    return n
}

func getDayNumber(day string) int {
    days := map[string]int{
        "monday":    1,
        "tuesday":   2,
        "wednesday": 3,
        "thursday":  4,
        "friday":    5,
        "saturday":  6,
        "sunday":    7,
    }
    return days[strings.ToLower(day)]
}
  • main.go 文件(入口文件,整合命令)
package main

import "ecron-cli/cmd"

func main() {
    cmd.Execute()
}

4. 运行项目及测试命令

在命令行切换到项目的根目录(ecron-cli 目录),然后执行以下命令来运行项目:

go run main.go

之后就可以测试各个命令了,比如:

  • go run main.go ecron list:会输出提示当前还没有任务可展示的信息(因为实际获取任务列表逻辑还没完善)。
  • go run main.go ecron add --minutely /opt/script.sh:会打印出根据 minutely 规则生成的定时任务信息以及对应的脚本路径(同样只是模拟,没真正保存任务)。
  • 按照你提供的其他命令格式类似地进行测试,如 go run main.go ecron add --hourly --quarter=0/1/2/3 /opt/script.sh 等。

请注意,上述代码中的定时任务相关的表达式生成等逻辑只是简单示例,在实际应用中需要更严谨地进行校验、处理时间格式转换以及将任务保存到合适的存储(比如数据库等),还可以添加更多的错误处理和功能完善。你可以根据实际需求进一步扩展和优化这个命令行工具哦。