4
4
"bufio"
5
5
"context"
6
6
"encoding/json"
7
- "fmt"
8
7
"io"
9
8
"os"
10
9
"strings"
@@ -15,6 +14,7 @@ import (
15
14
"golang.org/x/xerrors"
16
15
17
16
"github.com/coder/coder/v2/cli/cliui"
17
+ "github.com/coder/coder/v2/coderd/util/slice"
18
18
"github.com/coder/coder/v2/codersdk"
19
19
"github.com/coder/coder/v2/codersdk/workspacesdk"
20
20
"github.com/coder/coder/v2/pty"
@@ -96,6 +96,7 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT
96
96
} else {
97
97
reconnectID = uuid .New ()
98
98
}
99
+
99
100
ws , agt , err := getWorkspaceAndAgent (ctx , inv , client , true , args .NamedWorkspace )
100
101
if err != nil {
101
102
return err
@@ -118,14 +119,6 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT
118
119
}
119
120
}
120
121
121
- if err := cliui .Agent (ctx , inv .Stderr , agt .ID , cliui.AgentOptions {
122
- FetchInterval : 0 ,
123
- Fetch : client .WorkspaceAgent ,
124
- Wait : false ,
125
- }); err != nil {
126
- return err
127
- }
128
-
129
122
// Get the width and height of the terminal.
130
123
var termWidth , termHeight uint16
131
124
stdoutFile , validOut := inv .Stdout .(* os.File )
@@ -149,6 +142,15 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT
149
142
}()
150
143
}
151
144
145
+ // If a user does not specify a command, we'll assume they intend to open an
146
+ // interactive shell.
147
+ var backend string
148
+ if isOneShotCommand (args .Command ) {
149
+ // If the user specified a command, we'll prefer to use the buffered method.
150
+ // The screen backend is not well suited for one-shot commands.
151
+ backend = "buffered"
152
+ }
153
+
152
154
conn , err := workspacesdk .New (client ).AgentReconnectingPTY (ctx , workspacesdk.WorkspaceAgentReconnectingPTYOpts {
153
155
AgentID : agt .ID ,
154
156
Reconnect : reconnectID ,
@@ -157,14 +159,13 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT
157
159
ContainerUser : args .ContainerUser ,
158
160
Width : termWidth ,
159
161
Height : termHeight ,
162
+ BackendType : backend ,
160
163
})
161
164
if err != nil {
162
165
return xerrors .Errorf ("open reconnecting PTY: %w" , err )
163
166
}
164
167
defer conn .Close ()
165
168
166
- cliui .Infof (inv .Stderr , "Connected to %s (agent id: %s)" , args .NamedWorkspace , agt .ID )
167
- cliui .Infof (inv .Stderr , "Reconnect ID: %s" , reconnectID )
168
169
closeUsage := client .UpdateWorkspaceUsageWithBodyContext (ctx , ws .ID , codersdk.PostWorkspaceUsageRequest {
169
170
AgentID : agt .ID ,
170
171
AppName : codersdk .UsageAppNameReconnectingPty ,
@@ -210,7 +211,21 @@ func handleRPTY(inv *serpent.Invocation, client *codersdk.Client, args handleRPT
210
211
_ , _ = io .Copy (inv .Stdout , conn )
211
212
cancel ()
212
213
_ = conn .Close ()
213
- _ , _ = fmt .Fprintf (inv .Stderr , "Connection closed\n " )
214
214
215
215
return nil
216
216
}
217
+
218
+ var knownShells = []string {"ash" , "bash" , "csh" , "dash" , "fish" , "ksh" , "powershell" , "pwsh" , "zsh" }
219
+
220
+ func isOneShotCommand (cmd []string ) bool {
221
+ // If the command is empty, we'll assume the user wants to open a shell.
222
+ if len (cmd ) == 0 {
223
+ return false
224
+ }
225
+ // If the command is a single word, and that word is a known shell, we'll
226
+ // assume the user wants to open a shell.
227
+ if len (cmd ) == 1 && slice .Contains (knownShells , cmd [0 ]) {
228
+ return false
229
+ }
230
+ return true
231
+ }
0 commit comments