@@ -3,19 +3,129 @@ package main
33import (
44 "fmt"
55 "os"
6+ "strconv"
7+ "strings"
8+ "time"
69
10+ "github.com/coder/pretty"
711 "github.com/coder/serpent"
12+ "github.com/coder/wush/cliui"
13+ "github.com/mitchellh/go-wordwrap"
814)
915
1016func main () {
11- cmd := sshCmd ()
12- cmd .Children = []* serpent.Command {
13- receiveCmd (),
14- rsyncCmd (),
17+ var (
18+ showVersion bool
19+
20+ fmtLong = "wush %s - peer-to-peer file transfers and shells\n "
21+ )
22+ cmd := & serpent.Command {
23+ Use : "wush <subcommand>" ,
24+ Long : fmt .Sprintf (fmtLong , getBuildInfo ().version ) + formatExamples (
25+ example {
26+ Description : "Start the wush server" ,
27+ Command : "wush receive" ,
28+ },
29+ example {
30+ Description : "Open a shell to the wush host" ,
31+ Command : "wush ssh" ,
32+ },
33+ example {
34+ Description : "Transfer files to the wush host using rsync" ,
35+ Command : "wush rsync local-file.txt :/path/to/remote/file" ,
36+ },
37+ ),
38+ Handler : func (i * serpent.Invocation ) error {
39+ if showVersion {
40+ return versionCmd ().Handler (i )
41+ }
42+ return serpent .DefaultHelpFn ()(i )
43+ },
44+ Children : []* serpent.Command {
45+ versionCmd (),
46+ sshCmd (),
47+ receiveCmd (),
48+ rsyncCmd (),
49+ },
50+ Options : []serpent.Option {
51+ {
52+ Flag : "version" ,
53+ Description : "Print the version and exit." ,
54+ Value : serpent .BoolOf (& showVersion ),
55+ },
56+ },
1557 }
58+
1659 err := cmd .Invoke ().WithOS ().Run ()
1760 if err != nil {
1861 fmt .Fprintf (os .Stderr , "error: %v\n " , err )
1962 os .Exit (1 )
2063 }
2164}
65+
66+ // example represents a standard example for command usage, to be used
67+ // with formatExamples.
68+ type example struct {
69+ Description string
70+ Command string
71+ }
72+
73+ // formatExamples formats the examples as width wrapped bulletpoint
74+ // descriptions with the command underneath.
75+ func formatExamples (examples ... example ) string {
76+ var sb strings.Builder
77+
78+ padStyle := cliui .DefaultStyles .Wrap .With (pretty .XPad (4 , 0 ))
79+ for i , e := range examples {
80+ if len (e .Description ) > 0 {
81+ wordwrap .WrapString (e .Description , 80 )
82+ _ , _ = sb .WriteString (
83+ " - " + pretty .Sprint (padStyle , e .Description + ":" )[4 :] + "\n \n " ,
84+ )
85+ }
86+ // We add 1 space here because `cliui.DefaultStyles.Code` adds an extra
87+ // space. This makes the code block align at an even 2 or 6
88+ // spaces for symmetry.
89+ _ , _ = sb .WriteString (" " + pretty .Sprint (cliui .DefaultStyles .Code , fmt .Sprintf ("$ %s" , e .Command )))
90+ if i < len (examples )- 1 {
91+ _ , _ = sb .WriteString ("\n \n " )
92+ }
93+ }
94+ return sb .String ()
95+ }
96+
97+ var (
98+ version string
99+ commit string
100+ commitDate string
101+ )
102+
103+ type buildInfo struct {
104+ version string
105+ commitHash string
106+ commitTime time.Time
107+ }
108+
109+ func getBuildInfo () buildInfo {
110+ bi := buildInfo {
111+ version : "v0.0.0-devel" ,
112+ commitHash : "0000000000000000000000000000000000000000" ,
113+ commitTime : time .Now (),
114+ }
115+
116+ if version != "" {
117+ bi .version = version
118+ }
119+ if commit != "" {
120+ bi .commitHash = commit
121+ }
122+ if commitDate != "" {
123+ dateUnix , err := strconv .ParseInt (commitDate , 10 , 64 )
124+ if err != nil {
125+ panic ("invalid commitDate: " + err .Error ())
126+ }
127+ bi .commitTime = time .Unix (dateUnix , 0 )
128+ }
129+
130+ return bi
131+ }
0 commit comments