Skip to content

Commit 16d0543

Browse files
authored
Add Info Command (#19)
1 parent 3f999ed commit 16d0543

13 files changed

Lines changed: 220 additions & 106 deletions

File tree

assets/banner.tape

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,7 @@ Sleep 0.3s
2828
Enter
2929

3030
Source assets/main.tape
31+
32+
Type "clear"
33+
Sleep 0.3s
34+
Enter

assets/demo.tape

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,12 @@ Env TERM "xterm-256color"
1818
Env COLORTERM "truecolor"
1919

2020
Source assets/main.tape
21+
22+
Type "ir info smashedr/bup -s"
23+
Sleep 0.5s
24+
Enter
25+
Sleep 3s
26+
27+
Type "clear"
28+
Sleep 0.3s
29+
Enter

assets/main.tape

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,3 @@ Left
5656
Sleep 0.4s
5757
Enter
5858
Sleep 1.5s
59-
60-
Type "clear"
61-
Sleep 0.3s
62-
Enter

cmd/info.go

Lines changed: 77 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,107 @@
11
package cmd
22

33
import (
4+
"fmt"
5+
"github.com/charmbracelet/glamour"
46
"github.com/charmbracelet/log"
7+
"github.com/dustin/go-humanize"
58
"github.com/smashedr/install-release/internal/pathmgr"
69
"github.com/smashedr/install-release/internal/styles"
710
"github.com/spf13/cobra"
811
"github.com/spf13/viper"
912
"os"
10-
"path/filepath"
13+
"strconv"
14+
"strings"
1115
)
1216

1317
var infoCmd = &cobra.Command{
14-
Use: "info",
18+
Use: "info [owner/repo]",
1519
Aliases: []string{"i", "in", "inf"},
16-
Short: "Show application information",
17-
Long: "Show application information.",
20+
Short: "Show app or package information",
21+
Long: "Show app or package information.",
1822
Run: func(cmd *cobra.Command, args []string) {
1923
binPath := viper.GetString("bin")
20-
log.Debug("infoCmd:", "args", args, "binPath", binPath)
24+
sumFlag, _ := cmd.Flags().GetBool("summary")
25+
log.Debug("infoCmd:", "args", args, "binPath", binPath, "sumFlag", sumFlag)
2126

22-
pathmgr.CheckBinPath(binPath)
27+
//// Enable Console on Windows (rendering a table does this)
28+
//if runtime.GOOS == "windows" {
29+
// kernel32 := syscall.NewLazyDLL("kernel32.dll")
30+
// setConsoleMode := kernel32.NewProc("SetConsoleMode")
31+
// handle, _ := syscall.GetStdHandle(syscall.STD_OUTPUT_HANDLE)
32+
// _, _, _ = setConsoleMode.Call(uintptr(handle), 0x0001|0x0002|0x0004)
33+
//}
2334

24-
exPath := "Unknown"
25-
ex, err := os.Executable()
35+
if len(args) >= 1 && strings.Contains(args[0], "/") {
36+
owner, repo, err := parseRepository(args[0])
37+
if err != nil {
38+
_ = cmd.Help()
39+
log.Fatal(err)
40+
}
41+
log.Info("Repository", "owner", owner, "repo", repo)
42+
client := getClient()
43+
release, err := getRelease(client, owner, repo, "")
44+
if err != nil {
45+
log.Fatalf("Error getting release: %v", err)
46+
}
47+
if verbose >= 3 {
48+
log.Debugf("%v", release)
49+
}
50+
51+
releaseTime := release.GetCreatedAt().Time // Timestamp → time.Time
52+
formattedDate := releaseTime.Format("15:04 on 2 Jan 2006")
53+
54+
rows := [][]string{
55+
{"Tag", release.GetTagName()},
56+
{"Name", release.GetName()},
57+
{"Date", formattedDate},
58+
{"Time", humanize.Time(releaseTime)},
59+
{"Author", release.GetAuthor().GetLogin()},
60+
{"Assets", strconv.Itoa(len(release.Assets))},
61+
}
62+
styles.RenderTable(rows, "Info", "Details")
63+
if sumFlag {
64+
return
65+
}
66+
67+
//width, height, err := term.GetSize(os.Stdout.Fd())
68+
//if err != nil {
69+
// log.Warn(err)
70+
// width = 80
71+
//}
72+
//log.Info("GetSize:", "width", width, "height", height)
73+
74+
// Add Pager
75+
result := headString(release.GetBody(), 12)
76+
77+
out, err := glamour.Render(result, "dracula")
78+
if err != nil {
79+
log.Fatalf("Error rendering release notes: %v", err)
80+
}
81+
fmt.Print(strings.TrimLeft(out, "\n"))
82+
83+
styles.PrintKV("Release URL:", release.GetHTMLURL())
84+
return
85+
}
86+
87+
pathmgr.CheckBinPath(binPath) // WIP
88+
89+
executable, err := os.Executable()
2690
if err != nil {
2791
log.Warn(err)
28-
} else {
29-
exPath = filepath.Dir(ex)
3092
}
3193

32-
styles.PrintKV("Executable:", exPath)
94+
styles.PrintKV("Executable:", executable)
3395
styles.PrintKV("Config Used:", viper.ConfigFileUsed())
3496
styles.PrintKV("Bin Path:", binPath)
3597

98+
fmt.Printf("To get package info, run:\n")
99+
fmt.Println(styles.Command.Render("ir info owner/repo"))
100+
36101
},
37102
}
38103

39104
func init() {
40105
rootCmd.AddCommand(infoCmd)
106+
infoCmd.Flags().BoolP("summary", "s", false, "only show summary")
41107
}

cmd/install.go

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -44,51 +44,30 @@ func runInstall(cmd *cobra.Command, args []string) error { // NOSONAR
4444
return fmt.Errorf("repository must be in format: owner/repo")
4545
}
4646

47-
repository := args[0]
48-
log.Infof("repository: %v", repository)
49-
if !strings.Contains(repository, "/") {
50-
return fmt.Errorf("repository must be in format: owner/repo")
47+
owner, repo, err := parseRepository(args[0])
48+
if err != nil {
49+
_ = cmd.Help()
50+
log.Fatal(err)
5151
}
5252

53-
parts := strings.Split(repository, "/")
54-
owner := parts[0]
55-
repo := parts[1]
56-
5753
tag := "latest"
5854
if len(args) > 1 {
5955
tag = args[1]
6056
}
61-
//fmt.Printf("Processing: %s/%s:%s\n", owner, repo, tag)
62-
styles.PrintKV("Repository:", fmt.Sprintf("%s/%s:%s", owner, repo, tag))
6357

64-
log.Info("GOOS", "runtime.GOOS", runtime.GOOS)
65-
log.Info("GOARCH", "runtime.GOARCH", runtime.GOARCH)
58+
log.Info("runtime", "GOOS", runtime.GOOS, "GOARCH", runtime.GOARCH)
59+
styles.PrintKV("Repository:", fmt.Sprintf("%s/%s:%s", owner, repo, tag))
6660

67-
// Cache
68-
dsn := "fscache://?appname=install-release&maxsize=10485760"
69-
httpClient := &http.Client{
70-
Transport: httpcache.NewTransport(dsn, httpcache.WithSWRTimeout(10*time.Second)),
71-
}
72-
// Client
73-
client := github.NewClient(httpClient)
61+
client := getClient()
7462

75-
// Release
76-
ctx := context.Background()
77-
var release *github.RepositoryRelease
78-
if tag == "latest" {
79-
release, _, err = client.Repositories.GetLatestRelease(ctx, owner, repo)
80-
} else {
81-
release, _, err = client.Repositories.GetReleaseByTag(ctx, owner, repo, tag)
82-
}
83-
//release, err := getRelease(client, owner, repo, tag)
63+
release, err := getRelease(client, owner, repo, tag)
8464
if err != nil {
8565
return fmt.Errorf("get release error: %w", err)
8666
}
8767
if verbose >= 3 {
8868
log.Debugf("release: %v", release)
8969
}
9070

91-
//fmt.Printf("Installing Version: %s\n", release.GetTagName())
9271
styles.PrintKV("Version:", release.GetTagName())
9372

9473
// Asset
@@ -127,12 +106,11 @@ func runInstall(cmd *cobra.Command, args []string) error { // NOSONAR
127106
}
128107

129108
log.Infof("id: %v", asset.GetID())
130-
//fmt.Printf("url: %s\n", asset.GetBrowserDownloadURL())
131109
log.Infof("url: %v", asset.GetBrowserDownloadURL())
132110
styles.PrintKV("Asset Name:", asset.GetName())
133111

134112
rc, _, err := client.Repositories.DownloadReleaseAsset(
135-
ctx, owner, repo, asset.GetID(), http.DefaultClient,
113+
context.Background(), owner, repo, asset.GetID(), http.DefaultClient,
136114
)
137115
if err != nil {
138116
return err
@@ -258,10 +236,8 @@ func runInstall(cmd *cobra.Command, args []string) error { // NOSONAR
258236
}
259237
}
260238

261-
// WIP
262-
pathmgr.CheckBinPath(binPath)
239+
pathmgr.CheckBinPath(binPath) // WIP
263240

264-
//fmt.Printf("\nSuccessfully Installed: %s\n", destName)
265241
styles.PrintKV("Installed:", destName)
266242
return nil
267243
}
@@ -395,17 +371,25 @@ func findMatch(assets []*github.ReleaseAsset, os string, aliases []string) int {
395371
return -1
396372
}
397373

398-
//func getRelease(client *github.Client, owner, repo, tag string) (*github.RepositoryRelease, error) {
399-
// ctx := context.Background()
400-
// var release *github.RepositoryRelease
401-
// var err error
402-
// if tag == "latest" {
403-
// release, _, err = client.Repositories.GetLatestRelease(ctx, owner, repo)
404-
// } else {
405-
// release, _, err = client.Repositories.GetReleaseByTag(ctx, owner, repo, tag)
406-
// }
407-
// if err != nil {
408-
// return nil, fmt.Errorf("get release error: %w", err)
409-
// }
410-
// return release, nil
411-
//}
374+
func getClient() *github.Client {
375+
dsn := "fscache://?appname=install-release&maxsize=10485760"
376+
httpClient := &http.Client{
377+
Transport: httpcache.NewTransport(dsn, httpcache.WithSWRTimeout(10*time.Second)),
378+
}
379+
return github.NewClient(httpClient)
380+
}
381+
382+
func getRelease(client *github.Client, owner, repo, tag string) (*github.RepositoryRelease, error) {
383+
ctx := context.Background()
384+
var release *github.RepositoryRelease
385+
var err error
386+
if tag == "" || tag == "latest" {
387+
release, _, err = client.Repositories.GetLatestRelease(ctx, owner, repo)
388+
} else {
389+
release, _, err = client.Repositories.GetReleaseByTag(ctx, owner, repo, tag)
390+
}
391+
if err != nil {
392+
return nil, fmt.Errorf("get release error: %w", err)
393+
}
394+
return release, nil
395+
}

cmd/list.go

Lines changed: 3 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package cmd
22

33
import (
4-
"fmt"
5-
"github.com/charmbracelet/lipgloss"
6-
"github.com/charmbracelet/lipgloss/table"
74
"github.com/charmbracelet/log"
5+
"github.com/dustin/go-humanize"
86
"github.com/smashedr/install-release/internal/styles"
97
"github.com/spf13/cobra"
108
"github.com/spf13/viper"
@@ -50,42 +48,13 @@ var listCmd = &cobra.Command{
5048
log.Warn(err)
5149
continue
5250
}
53-
rows = append(rows, []string{e.Name(), formatBytes(info.Size())})
51+
rows = append(rows, []string{e.Name(), humanize.Bytes(uint64(info.Size()))})
5452
}
5553
log.Debugf("rows: %v", rows)
56-
renderTable(rows, "Name", "Size")
57-
54+
styles.RenderTable(rows, "Name", "Size")
5855
},
5956
}
6057

