main.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. // License: GPLv3 Copyright: 2022, Kovid Goyal, <kovid at kovidgoyal.net>
  2. package update_self
  3. import (
  4. "fmt"
  5. "os"
  6. "path/filepath"
  7. "runtime"
  8. "kitty"
  9. "kitty/tools/cli"
  10. "kitty/tools/tty"
  11. "kitty/tools/tui"
  12. "kitty/tools/utils"
  13. "golang.org/x/sys/unix"
  14. )
  15. var _ = fmt.Print
  16. type Options struct {
  17. FetchVersion string
  18. }
  19. func update_self(version string) (err error) {
  20. exe := ""
  21. exe, err = os.Executable()
  22. if err != nil {
  23. return fmt.Errorf("Failed to determine path to kitten: %w", err)
  24. }
  25. exe, err = filepath.EvalSymlinks(exe)
  26. if err != nil {
  27. return err
  28. }
  29. if kitty.IsStandaloneBuild == "" {
  30. return fmt.Errorf("This is not a standalone kitten executable. You must update all of kitty instead.")
  31. }
  32. rv := "v" + version
  33. if version == "nightly" {
  34. rv = version
  35. }
  36. url_base := fmt.Sprintf("https://github.com/kovidgoyal/kitty/releases/download/%s", rv)
  37. if version == "latest" {
  38. url_base = "https://github.com/kovidgoyal/kitty/releases/latest/download"
  39. }
  40. url := fmt.Sprintf("%s/kitten-%s-%s", url_base, runtime.GOOS, runtime.GOARCH)
  41. dest, err := os.CreateTemp(filepath.Dir(exe), "kitten.")
  42. if err != nil {
  43. return err
  44. }
  45. defer func() { os.Remove(dest.Name()) }()
  46. if !tty.IsTerminal(os.Stdout.Fd()) {
  47. fmt.Println("Downloading:", url)
  48. err = utils.DownloadToFile(exe, url, nil, nil)
  49. if err != nil {
  50. return err
  51. }
  52. fmt.Println("Downloaded to:", exe)
  53. } else {
  54. err = tui.DownloadFileWithProgress(exe, url, true)
  55. if err != nil {
  56. return err
  57. }
  58. }
  59. fmt.Print("Updated to: ")
  60. return unix.Exec(exe, []string{"kitten", "--version"}, os.Environ())
  61. }
  62. func EntryPoint(root *cli.Command) *cli.Command {
  63. sc := root.AddSubCommand(&cli.Command{
  64. Name: "update-self",
  65. Usage: "[options]",
  66. ShortDescription: "Update this kitten binary",
  67. HelpText: "Update this kitten binary in place to the latest available version.",
  68. Run: func(cmd *cli.Command, args []string) (ret int, err error) {
  69. if len(args) != 0 {
  70. return 1, fmt.Errorf("No command line arguments are allowed")
  71. }
  72. opts := &Options{}
  73. err = cmd.GetOptionValues(opts)
  74. if err != nil {
  75. return 1, err
  76. }
  77. return 0, update_self(opts.FetchVersion)
  78. },
  79. })
  80. sc.Add(cli.OptionSpec{
  81. Name: "--fetch-version",
  82. Default: "latest",
  83. Help: fmt.Sprintf("The version to fetch. The special words :code:`latest` and :code:`nightly` fetch the latest stable and nightly release respectively. Other values can be, for example: :code:`%s`.", kitty.VersionString),
  84. })
  85. return sc
  86. }