@@ -3,19 +3,129 @@ package main
3
3
import (
4
4
"fmt"
5
5
"os"
6
+ "strconv"
7
+ "strings"
8
+ "time"
6
9
10
+ "github.com/coder/pretty"
7
11
"github.com/coder/serpent"
12
+ "github.com/coder/wush/cliui"
13
+ "github.com/mitchellh/go-wordwrap"
8
14
)
9
15
10
16
func 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
+ },
15
57
}
58
+
16
59
err := cmd .Invoke ().WithOS ().Run ()
17
60
if err != nil {
18
61
fmt .Fprintf (os .Stderr , "error: %v\n " , err )
19
62
os .Exit (1 )
20
63
}
21
64
}
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