61-
func renderTable(rows [][]string, headers ...string) {
62-
t := table.New().
63-
Border(lipgloss.RoundedBorder()).
64-
BorderStyle(styles.TableBorder).
65-
StyleFunc(func(row, col int) lipgloss.Style {
66-
if row == table.HeaderRow {
67-
return styles.TableHeader
68-
}
69-
return styles.TableRow
70-
}).
71-
Headers(headers...).
72-
Rows(rows...)
73-
fmt.Println(t)
74-
}
75-
76-
func formatBytes(bytes int64) string {
77-
const unit = 1024
78-
if bytes < unit {
79-
return fmt.Sprintf("%d B", bytes)
80-
}
81-
div, exp := int64(unit), 0
82-
for n := bytes / unit; n >= unit; n /= unit {
83-
div *= unit
84-
exp++
85-
}
86-
return fmt.Sprintf("%.1f %cB", float64(bytes)/float64(div), "KMGTPE"[exp])
87-
}
88-
8958
//func listDir(path string) {
9059
// entries, err := os.ReadDir(path)
9160
// log.Infof("entries: %v", entries)

cmd/remove.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ var removeCmd = &cobra.Command{
2222
log.Debug("removeCmd:", "args", args, "binPath", binPath)
2323
//noConfirm, _ := cmd.Flags().GetBool("yes")
2424
//log.Debug("Flags", "noConfirm", noConfirm)
25-
2625
if len(args) == 0 {
2726
_ = cmd.Help()
2827
return

cmd/test.go

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ var testCmd = &cobra.Command{
2424

2525
log.Warnf("This is only a test and does nothing...")
2626

27-
pathmgr.CheckBinPath(binPath)
27+
pathmgr.CheckBinPath(binPath) // WIP
2828

2929
homeDir, err := os.UserHomeDir()
3030
if err != nil {
@@ -109,16 +109,13 @@ func promptPath() string {
109109
}
110110

111111
func getHomePaths(homeDir string) []string {
112-
113112
relativePaths := []string{
114113
"bin",
115114
".local/bin",
116115
}
117-
118116
absolutePaths := make([]string, len(relativePaths))
119117
for i, relPath := range relativePaths {
120118
absolutePaths[i] = filepath.Join(homeDir, relPath)
121119
}
122-
123120
return absolutePaths
124121
}

cmd/utils.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package cmd
2+
3+
import (
4+
"fmt"
5+
"regexp"
6+
"strings"
7+
)
8+
9+
func parseRepository(repository string) (owner, repo string, err error) {
10+
var repoPattern = regexp.MustCompile(`^[a-zA-Z0-9_.-]+/[a-zA-Z0-9_.-]+$`)
11+
12+
if !repoPattern.MatchString(repository) {
13+
return "", "", fmt.Errorf("repository must be in format: owner/repo")
14+
}
15+
split := strings.Split(repository, "/")
16+
return split[0], split[1], nil
17+
}
18+
19+
func headString(text string, length int) string {
20+
lines := strings.SplitN(strings.TrimSpace(text), "\n", length+1)
21+
if len(lines) > length {
22+
lines = lines[:length]
23+
}
24+
return strings.Join(lines, "\n")
25+
}

0 commit comments

Comments
 (0)