forked from Elara6331/itd
		
	Rewrite itctl to use urfave/cli instead of spf13/cobra
This commit is contained in:
		| @@ -1,35 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // filesystemCmd represents the filesystem command | ||||
| var filesystemCmd = &cobra.Command{ | ||||
| 	Use:   "filesystem", | ||||
| 	Aliases: []string{"fs"}, | ||||
| 	Short: "Perform filesystem operations on the PineTime", | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(filesystemCmd) | ||||
| } | ||||
| @@ -1,56 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // listCmd represents the list command | ||||
| var listCmd = &cobra.Command{ | ||||
| 	Use:     "list [path]", | ||||
| 	Aliases: []string{"ls"}, | ||||
| 	Short:   "List a directory", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		dirPath := "/" | ||||
| 		if len(args) > 0 { | ||||
| 			dirPath = args[0] | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		listing, err := client.ReadDir(dirPath) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting directory listing") | ||||
| 		} | ||||
|  | ||||
| 		for _, entry := range listing { | ||||
| 			fmt.Println(entry) | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	filesystemCmd.AddCommand(listCmd) | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // mkdirCmd represents the mkdir command | ||||
| var mkdirCmd = &cobra.Command{ | ||||
| 	Use:   "mkdir <path...>", | ||||
| 	Short: "Create a new directory", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		if len(args) < 1 { | ||||
| 			cmd.Usage() | ||||
| 			log.Fatal().Msg("Command mkdir requires one or more arguments") | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		err := client.Mkdir(args...) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error creating directory") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	filesystemCmd.AddCommand(mkdirCmd) | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // moveCmd represents the move command | ||||
| var moveCmd = &cobra.Command{ | ||||
| 	Use:     "move <old> <new>", | ||||
| 	Aliases: []string{"mv"}, | ||||
| 	Short:   "Move a file or directory", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		if len(args) != 2 { | ||||
| 			cmd.Usage() | ||||
| 			log.Fatal().Msg("Command move requires two arguments") | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		err := client.Rename(args[0], args[1]) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error moving file or directory") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	filesystemCmd.AddCommand(moveCmd) | ||||
| } | ||||
| @@ -1,95 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/cheggaaa/pb/v3" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // readCmd represents the read command | ||||
| var readCmd = &cobra.Command{ | ||||
| 	Use:   `read <remote path> <local path | "-">`, | ||||
| 	Short: "Read a file from InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		if len(args) != 2 { | ||||
| 			cmd.Usage() | ||||
| 			log.Fatal().Msg("Command read requires two arguments") | ||||
| 		} | ||||
|  | ||||
| 		var tmpFile *os.File | ||||
| 		var path string | ||||
| 		var err error | ||||
| 		if args[1] == "-" { | ||||
| 			tmpFile, err = ioutil.TempFile("/tmp", "itctl.*") | ||||
| 			if err != nil { | ||||
| 				log.Fatal().Err(err).Msg("Error creating temporary file") | ||||
| 			} | ||||
| 			path = tmpFile.Name() | ||||
| 		} else { | ||||
| 			path, err = filepath.Abs(args[1]) | ||||
| 			if err != nil { | ||||
| 				log.Fatal().Err(err).Msg("Error making absolute directory") | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		progress, err := client.ReadFile(path, args[0]) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error reading remote file") | ||||
| 		} | ||||
|  | ||||
| 		// Create progress bar template | ||||
| 		barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}` | ||||
| 		// Start full bar at 0 total | ||||
| 		bar := pb.ProgressBarTemplate(barTmpl).Start(0) | ||||
| 		// Get progress events | ||||
| 		for event := range progress { | ||||
| 			// Set total bytes in progress bar | ||||
| 			bar.SetTotal(int64(event.Total)) | ||||
| 			// Set amount of bytes sent in progress bar | ||||
| 			bar.SetCurrent(int64(event.Sent)) | ||||
| 			// If transfer finished, break | ||||
| 			if event.Done { | ||||
| 				bar.Finish() | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if args[1] == "-" { | ||||
| 			io.Copy(os.Stdout, tmpFile) | ||||
| 			os.Stdout.WriteString("\n") | ||||
| 			os.Stdout.Sync() | ||||
| 			tmpFile.Close() | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	filesystemCmd.AddCommand(readCmd) | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // removeCmd represents the remove command | ||||
| var removeCmd = &cobra.Command{ | ||||
| 	Use:   "remove <path...>", | ||||
| 	Aliases: []string{"rm"}, | ||||
| 	Short: "Create a new directory", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		if len(args) < 1 { | ||||
| 			cmd.Usage() | ||||
| 			log.Fatal().Msg("Command mkdir requires one or more arguments") | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		err := client.Remove(args...) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error removing file or directory") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	filesystemCmd.AddCommand(removeCmd) | ||||
| } | ||||
| @@ -1,94 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package filesystem | ||||
|  | ||||
| import ( | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/cheggaaa/pb/v3" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // writeCmd represents the write command | ||||
| var writeCmd = &cobra.Command{ | ||||
| 	Use:   `write <local path | "-"> <remote path>`, | ||||
| 	Short: "Write a file to InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		if len(args) != 2 { | ||||
| 			cmd.Usage() | ||||
| 			log.Fatal().Msg("Command write requires two arguments") | ||||
| 		} | ||||
|  | ||||
| 		var tmpFile *os.File | ||||
| 		var path string | ||||
| 		var err error | ||||
| 		if args[0] == "-" { | ||||
| 			tmpFile, err = ioutil.TempFile("/tmp", "itctl.*") | ||||
| 			if err != nil { | ||||
| 				log.Fatal().Err(err).Msg("Error creating temporary file") | ||||
| 			} | ||||
| 			path = tmpFile.Name() | ||||
| 		} else { | ||||
| 			path, err = filepath.Abs(args[0]) | ||||
| 			if err != nil { | ||||
| 				log.Fatal().Err(err).Msg("Error making absolute directory") | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		if args[0] == "-" { | ||||
| 			io.Copy(tmpFile, os.Stdin) | ||||
| 			defer tmpFile.Close() | ||||
| 			defer os.Remove(path) | ||||
| 		} | ||||
|  | ||||
| 		progress, err := client.WriteFile(path, args[1]) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error moving file or directory") | ||||
| 		} | ||||
|  | ||||
| 		// Create progress bar template | ||||
| 		barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}` | ||||
| 		// Start full bar at 0 total | ||||
| 		bar := pb.ProgressBarTemplate(barTmpl).Start(0) | ||||
| 		// Get progress events | ||||
| 		for event := range progress { | ||||
| 			// Set total bytes in progress bar | ||||
| 			bar.SetTotal(int64(event.Total)) | ||||
| 			// Set amount of bytes sent in progress bar | ||||
| 			bar.SetCurrent(int64(event.Sent)) | ||||
| 			// If transfer finished, break | ||||
| 			if event.Done { | ||||
| 				bar.Finish() | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	filesystemCmd.AddCommand(writeCmd) | ||||
| } | ||||
							
								
								
									
										80
									
								
								cmd/itctl/firmware.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								cmd/itctl/firmware.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,80 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/cheggaaa/pb/v3" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| 	"go.arsenm.dev/itd/internal/types" | ||||
| ) | ||||
|  | ||||
| func fwUpgrade(c *cli.Context) error { | ||||
| 	start := time.Now() | ||||
|  | ||||
| 	var upgType api.UpgradeType | ||||
| 	var files []string | ||||
| 	// Get relevant data struct | ||||
| 	if c.String("archive") != "" { | ||||
| 		// Get archive data struct | ||||
| 		upgType = types.UpgradeTypeArchive | ||||
| 		files = []string{c.String("archive")} | ||||
| 	} else if c.String("init-packet") != "" && c.String("firmware") != "" { | ||||
| 		// Get files data struct | ||||
| 		upgType = types.UpgradeTypeFiles | ||||
| 		files = []string{c.String("init-packet"), c.String("firmware")} | ||||
| 	} else { | ||||
| 		return cli.Exit("Upgrade command requires either archive or init packet and firmware.", 1) | ||||
| 	} | ||||
|  | ||||
| 	progress, err := client.FirmwareUpgrade(upgType, abs(files)...) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Create progress bar template | ||||
| 	barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}` | ||||
| 	// Start full bar at 0 total | ||||
| 	bar := pb.ProgressBarTemplate(barTmpl).Start(0) | ||||
| 	// Create new scanner of connection | ||||
| 	for event := range progress { | ||||
| 		// Set total bytes in progress bar | ||||
| 		bar.SetTotal(event.Total) | ||||
| 		// Set amount of bytes received in progress bar | ||||
| 		bar.SetCurrent(event.Received) | ||||
| 		// If transfer finished, break | ||||
| 		if event.Sent == event.Total { | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
| 	// Finish progress bar | ||||
| 	bar.Finish() | ||||
|  | ||||
| 	fmt.Printf("Transferred %d B in %s.\n", bar.Total(), time.Since(start)) | ||||
| 	fmt.Println("Remember to validate the new firmware in the InfiniTime settings.") | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func fwVersion(c *cli.Context) error { | ||||
| 	version, err := client.Version() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println(version) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func abs(paths []string) []string { | ||||
| 	for index, path := range paths { | ||||
| 		newPath, err := filepath.Abs(path) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		paths[index] = newPath | ||||
| 	} | ||||
| 	return paths | ||||
| } | ||||
| @@ -1,35 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package firmware | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // firmwareCmd represents the firmware command | ||||
| var firmwareCmd = &cobra.Command{ | ||||
| 	Use:     "firmware", | ||||
| 	Short:   "Manage InfiniTime firmware", | ||||
| 	Aliases: []string{"fw"}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(firmwareCmd) | ||||
| } | ||||
| @@ -1,117 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package firmware | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/cheggaaa/pb/v3" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| 	"go.arsenm.dev/itd/internal/types" | ||||
| ) | ||||
|  | ||||
| type DFUProgress struct { | ||||
| 	Received int64 `mapstructure:"recvd"` | ||||
| 	Total    int64 `mapstructure:"total"` | ||||
| } | ||||
|  | ||||
| // upgradeCmd represents the upgrade command | ||||
| var upgradeCmd = &cobra.Command{ | ||||
| 	Use:     "upgrade", | ||||
| 	Short:   "Upgrade InfiniTime firmware using files or archive", | ||||
| 	Aliases: []string{"upg"}, | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		start := time.Now() | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		var upgType api.UpgradeType | ||||
| 		var files []string | ||||
| 		// Get relevant data struct | ||||
| 		if viper.GetString("archive") != "" { | ||||
| 			// Get archive data struct | ||||
| 			upgType = types.UpgradeTypeArchive | ||||
| 			files = []string{viper.GetString("archive")} | ||||
| 		} else if viper.GetString("initPkt") != "" && viper.GetString("firmware") != "" { | ||||
| 			// Get files data struct | ||||
| 			upgType = types.UpgradeTypeFiles | ||||
| 			files = []string{viper.GetString("initPkt"), viper.GetString("firmware")} | ||||
| 		} else { | ||||
| 			cmd.Usage() | ||||
| 			log.Warn().Msg("Upgrade command requires either archive or init packet and firmware.") | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		progress, err := client.FirmwareUpgrade(upgType, abs(files)...) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error initiating DFU") | ||||
| 		} | ||||
|  | ||||
| 		// Create progress bar template | ||||
| 		barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}` | ||||
| 		// Start full bar at 0 total | ||||
| 		bar := pb.ProgressBarTemplate(barTmpl).Start(0) | ||||
| 		// Create new scanner of connection | ||||
| 		for event := range progress { | ||||
| 			// Set total bytes in progress bar | ||||
| 			bar.SetTotal(event.Total) | ||||
| 			// Set amount of bytes received in progress bar | ||||
| 			bar.SetCurrent(event.Received) | ||||
| 			// If transfer finished, break | ||||
| 			if event.Sent == event.Total { | ||||
| 				break | ||||
| 			} | ||||
| 		} | ||||
| 		// Finish progress bar | ||||
| 		bar.Finish() | ||||
|  | ||||
| 		fmt.Printf("Transferred %d B in %s.\n", bar.Total(), time.Since(start)) | ||||
| 		fmt.Println("Remember to validate the new firmware in the InfiniTime settings.") | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func abs(paths []string) []string { | ||||
| 	for index, path := range paths { | ||||
| 		newPath, err := filepath.Abs(path) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
| 		paths[index] = newPath | ||||
| 	} | ||||
| 	return paths | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	firmwareCmd.AddCommand(upgradeCmd) | ||||
|  | ||||
| 	// Register flags | ||||
| 	upgradeCmd.Flags().StringP("archive", "a", "", "Path to firmware archive") | ||||
| 	upgradeCmd.Flags().StringP("init-pkt", "i", "", "Path to init packet (.dat file)") | ||||
| 	upgradeCmd.Flags().StringP("firmware", "f", "", "Path to firmware image (.bin file)") | ||||
|  | ||||
| 	// Bind flags to viper keys | ||||
| 	viper.BindPFlag("archive", upgradeCmd.Flags().Lookup("archive")) | ||||
| 	viper.BindPFlag("initPkt", upgradeCmd.Flags().Lookup("init-pkt")) | ||||
| 	viper.BindPFlag("firmware", upgradeCmd.Flags().Lookup("firmware")) | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package firmware | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // versionCmd represents the version command | ||||
| var versionCmd = &cobra.Command{ | ||||
| 	Use:     "version", | ||||
| 	Aliases: []string{"ver"}, | ||||
| 	Short:   "Get firmware version of InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		version, err := client.Version() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting firmware version") | ||||
| 		} | ||||
|  | ||||
| 		fmt.Println(version) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	firmwareCmd.AddCommand(versionCmd) | ||||
| } | ||||
							
								
								
									
										174
									
								
								cmd/itctl/fs.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										174
									
								
								cmd/itctl/fs.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,174 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
|  | ||||
| 	"github.com/cheggaaa/pb/v3" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
|  | ||||
| func fsList(c *cli.Context) error { | ||||
| 	dirPath := "/" | ||||
| 	if c.Args().Len() > 0 { | ||||
| 		dirPath = c.Args().Get(0) | ||||
| 	} | ||||
|  | ||||
| 	listing, err := client.ReadDir(dirPath) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	for _, entry := range listing { | ||||
| 		fmt.Println(entry) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func fsMkdir(c *cli.Context) error { | ||||
| 	if c.Args().Len() < 1 { | ||||
| 		return cli.Exit("Command mkdir requires one or more arguments", 1) | ||||
| 	} | ||||
|  | ||||
| 	err := client.Mkdir(c.Args().Slice()...) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func fsMove(c *cli.Context) error { | ||||
| 	if c.Args().Len() != 2 { | ||||
| 		return cli.Exit("Command move requires two arguments", 1) | ||||
| 	} | ||||
|  | ||||
| 	err := client.Rename(c.Args().Get(0), c.Args().Get(1)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func fsRead(c *cli.Context) error { | ||||
| 	if c.Args().Len() != 2 { | ||||
| 		return cli.Exit("Command read requires two arguments", 1) | ||||
| 	} | ||||
|  | ||||
| 	var tmpFile *os.File | ||||
| 	var path string | ||||
| 	var err error | ||||
| 	if c.Args().Get(1) == "-" { | ||||
| 		tmpFile, err = ioutil.TempFile("/tmp", "itctl.*") | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		path = tmpFile.Name() | ||||
| 	} else { | ||||
| 		path, err = filepath.Abs(c.Args().Get(1)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	progress, err := client.ReadFile(path, c.Args().Get(0)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Create progress bar template | ||||
| 	barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}` | ||||
| 	// Start full bar at 0 total | ||||
| 	bar := pb.ProgressBarTemplate(barTmpl).Start(0) | ||||
| 	// Get progress events | ||||
| 	for event := range progress { | ||||
| 		// Set total bytes in progress bar | ||||
| 		bar.SetTotal(int64(event.Total)) | ||||
| 		// Set amount of bytes sent in progress bar | ||||
| 		bar.SetCurrent(int64(event.Sent)) | ||||
| 		// If transfer finished, break | ||||
| 		if event.Done { | ||||
| 			bar.Finish() | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if c.Args().Get(1) == "-" { | ||||
| 		io.Copy(os.Stdout, tmpFile) | ||||
| 		os.Stdout.WriteString("\n") | ||||
| 		os.Stdout.Sync() | ||||
| 		tmpFile.Close() | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func fsRemove(c *cli.Context) error { | ||||
| 	if c.Args().Len() < 1 { | ||||
| 		return cli.Exit("Command remove requires one or more arguments", 1) | ||||
| 	} | ||||
|  | ||||
| 	err := client.Remove(c.Args().Slice()...) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func fsWrite(c *cli.Context) error { | ||||
| 	if c.Args().Len() != 2 { | ||||
| 		return cli.Exit("Command write requires two arguments", 1) | ||||
| 	} | ||||
|  | ||||
| 	var tmpFile *os.File | ||||
| 	var path string | ||||
| 	var err error | ||||
| 	if c.Args().Get(0) == "-" { | ||||
| 		tmpFile, err = ioutil.TempFile("/tmp", "itctl.*") | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		path = tmpFile.Name() | ||||
| 	} else { | ||||
| 		path, err = filepath.Abs(c.Args().Get(0)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if c.Args().Get(0) == "-" { | ||||
| 		io.Copy(tmpFile, os.Stdin) | ||||
| 		defer tmpFile.Close() | ||||
| 		defer os.Remove(path) | ||||
| 	} | ||||
|  | ||||
| 	progress, err := client.WriteFile(path, c.Args().Get(1)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Create progress bar template | ||||
| 	barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}` | ||||
| 	// Start full bar at 0 total | ||||
| 	bar := pb.ProgressBarTemplate(barTmpl).Start(0) | ||||
| 	// Get progress events | ||||
| 	for event := range progress { | ||||
| 		// Set total bytes in progress bar | ||||
| 		bar.SetTotal(int64(event.Total)) | ||||
| 		// Set amount of bytes sent in progress bar | ||||
| 		bar.SetCurrent(int64(event.Sent)) | ||||
| 		// If transfer finished, break | ||||
| 		if event.Done { | ||||
| 			bar.Finish() | ||||
| 			break | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										71
									
								
								cmd/itctl/get.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								cmd/itctl/get.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
|  | ||||
| func getAddress(c *cli.Context) error { | ||||
| 	address, err := client.Address() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	fmt.Println(address) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getBattery(c *cli.Context) error { | ||||
| 	battLevel, err := client.BatteryLevel() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Print returned percentage | ||||
| 	fmt.Printf("%d%%\n", battLevel) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getHeart(c *cli.Context) error { | ||||
| 	heartRate, err := client.HeartRate() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Print returned BPM | ||||
| 	fmt.Printf("%d BPM\n", heartRate) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getMotion(c *cli.Context) error { | ||||
| 	motionVals, err := client.Motion() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if c.Bool("shell") { | ||||
| 		fmt.Printf( | ||||
| 			"X=%d\nY=%d\nZ=%d\n", | ||||
| 			motionVals.X, | ||||
| 			motionVals.Y, | ||||
| 			motionVals.Z, | ||||
| 		) | ||||
| 	} else { | ||||
| 		return json.NewEncoder(os.Stdout).Encode(motionVals) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getSteps(c *cli.Context) error { | ||||
| 	stepCount, err := client.StepCount() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	// Print returned BPM | ||||
| 	fmt.Printf("%d Steps\n", stepCount) | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package get | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // addressCmd represents the address command | ||||
| var addressCmd = &cobra.Command{ | ||||
| 	Use:     "address", | ||||
| 	Aliases: []string{"addr"}, | ||||
| 	Short:   "Get InfiniTime's bluetooth address", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
| 		 | ||||
| 		address, err := client.Address() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting bluetooth address") | ||||
| 		} | ||||
|  | ||||
| 		fmt.Println(address) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	getCmd.AddCommand(addressCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// addressCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||||
| } | ||||
| @@ -1,50 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package get | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // batteryCmd represents the batt command | ||||
| var batteryCmd = &cobra.Command{ | ||||
| 	Use:     "battery", | ||||
| 	Aliases: []string{"batt"}, | ||||
| 	Short:   "Get battery level from InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		battLevel, err := client.BatteryLevel() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting battery level") | ||||
| 		} | ||||
|  | ||||
| 		// Print returned percentage | ||||
| 		fmt.Printf("%d%%\n", battLevel) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	getCmd.AddCommand(batteryCmd) | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package get | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // getCmd represents the get command | ||||
| var getCmd = &cobra.Command{ | ||||
| 	Use:   "get", | ||||
| 	Short: "Get information from InfiniTime", | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(getCmd) | ||||
| } | ||||
| @@ -1,49 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package get | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // heartCmd represents the heart command | ||||
| var heartCmd = &cobra.Command{ | ||||
| 	Use:   "heart", | ||||
| 	Short: "Get heart rate from InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		heartRate, err := client.HeartRate() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting heart rate") | ||||
| 		} | ||||
|  | ||||
| 		// Print returned BPM | ||||
| 		fmt.Printf("%d BPM\n", heartRate) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	getCmd.AddCommand(heartCmd) | ||||
| } | ||||
| @@ -1,68 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package get | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // steps.goCmd represents the steps.go command | ||||
| var motionCmd = &cobra.Command{ | ||||
| 	Use:   "motion", | ||||
| 	Short: "Get motion values from InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		motionVals, err := client.Motion() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting motion values") | ||||
| 		} | ||||
|  | ||||
| 		if viper.GetBool("shell") { | ||||
| 			fmt.Printf( | ||||
| 				"X=%d\nY=%d\nZ=%d", | ||||
| 				motionVals.X, | ||||
| 				motionVals.Y, | ||||
| 				motionVals.Z, | ||||
| 			) | ||||
| 		} else { | ||||
| 			fmt.Printf("%+v\n", motionVals) | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	getCmd.AddCommand(motionCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// steps.goCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	motionCmd.Flags().BoolP("shell", "s", false, "Output data in shell-compatible format") | ||||
| 	viper.BindPFlag("shell", motionCmd.Flags().Lookup("shell")) | ||||
| } | ||||
| @@ -1,59 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package get | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // steps.goCmd represents the steps.go command | ||||
| var stepsCmd = &cobra.Command{ | ||||
| 	Use:   "steps", | ||||
| 	Short: "Get step count from InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		stepCount, err := client.StepCount() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting step count") | ||||
| 		} | ||||
|  | ||||
| 		// Print returned BPM | ||||
| 		fmt.Printf("%d Steps\n", stepCount) | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	getCmd.AddCommand(stepsCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// steps.goCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	// steps.goCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||||
| } | ||||
| @@ -1,43 +1,202 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/firmware" | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/get" | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/notify" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/set" | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/watch" | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/filesystem" | ||||
| 	_ "go.arsenm.dev/itd/cmd/itctl/update" | ||||
|  | ||||
| 	"os" | ||||
|  | ||||
| 	"github.com/rs/zerolog" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/urfave/cli/v2" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) | ||||
| } | ||||
| var client *api.Client | ||||
|  | ||||
| func main() { | ||||
| 	root.Execute() | ||||
| 	log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr}) | ||||
|  | ||||
| 	app := cli.App{ | ||||
| 		Name: "itctl", | ||||
| 		Flags: []cli.Flag{ | ||||
| 			&cli.StringFlag{ | ||||
| 				Name:    "socket-path", | ||||
| 				Aliases: []string{"s"}, | ||||
| 				Value:   api.DefaultAddr, | ||||
| 				Usage:   "Path to itd socket", | ||||
| 			}, | ||||
| 		}, | ||||
| 		Commands: []*cli.Command{ | ||||
| 			{ | ||||
| 				Name:    "filesystem", | ||||
| 				Aliases: []string{"fs"}, | ||||
| 				Usage:   "Perform filesystem operations on the PineTime", | ||||
| 				Subcommands: []*cli.Command{ | ||||
| 					{ | ||||
| 						Name:      "list", | ||||
| 						ArgsUsage: "[dir]", | ||||
| 						Aliases:   []string{"ls"}, | ||||
| 						Usage:     "List a directory", | ||||
| 						Action:    fsList, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:      "mkdir", | ||||
| 						ArgsUsage: "<paths...>", | ||||
| 						Usage:     "Create new directories", | ||||
| 						Action:    fsMkdir, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:      "move", | ||||
| 						ArgsUsage: "<old> <new>", | ||||
| 						Aliases:   []string{"mv"}, | ||||
| 						Usage:     "Move a file or directory", | ||||
| 						Action:    fsMove, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "read", | ||||
| 						ArgsUsage:   `<remote path> <local path>`, | ||||
| 						Usage:       "Read a file from InfiniTime.", | ||||
| 						Description: `Read is used to read files from InfiniTime's filesystem. A "-" can be used to signify stdout`, | ||||
| 						Action:      fsRead, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:      "remove", | ||||
| 						ArgsUsage: "<paths...>", | ||||
| 						Aliases:   []string{"rm"}, | ||||
| 						Usage:     "Create a new directory", | ||||
| 						Action:    fsRemove, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:        "write", | ||||
| 						ArgsUsage:   `<local path> <remote path>`, | ||||
| 						Usage:       "Write a file to InfiniTime", | ||||
| 						Description: `Write is used to write files to InfiniTime's filesystem. A "-" can be used to signify stdin`, | ||||
| 						Action:      fsWrite, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:    "firmware", | ||||
| 				Aliases: []string{"fw"}, | ||||
| 				Usage:   "Manage InfiniTime firmware", | ||||
| 				Subcommands: []*cli.Command{ | ||||
| 					{ | ||||
| 						Flags: []cli.Flag{ | ||||
| 							&cli.PathFlag{ | ||||
| 								Name:    "init-packet", | ||||
| 								Aliases: []string{"i"}, | ||||
| 								Usage:   "Path to init packet (.dat file)", | ||||
| 							}, | ||||
| 							&cli.PathFlag{ | ||||
| 								Name:    "firmware", | ||||
| 								Aliases: []string{"f"}, | ||||
| 								Usage:   "Path to firmware image (.bin file)", | ||||
| 							}, | ||||
| 							&cli.PathFlag{ | ||||
| 								Name:    "archive", | ||||
| 								Aliases: []string{"a"}, | ||||
| 								Usage:   "Path to firmware archive (.zip file)", | ||||
| 							}, | ||||
| 						}, | ||||
| 						Name:    "upgrade", | ||||
| 						Aliases: []string{"upg"}, | ||||
| 						Usage:   "Upgrade InfiniTime firmware using files or archive", | ||||
| 						Action:  fwUpgrade, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:    "version", | ||||
| 						Aliases: []string{"ver"}, | ||||
| 						Usage:   "Get firmware version of InfiniTime", | ||||
| 						Action:  fwVersion, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:  "get", | ||||
| 				Usage: "Get information from InfiniTime", | ||||
| 				Subcommands: []*cli.Command{ | ||||
| 					{ | ||||
| 						Name:    "address", | ||||
| 						Aliases: []string{"addr"}, | ||||
| 						Usage:   "Get InfiniTime's bluetooth address", | ||||
| 						Action:  getAddress, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:    "battery", | ||||
| 						Aliases: []string{"batt"}, | ||||
| 						Usage:   "Get InfiniTime's battery percentage", | ||||
| 						Action:  getBattery, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:   "heart", | ||||
| 						Usage:  "Get heart rate from InfiniTime", | ||||
| 						Action: getHeart, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Flags: []cli.Flag{ | ||||
| 							&cli.BoolFlag{Name: "shell"}, | ||||
| 						}, | ||||
| 						Name:   "motion", | ||||
| 						Usage:  "Get motion values from InfiniTime", | ||||
| 						Action: getMotion, | ||||
| 					}, | ||||
| 					{ | ||||
| 						Name:   "steps", | ||||
| 						Usage:  "Get step count from InfiniTime", | ||||
| 						Action: getSteps, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:   "notify", | ||||
| 				Usage:  "Send notification to InfiniTime", | ||||
| 				Action: notify, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:  "set", | ||||
| 				Usage: "Set information on InfiniTime", | ||||
| 				Subcommands: []*cli.Command{ | ||||
| 					{ | ||||
| 						Name:      "time", | ||||
| 						ArgsUsage: `<ISO8601|"now">`, | ||||
| 						Usage:     "Set InfiniTime's clock to specified time", | ||||
| 						Action:    setTime, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 			{ | ||||
| 				Name:    "update", | ||||
| 				Usage:   "Update information on InfiniTime", | ||||
| 				Aliases: []string{"upd"}, | ||||
| 				Subcommands: []*cli.Command{ | ||||
| 					{ | ||||
| 						Name:   "weather", | ||||
| 						Usage:  "Force an immediate update of weather data", | ||||
| 						Action: updateWeather, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Before: func(c *cli.Context) error { | ||||
| 			newClient, err := api.New(c.String("socket-path")) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			client = newClient | ||||
| 			return nil | ||||
| 		}, | ||||
| 		After: func(*cli.Context) error { | ||||
| 			return client.Close() | ||||
| 		}, | ||||
| 		ExitErrHandler: func(c *cli.Context, err error) { | ||||
| 			cli.ShowCommandHelp(c, c.Command.Name) | ||||
| 			if err != nil { | ||||
| 				log.Fatal().Msgf("%v", err) | ||||
| 			} | ||||
| 			os.Exit(0) | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	err := app.Run(os.Args) | ||||
| 	if err != nil { | ||||
| 		log.Fatal().Err(err).Msg("Error while running app") | ||||
| 	} | ||||
| } | ||||
|   | ||||
							
								
								
									
										17
									
								
								cmd/itctl/notify.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								cmd/itctl/notify.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli/v2" | ||||
|  | ||||
| func notify(c *cli.Context) error { | ||||
| 	// Ensure required arguments | ||||
| 	if c.Args().Len() != 2 { | ||||
| 		return cli.Exit("Command notify requires two arguments", 1) | ||||
| 	} | ||||
|  | ||||
| 	err := client.Notify(c.Args().Get(0), c.Args().Get(1)) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @@ -1,51 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package notify | ||||
|  | ||||
| import ( | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // notifyCmd represents the notify command | ||||
| var notifyCmd = &cobra.Command{ | ||||
| 	Use:   "notify <title> <body>", | ||||
| 	Short: "Send notification to InfiniTime", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		// Ensure required arguments | ||||
| 		if len(args) != 2 { | ||||
| 			cmd.Usage() | ||||
| 			log.Fatal().Msg("Command notify requires two arguments") | ||||
| 		} | ||||
|  | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		err := client.Notify(args[0], args[1]) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error sending notification") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(notifyCmd) | ||||
| } | ||||
| @@ -1,87 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package root | ||||
|  | ||||
| import ( | ||||
| 	"github.com/abiosoft/ishell" | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // RootCmd represents the base command when called without any subcommands | ||||
| var RootCmd = &cobra.Command{ | ||||
| 	Use:   "itctl", | ||||
| 	Short: "Control the itd daemon for InfiniTime smartwatches", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
|  | ||||
| 		// Create new shell | ||||
| 		sh := ishell.New() | ||||
| 		sh.SetPrompt("itctl> ") | ||||
|  | ||||
| 		// For every command in cobra | ||||
| 		for _, subCmd := range cmd.Commands() { | ||||
| 			// Add top level command to ishell | ||||
| 			sh.AddCmd(&ishell.Cmd{ | ||||
| 				Name:     subCmd.Name(), | ||||
| 				Help:     subCmd.Short, | ||||
| 				Aliases:  subCmd.Aliases, | ||||
| 				LongHelp: subCmd.Long, | ||||
| 				Func: func(ctx *ishell.Context) { | ||||
| 					// Append name and arguments of command | ||||
| 					args := append([]string{ctx.Cmd.Name}, ctx.Args...) | ||||
| 					// Set root command arguments | ||||
| 					cmd.SetArgs(args) | ||||
| 					// Execute root command with new arguments | ||||
| 					cmd.Execute() | ||||
| 				}, | ||||
| 			}) | ||||
| 		} | ||||
|  | ||||
| 		// Start shell | ||||
| 		sh.Run() | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| // Execute adds all child commands to the root command and sets flags appropriately. | ||||
| // This is called by main.main(). It only needs to happen once to the rootCmd. | ||||
| func Execute() { | ||||
| 	client, err := api.New(viper.GetString("sockPath")) | ||||
| 	if err != nil { | ||||
| 		log.Fatal().Err(err).Msg("Error connecting to socket. Is itd running?") | ||||
| 	} | ||||
| 	defer client.Close() | ||||
| 	viper.Set("client", client) | ||||
| 	RootCmd.CompletionOptions.DisableDefaultCmd = true | ||||
| 	cobra.CheckErr(RootCmd.Execute()) | ||||
|  | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	// Register flag for socket path | ||||
| 	RootCmd.Flags().StringP("socket-path", "s", api.DefaultAddr, "Path to itd socket") | ||||
|  | ||||
| 	// Bind flag and environment variable to viper key | ||||
| 	viper.BindPFlag("sockPath", RootCmd.Flags().Lookup("socket-path")) | ||||
| 	viper.BindEnv("sockPath", "ITCTL_SOCKET_PATH") | ||||
|  | ||||
| 	// Set default value for socket path | ||||
| 	viper.SetDefault("sockPath", api.DefaultAddr) | ||||
| } | ||||
							
								
								
									
										24
									
								
								cmd/itctl/set.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								cmd/itctl/set.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/urfave/cli/v2" | ||||
| ) | ||||
|  | ||||
| func setTime(c *cli.Context) error { | ||||
| 	// Ensure required arguments | ||||
| 	if c.Args().Len() < 1 { | ||||
| 		return cli.Exit("Command time requires one argument", 1) | ||||
| 	} | ||||
|  | ||||
| 	if c.Args().Get(0) == "now" { | ||||
| 		return client.SetTimeNow() | ||||
| 	} else { | ||||
| 		parsed, err := time.Parse(time.RFC3339, c.Args().Get(0)) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		return client.SetTime(parsed) | ||||
| 	} | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package set | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // setCmd represents the set command | ||||
| var setCmd = &cobra.Command{ | ||||
| 	Use:   "set", | ||||
| 	Short: "Set information on InfiniTime", | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(setCmd) | ||||
| } | ||||
| @@ -1,81 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package set | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"encoding/json" | ||||
| 	"net" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/internal/types" | ||||
| ) | ||||
|  | ||||
| // timeCmd represents the time command | ||||
| var timeCmd = &cobra.Command{ | ||||
| 	Use:   `time <ISO8601|"now">`, | ||||
| 	Short: "Set InfiniTime's clock to specified time", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		// Ensure required arguments | ||||
| 		if len(args) != 1 { | ||||
| 			cmd.Usage() | ||||
| 			log.Warn().Msg("Command time requires one argument") | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Connect to itd UNIX socket | ||||
| 		conn, err := net.Dial("unix", viper.GetString("sockPath")) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error dialing socket. Is itd running?") | ||||
| 		} | ||||
| 		defer conn.Close() | ||||
|  | ||||
| 		// Encode request into connection | ||||
| 		err = json.NewEncoder(conn).Encode(types.Request{ | ||||
| 			Type: types.ReqTypeSetTime, | ||||
| 			Data: args[0], | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error making request") | ||||
| 		} | ||||
|  | ||||
| 		// Read one line from connetion | ||||
| 		line, _, err := bufio.NewReader(conn).ReadLine() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error reading line from connection") | ||||
| 		} | ||||
|  | ||||
| 		var res types.Response | ||||
| 		// Decode line into response | ||||
| 		err = json.Unmarshal(line, &res) | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error decoding JSON data") | ||||
| 		} | ||||
|  | ||||
| 		if res.Error { | ||||
| 			log.Fatal().Msg(res.Message) | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	setCmd.AddCommand(timeCmd) | ||||
| } | ||||
							
								
								
									
										7
									
								
								cmd/itctl/update.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								cmd/itctl/update.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| package main | ||||
|  | ||||
| import "github.com/urfave/cli/v2" | ||||
|  | ||||
| func updateWeather(c *cli.Context) error { | ||||
| 	return client.UpdateWeather() | ||||
| } | ||||
| @@ -1,44 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package update | ||||
|  | ||||
| import ( | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // weatherCmd represents the time command | ||||
| var weatherCmd = &cobra.Command{ | ||||
| 	Use:   `weather`, | ||||
| 	Short: "Force an immediate update of weather data", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		err := client.UpdateWeather() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error updating weather") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	updateCmd.AddCommand(weatherCmd) | ||||
| } | ||||
| @@ -1,35 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package update | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // updateCmd represents the update command | ||||
| var updateCmd = &cobra.Command{ | ||||
| 	Use:   "update", | ||||
| 	Short: "Update information on InfiniTime", | ||||
| 	Aliases: []string{"upd"}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(updateCmd) | ||||
| } | ||||
| @@ -1,76 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package watch | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // heartCmd represents the address command | ||||
| var batteryCmd = &cobra.Command{ | ||||
| 	Use:   "battery", | ||||
| 	Aliases: []string{"batt"}, | ||||
| 	Short: "Watch InfiniTime's battery level for changes", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		battLevelCh, cancel, err := client.WatchBatteryLevel() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting battery level channel") | ||||
| 		} | ||||
| 		defer cancel() | ||||
|  | ||||
| 		signalCh := make(chan os.Signal, 1) | ||||
| 		go func() { | ||||
| 			<-signalCh | ||||
| 			cancel() | ||||
| 			os.Exit(0) | ||||
| 		}() | ||||
| 		signal.Notify(signalCh, | ||||
| 			syscall.SIGINT, | ||||
| 			syscall.SIGTERM,			 | ||||
| 		) | ||||
|  | ||||
| 		for battlevel := range battLevelCh { | ||||
| 			fmt.Printf("%d%%\n", battlevel) | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	watchCmd.AddCommand(batteryCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// addressCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||||
| } | ||||
| @@ -1,75 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package watch | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // heartCmd represents the address command | ||||
| var heartCmd = &cobra.Command{ | ||||
| 	Use:   "heart", | ||||
| 	Short: "Watch InfiniTime's heart rate for changes", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		heartRateCh, cancel, err := client.WatchHeartRate() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting heart rate channel") | ||||
| 		} | ||||
| 		defer cancel() | ||||
|  | ||||
| 		signalCh := make(chan os.Signal, 1) | ||||
| 		go func() { | ||||
| 			<-signalCh | ||||
| 			cancel() | ||||
| 			os.Exit(0) | ||||
| 		}() | ||||
| 		signal.Notify(signalCh, | ||||
| 			syscall.SIGINT, | ||||
| 			syscall.SIGTERM,			 | ||||
| 		) | ||||
|  | ||||
| 		for heartRate := range heartRateCh { | ||||
| 			fmt.Println(heartRate, "BPM") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	watchCmd.AddCommand(heartCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// addressCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||||
| } | ||||
| @@ -1,86 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package watch | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // heartCmd represents the address command | ||||
| var motionCmd = &cobra.Command{ | ||||
| 	Use:   "motion", | ||||
| 	Short: "Watch InfiniTime's motion values for changes", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		motionValCh, cancel, err := client.WatchMotion() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting motion value channel") | ||||
| 		} | ||||
| 		defer cancel() | ||||
|  | ||||
| 		signalCh := make(chan os.Signal, 1) | ||||
| 		go func() { | ||||
| 			<-signalCh | ||||
| 			cancel() | ||||
| 			os.Exit(0) | ||||
| 		}() | ||||
| 		signal.Notify(signalCh, | ||||
| 			syscall.SIGINT, | ||||
| 			syscall.SIGTERM, | ||||
| 		) | ||||
|  | ||||
| 		for motionVals := range motionValCh { | ||||
| 			if viper.GetBool("shell") { | ||||
| 				fmt.Printf( | ||||
| 					"X=%d\nY=%d\nZ=%d\n", | ||||
| 					motionVals.X, | ||||
| 					motionVals.Y, | ||||
| 					motionVals.Z, | ||||
| 				) | ||||
| 			} else { | ||||
| 				fmt.Printf("%+v\n", motionVals) | ||||
| 			} | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	watchCmd.AddCommand(motionCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// addressCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||||
| 	motionCmd.Flags().BoolP("shell", "s", false, "Output data in shell-compatible format") | ||||
| 	viper.BindPFlag("shell", motionCmd.Flags().Lookup("shell")) | ||||
| } | ||||
| @@ -1,75 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package watch | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"os/signal" | ||||
| 	"syscall" | ||||
|  | ||||
| 	"github.com/rs/zerolog/log" | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"github.com/spf13/viper" | ||||
| 	"go.arsenm.dev/itd/api" | ||||
| ) | ||||
|  | ||||
| // heartCmd represents the address command | ||||
| var stepsCmd = &cobra.Command{ | ||||
| 	Use:   "steps", | ||||
| 	Short: "Watch InfiniTime's step count for changes", | ||||
| 	Run: func(cmd *cobra.Command, args []string) { | ||||
| 		client := viper.Get("client").(*api.Client) | ||||
|  | ||||
| 		stepCountCh, cancel, err := client.WatchStepCount() | ||||
| 		if err != nil { | ||||
| 			log.Fatal().Err(err).Msg("Error getting step count channel") | ||||
| 		} | ||||
| 		defer cancel() | ||||
|  | ||||
| 		signalCh := make(chan os.Signal, 1) | ||||
| 		go func() { | ||||
| 			<-signalCh | ||||
| 			cancel() | ||||
| 			os.Exit(0) | ||||
| 		}() | ||||
| 		signal.Notify(signalCh, | ||||
| 			syscall.SIGINT, | ||||
| 			syscall.SIGTERM,			 | ||||
| 		) | ||||
|  | ||||
| 		for stepCount := range stepCountCh { | ||||
| 			fmt.Println(stepCount, "Steps") | ||||
| 		} | ||||
| 	}, | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	watchCmd.AddCommand(stepsCmd) | ||||
|  | ||||
| 	// Here you will define your flags and configuration settings. | ||||
|  | ||||
| 	// Cobra supports Persistent Flags which will work for this command | ||||
| 	// and all subcommands, e.g.: | ||||
| 	// addressCmd.PersistentFlags().String("foo", "", "A help for foo") | ||||
|  | ||||
| 	// Cobra supports local flags which will only run when this command | ||||
| 	// is called directly, e.g.: | ||||
| 	// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle") | ||||
| } | ||||
| @@ -1,34 +0,0 @@ | ||||
| /* | ||||
|  *	itd uses bluetooth low energy to communicate with InfiniTime devices | ||||
|  *	Copyright (C) 2021 Arsen Musayelyan | ||||
|  * | ||||
|  *	This program is free software: you can redistribute it and/or modify | ||||
|  *	it under the terms of the GNU General Public License as published by | ||||
|  *	the Free Software Foundation, either version 3 of the License, or | ||||
|  *	(at your option) any later version. | ||||
|  * | ||||
|  *	This program is distributed in the hope that it will be useful, | ||||
|  *	but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  *	GNU General Public License for more details. | ||||
|  * | ||||
|  *	You should have received a copy of the GNU General Public License | ||||
|  *	along with this program.  If not, see <http://www.gnu.org/licenses/>. | ||||
|  */ | ||||
|  | ||||
| package watch | ||||
|  | ||||
| import ( | ||||
| 	"github.com/spf13/cobra" | ||||
| 	"go.arsenm.dev/itd/cmd/itctl/root" | ||||
| ) | ||||
|  | ||||
| // watchCmd represents the watch command | ||||
| var watchCmd = &cobra.Command{ | ||||
| 	Use:   "watch", | ||||
| 	Short: "Watch values from InfiniTime for changes", | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	root.RootCmd.AddCommand(watchCmd) | ||||
| } | ||||
		Reference in New Issue
	
	Block a user