diff --git a/src/cli/cmd/future.go b/src/cli/cmd/future.go new file mode 100644 index 0000000..a455377 --- /dev/null +++ b/src/cli/cmd/future.go @@ -0,0 +1,28 @@ +package cmd + +import ( + "github.com/devhindo/x/src/cli/tweet" + + "github.com/spf13/cobra" +) + +var ( + wait string + date string + content string +) + +func init() { + rootCmd.AddCommand(futureCmd) +} + +var futureCmd = &cobra.Command{ + Use: "-f", + Short: "Post future tweets", + Long: `Post future tweets.`, + Run: futureCmdRun, +} + +func futureCmdRun(cmd *cobra.Command, args []string) { + tweet.PostFutureTweet(args) +} diff --git a/src/cli/cmd/root.go b/src/cli/cmd/root.go new file mode 100644 index 0000000..8e3c58d --- /dev/null +++ b/src/cli/cmd/root.go @@ -0,0 +1,45 @@ +package cmd + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +var ( + version = "1.1.3" + man = fmt.Sprintf(`interact with x (twitter) from terminal. version: %s. + + USAGE + x + + Commands + -h show this help + auth start authorizing your X account + auth --url get auth url if it didn't open browser after running 'x auth' + auth -v verify authorization after running 'x auth' + -t "text" post a tweet + -v show version (%s) + -c clear authorized account`, version, version) +) + +var rootCmd = &cobra.Command{ + Use: "x", + Short: "x is a CLI tool for posting tweets", + Long: man, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(man) + }, +} + +func Execute() { + if err := rootCmd.Execute(); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func init() { + +} diff --git a/src/cli/cmd/tweet.go b/src/cli/cmd/tweet.go new file mode 100644 index 0000000..3b3b9bd --- /dev/null +++ b/src/cli/cmd/tweet.go @@ -0,0 +1,98 @@ +package cmd + +import ( + "fmt" + "regexp" + "strconv" + "time" + + "github.com/spf13/cobra" +) + +/* + x tweet -c "hi" -w 2d5h6m7s -d 2020-12-12 -t 3:34pm +*/ + +func init() { + rootCmd.AddCommand(tweetCmd) + + tweetCmd.Flags().StringP("content", "c", "", "Tweet message") + tweetCmd.Flags().StringP("wait", "w", "0", "When to post the tweet") + tweetCmd.Flags().StringP("date", "d", "0", "Date to post the tweet") + tweetCmd.Flags().StringP("time", "t", "0", "Time to post the tweet") + // tweetCmd.Flags().BoolP("media", "m", false, "Add media to the tweet") TODO: feat: post media content +} + +var ( + tweetCmd = &cobra.Command{ + Use: "tweet", + Short: "Post a tweet", + Long: `Post a tweet.`, + RunE: tweetCmdRun, + } +) + +func tweetCmdRun(cmd *cobra.Command, args []string) error { + content, err := cmd.Flags().GetString("content") + if err != nil { + err = fmt.Errorf("error getting content flag: %v", err) + return err + } + + wait, err := cmd.Flags().GetString("wait") + h, m, s, ms, err := handleWaitArg(wait) + if err != nil { + err = fmt.Errorf("error getting wait flag: %v", err) + return err + } + fmt.Println(h, m, s, ms) + + fmt.Println(content) + + return nil +} + +func calcWaitingTime() { + UTCtime := time.Now().UTC() + fmt.Println(UTCtime) +} + +// sra7a ai generated, I wouldn't be able to do that by myself +func handleWaitArg(wait string) (int, int, int, int, error) { + // Define the regular expression patterns for each unit + patterns := map[string]*regexp.Regexp{ + "d": regexp.MustCompile(`(\d*)d`), + "h": regexp.MustCompile(`(\d*)h`), + "m": regexp.MustCompile(`(\d*)m`), + "s": regexp.MustCompile(`(\d*)s`), + } + + // Initialize the time units + var days, hours, minutes, seconds int + + // Extract each unit from the argument + for unit, pattern := range patterns { + match := pattern.FindStringSubmatch(wait) + if match != nil { + value, err := strconv.Atoi(match[1]) + if err != nil { + return 0, 0, 0, 0, fmt.Errorf("invalid waiting time format: %s", wait) + } + + switch unit { + case "d": + days = value + case "h": + hours = value + case "m": + minutes = value + case "s": + seconds = value + } + } + } + + return days, hours, minutes, seconds, nil +} + + diff --git a/src/cli/cmd/update.go b/src/cli/cmd/update.go new file mode 100644 index 0000000..9c01ec9 --- /dev/null +++ b/src/cli/cmd/update.go @@ -0,0 +1,118 @@ +package cmd + +import ( + "fmt" + "os" + "os/exec" + "regexp" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(updateCmd) + + updateCmd.Flags().StringVarP(&vFlag, "version", "v", "latest", "Update the CLI to specific version") +} + +var ( + vFlag string + + updateCmd = &cobra.Command{ + Use: "update", + Short: "Update the CLI to specific version ", + Long: `Update the CLI to the latest version or specify a version using -v flag + Example: x update -v 1.1.1 + default: x update -v latest + `, + RunE: update, + } +) + +func update(cmd *cobra.Command, args []string) error { + + fmt.Println("Updating CLI...") + + vFlag, err := cmd.Flags().GetString("version") + if err != nil { + err = fmt.Errorf("error getting version flag: %v", err) + return err + } + + // validate version + if vFlag != "latest" { + err = validateVersion(vFlag) + if err != nil { + return err + } + } + + if isGoInstalled() { + err = updateUsingGo() + if err != nil { + return err + } + return nil + } + + return nil +} + +func validateVersion(v string) error { + // Regular expression pattern for semantic versioning + pattern := `^v\d+\.\d+\.\d+$` + match, err := regexp.MatchString(pattern, v) + if err != nil { + return err + } + if !match { + return fmt.Errorf("invalid version format. Please use semantic versioning like v1.1.1") + } + return nil +} + +func cmdUpdate() { + if !isGoInstalled() { + fmt.Println("") + } + + cmd := exec.Command("go", "get", "-u", "github.com/bradford-hamilton/monkey") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + if isGoInstalled() { + fmt.Println("Go is installed...") + + return + } + + fmt.Println("Go is not installed...") + + fmt.Println("CLI updated successfully!") +} + +func isGoInstalled() bool { + _, err := exec.LookPath("go") + + return err == nil +} + +func updateUsingGo() error { + cmd := exec.Command("go", "get", "-u", "github.com/devhindo/x/src/cli/cmd") + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + fmt.Println(err) + return err + } + fmt.Println("CLI updated successfully!") + return nil +} + +//TODO: x update -v 1.1.1 (default for v:latest) diff --git a/src/cli/cmd/version.go b/src/cli/cmd/version.go new file mode 100644 index 0000000..5158fcc --- /dev/null +++ b/src/cli/cmd/version.go @@ -0,0 +1,22 @@ +package cmd + +import ( + "fmt" + + "github.com/spf13/cobra" +) + +func init() { + rootCmd.AddCommand(versionCmd) +} + +//TODO: make it for -v and --version too + +var versionCmd = &cobra.Command{ + Use: "version", + Short: "Print the version of the CLI", + Long: `Print the version of the CLI`, + Run: func(cmd *cobra.Command, args []string) { + fmt.Println(version) + }, +} \ No newline at end of file diff --git a/src/cli/go.mod b/src/cli/go.mod index a9028b8..7999d7f 100644 --- a/src/cli/go.mod +++ b/src/cli/go.mod @@ -3,3 +3,9 @@ module github.com/devhindo/x/src/cli go 1.22.2 require github.com/google/uuid v1.3.1 + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/cobra v1.8.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect +) diff --git a/src/cli/go.sum b/src/cli/go.sum index a43f94d..779870e 100644 --- a/src/cli/go.sum +++ b/src/cli/go.sum @@ -1,2 +1,12 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/src/cli/main.go b/src/cli/main.go index c70a161..9abc3fd 100644 --- a/src/cli/main.go +++ b/src/cli/main.go @@ -1,8 +1,9 @@ package main -import "github.com/devhindo/x/src/cli/x" +import "github.com/devhindo/x/src/cli/cmd" func main() { - x.Run() + //x.Run() + cmd.Execute() } diff --git a/src/cli/x/args.go b/src/cli/x/args.go index 0fc3cab..08c8ba4 100644 --- a/src/cli/x/args.go +++ b/src/cli/x/args.go @@ -64,7 +64,7 @@ func HandleArgs() { os.Exit(0) } - tweet.POST_tweet(os.Args[1]) + //tweet.POST_tweet(os.Args[1]) x tweetText } } diff --git a/src/cli/x/run.go b/src/cli/x/run.go index a7f707f..6ee0b4e 100644 --- a/src/cli/x/run.go +++ b/src/cli/x/run.go @@ -1,5 +1,10 @@ package x +import ( + "github.com/devhindo/x/src/cli/cmd" +) + func Run() { - HandleArgs() + // HandleArgs() + cmd.Execute() } \ No newline at end of file