Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit3c3564a

Browse files
committed
refactor
1 parent5d370fc commit3c3564a

File tree

4 files changed

+205
-68
lines changed

4 files changed

+205
-68
lines changed

‎cli/open.go‎

Lines changed: 127 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func (r *RootCmd) openVSCode() *clibase.Cmd {
4343
cmd:=&clibase.Cmd{
4444
Annotations:workspaceCommand,
4545
Use:"vscode <workspace> [<directory in workspace>]",
46-
Short:"Open a workspace inVisual Studio Code",
46+
Short:fmt.Sprintf("Open a workspace in%s",vscodeDesktopName),
4747
Middleware:clibase.Chain(
4848
clibase.RequireRangeArgs(1,2),
4949
r.InitClient(client),
@@ -73,18 +73,12 @@ func (r *RootCmd) openVSCode() *clibase.Cmd {
7373
insideThisWorkspace:=insideAWorkspace&&inWorkspaceName==workspaceName
7474

7575
if!insideThisWorkspace {
76-
// We could optionally add a flag to skip wait, like with SSH.
77-
wait:=false
78-
for_,script:=rangeworkspaceAgent.Scripts {
79-
ifscript.StartBlocksLogin {
80-
wait=true
81-
break
82-
}
83-
}
76+
// Wait for the agent to connect, we don't care about readiness
77+
// otherwise (e.g. wait).
8478
err=cliui.Agent(ctx,inv.Stderr,workspaceAgent.ID, cliui.AgentOptions{
8579
Fetch:client.WorkspaceAgent,
86-
FetchLogs:client.WorkspaceAgentLogsAfter,
87-
Wait:wait,
80+
FetchLogs:nil,
81+
Wait:false,
8882
})
8983
iferr!=nil {
9084
ifxerrors.Is(err,context.Canceled) {
@@ -93,55 +87,33 @@ func (r *RootCmd) openVSCode() *clibase.Cmd {
9387
returnxerrors.Errorf("agent: %w",err)
9488
}
9589

96-
// If the ExpandedDirectory was initially missing, it could mean
97-
// that the agent hadn't reported it in yet. Retry once.
98-
ifworkspaceAgent.ExpandedDirectory=="" {
99-
autostart=false// Don't retry autostart.
100-
workspace,workspaceAgent,err=getWorkspaceAndAgent(ctx,inv,client,autostart,codersdk.Me,workspaceName)
90+
// The agent will report it's expanded directory before leaving
91+
// the created state, so we need to wait for that to happen.
92+
// However, if no directory is set, the expanded directory will
93+
// not be set either.
94+
ifworkspaceAgent.Directory!="" {
95+
workspace,workspaceAgent,err=waitForAgentCond(ctx,client,workspace,workspaceAgent,func(a codersdk.WorkspaceAgent)bool {
96+
returnworkspaceAgent.LifecycleState!=codersdk.WorkspaceAgentLifecycleCreated
97+
})
10198
iferr!=nil {
102-
returnxerrors.Errorf("get workspace andagent retry: %w",err)
99+
returnxerrors.Errorf("wait foragent: %w",err)
103100
}
104101
}
105102
}
106103

107-
directory:=workspaceAgent.ExpandedDirectory// Empty unless agentdirectoryis set.
104+
vardirectorystring
108105
iflen(inv.Args)>1 {
109-
d:=inv.Args[1]
110-
111-
switch {
112-
caseinsideThisWorkspace:
113-
// TODO(mafredri): Return error if directory doesn't exist?
114-
directory,err=filepath.Abs(d)
115-
iferr!=nil {
116-
returnxerrors.Errorf("expand directory: %w",err)
117-
}
118-
119-
cased=="~"||strings.HasPrefix(d,"~/"):
120-
returnxerrors.Errorf("path %q requires expansion and is not supported, use an absolute path instead",d)
121-
122-
caseworkspaceAgent.OperatingSystem=="windows":
123-
switch {
124-
casedirectory!=""&&!isWindowsAbsPath(d):
125-
directory=windowsJoinPath(directory,d)
126-
caseisWindowsAbsPath(d):
127-
directory=d
128-
default:
129-
returnxerrors.Errorf("path %q not supported, use an absolute path instead",d)
130-
}
131-
132-
// Note that we use `path` instead of `filepath` since we want Unix behavior.
133-
casedirectory!=""&&!path.IsAbs(d):
134-
directory=path.Join(directory,d)
135-
casepath.IsAbs(d):
136-
directory=d
137-
default:
138-
returnxerrors.Errorf("path %q not supported, use an absolute path instead",d)
139-
}
106+
directory=inv.Args[1]
140107
}
141-
142-
u,err:=url.Parse("vscode://coder.coder-remote/open")
108+
directory,err=resolveAgentAbsPath(workspaceAgent.ExpandedDirectory,directory,workspaceAgent.OperatingSystem,insideThisWorkspace)
143109
iferr!=nil {
144-
returnxerrors.Errorf("parse vscode URI: %w",err)
110+
returnxerrors.Errorf("resolve agent path: %w",err)
111+
}
112+
113+
u:=&url.URL{
114+
Scheme:"vscode",
115+
Host:"coder.coder-remote",
116+
Path:"/open",
145117
}
146118

147119
qp:= url.Values{}
@@ -190,6 +162,16 @@ func (r *RootCmd) openVSCode() *clibase.Cmd {
190162
}
191163
iferr!=nil {
192164
if!generateToken {
165+
// This is not an important step, so we don't want
166+
// to block the user here.
167+
token:=qp.Get("token")
168+
wait:=doAsync(func() {
169+
// Best effort, we don't care if this fails.
170+
apiKeyID:=strings.SplitN(token,"-",2)[0]
171+
_=client.DeleteAPIKey(ctx,codersdk.Me,apiKeyID)
172+
})
173+
deferwait()
174+
193175
qp.Del("token")
194176
u.RawQuery=qp.Encode()
195177
}
@@ -226,19 +208,50 @@ func (r *RootCmd) openVSCode() *clibase.Cmd {
226208
returncmd
227209
}
228210

211+
// waitForAgentCond uses the watch workspace API to update the agent information
212+
// until the condition is met.
213+
funcwaitForAgentCond(ctx context.Context,client*codersdk.Client,workspace codersdk.Workspace,workspaceAgent codersdk.WorkspaceAgent,condfunc(codersdk.WorkspaceAgent)bool) (codersdk.Workspace, codersdk.WorkspaceAgent,error) {
214+
ctx,cancel:=context.WithCancel(ctx)
215+
defercancel()
216+
217+
ifcond(workspaceAgent) {
218+
returnworkspace,workspaceAgent,nil
219+
}
220+
221+
wc,err:=client.WatchWorkspace(ctx,workspace.ID)
222+
iferr!=nil {
223+
returnworkspace,workspaceAgent,xerrors.Errorf("watch workspace: %w",err)
224+
}
225+
226+
forworkspace=rangewc {
227+
workspaceAgent,err=getWorkspaceAgent(workspace,workspaceAgent.Name)
228+
iferr!=nil {
229+
returnworkspace,workspaceAgent,xerrors.Errorf("get workspace agent: %w",err)
230+
}
231+
ifcond(workspaceAgent) {
232+
returnworkspace,workspaceAgent,nil
233+
}
234+
}
235+
236+
returnworkspace,workspaceAgent,xerrors.New("watch workspace: unexpected closed channel")
237+
}
238+
229239
// isWindowsAbsPath checks if the path is an absolute path on Windows. On Unix
230240
// systems the check is very simplistic and does not cover edge cases.
231-
//
232-
//nolint:revive // Shadow path variable for readability.
233-
funcisWindowsAbsPath(pathstring)bool {
241+
funcisWindowsAbsPath(pstring)bool {
234242
ifruntime.GOOS=="windows" {
235-
returnfilepath.IsAbs(path)
243+
returnfilepath.IsAbs(p)
236244
}
237245

238246
switch {
239-
caselen(path)>=2&&path[1]==':':
247+
caselen(p)<2:
248+
returnfalse
249+
casep[1]==':':
240250
// Path starts with a drive letter.
241-
returnlen(path)==2|| (len(path)>=4&&path[2]=='\\'&&path[3]=='\\')
251+
returnlen(p)==2|| (len(p)>=3&&p[2]=='\\')
252+
casep[0]=='\\'&&p[1]=='\\':
253+
// Path starts with \\.
254+
returntrue
242255
default:
243256
returnfalse
244257
}
@@ -262,7 +275,62 @@ func windowsJoinPath(elem ...string) string {
262275
s=e
263276
continue
264277
}
265-
s+="\\"+strings.TrimSuffix(s,"\\")
278+
s+="\\"+strings.TrimSuffix(e,"\\")
266279
}
267280
returns
268281
}
282+
283+
// resolveAgentAbsPath resolves the absolute path to a file or directory in the
284+
// workspace. If the path is relative, it will be resolved relative to the
285+
// workspace's expanded directory. If the path is absolute, it will be returned
286+
// as-is. If the path is relative and the workspace directory is not expanded,
287+
// an error will be returned.
288+
//
289+
// If the path is being resolved within the workspace, the path will be resolved
290+
// relative to the current working directory.
291+
funcresolveAgentAbsPath(workingDirectory,relOrAbsPath,agentOSstring,localbool) (string,error) {
292+
ifrelOrAbsPath=="" {
293+
returnworkingDirectory,nil
294+
}
295+
296+
switch {
297+
caserelOrAbsPath=="~"||strings.HasPrefix(relOrAbsPath,"~/"):
298+
return"",xerrors.Errorf("path %q requires expansion and is not supported, use an absolute path instead",relOrAbsPath)
299+
300+
caselocal:
301+
p,err:=filepath.Abs(relOrAbsPath)
302+
iferr!=nil {
303+
return"",xerrors.Errorf("expand path: %w",err)
304+
}
305+
returnp,nil
306+
307+
caseagentOS=="windows":
308+
switch {
309+
caseworkingDirectory!=""&&!isWindowsAbsPath(relOrAbsPath):
310+
returnwindowsJoinPath(workingDirectory,relOrAbsPath),nil
311+
caseisWindowsAbsPath(relOrAbsPath):
312+
returnrelOrAbsPath,nil
313+
default:
314+
return"",xerrors.Errorf("path %q not supported, use an absolute path instead",relOrAbsPath)
315+
}
316+
317+
// Note that we use `path` instead of `filepath` since we want Unix behavior.
318+
caseworkingDirectory!=""&&!path.IsAbs(relOrAbsPath):
319+
returnpath.Join(workingDirectory,relOrAbsPath),nil
320+
casepath.IsAbs(relOrAbsPath):
321+
returnrelOrAbsPath,nil
322+
default:
323+
return"",xerrors.Errorf("path %q not supported, use an absolute path instead",relOrAbsPath)
324+
}
325+
}
326+
327+
funcdoAsync(ffunc()) (waitfunc()) {
328+
done:=make(chanstruct{})
329+
gofunc() {
330+
deferclose(done)
331+
f()
332+
}()
333+
returnfunc() {
334+
<-done
335+
}
336+
}

‎cli/open_internal_test.go‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package cli
2+
3+
import"testing"
4+
5+
funcTest_resolveAgentAbsPath(t*testing.T) {
6+
t.Parallel()
7+
8+
typeargsstruct {
9+
workingDirectorystring
10+
relOrAbsPathstring
11+
agentOSstring
12+
localbool
13+
}
14+
tests:= []struct {
15+
namestring
16+
argsargs
17+
wantstring
18+
wantErrbool
19+
}{
20+
{"ok no args",args{},"",false},
21+
{"ok only working directory",args{workingDirectory:"/some/path"},"/some/path",false},
22+
{"ok with working directory and rel path",args{workingDirectory:"/some/path",relOrAbsPath:"other/path"},"/some/path/other/path",false},
23+
{"ok with working directory and abs path",args{workingDirectory:"/some/path",relOrAbsPath:"/other/path"},"/other/path",false},
24+
{"ok with no working directory and abs path",args{relOrAbsPath:"/other/path"},"/other/path",false},
25+
26+
{"fail tilde",args{relOrAbsPath:"~"},"",true},
27+
{"fail tilde with working directory",args{workingDirectory:"/some/path",relOrAbsPath:"~"},"",true},
28+
{"fail tilde path",args{relOrAbsPath:"~/some/path"},"",true},
29+
{"fail tilde path with working directory",args{workingDirectory:"/some/path",relOrAbsPath:"~/some/path"},"",true},
30+
{"fail relative dot with no working directory",args{relOrAbsPath:"."},"",true},
31+
{"fail relative with no working directory",args{relOrAbsPath:"some/path"},"",true},
32+
33+
{"ok with working directory and rel path on windows",args{workingDirectory:"C:\\some\\path",relOrAbsPath:"other\\path",agentOS:"windows"},"C:\\some\\path\\other\\path",false},
34+
{"ok with working directory and abs path on windows",args{workingDirectory:"C:\\some\\path",relOrAbsPath:"C:\\other\\path",agentOS:"windows"},"C:\\other\\path",false},
35+
{"ok with no working directory and abs path on windows",args{relOrAbsPath:"C:\\other\\path",agentOS:"windows"},"C:\\other\\path",false},
36+
37+
{"fail with no working directory and rel path on windows",args{relOrAbsPath:"other\\path",agentOS:"windows"},"",true},
38+
}
39+
for_,tt:=rangetests {
40+
tt:=tt
41+
t.Run(tt.name,func(t*testing.T) {
42+
t.Parallel()
43+
44+
got,err:=resolveAgentAbsPath(tt.args.workingDirectory,tt.args.relOrAbsPath,tt.args.agentOS,tt.args.local)
45+
if (err!=nil)!=tt.wantErr {
46+
t.Errorf("resolveAgentAbsPath() error = %v, wantErr %v",err,tt.wantErr)
47+
return
48+
}
49+
ifgot!=tt.want {
50+
t.Errorf("resolveAgentAbsPath() = %v, want %v",got,tt.want)
51+
}
52+
})
53+
}
54+
}

‎cli/ssh.go‎

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -594,40 +594,51 @@ func getWorkspaceAndAgent(ctx context.Context, inv *clibase.Invocation, client *
594594
return codersdk.Workspace{}, codersdk.WorkspaceAgent{},xerrors.Errorf("workspace %q is being deleted",workspace.Name)
595595
}
596596

597+
varagentNamestring
598+
iflen(workspaceParts)>=2 {
599+
agentName=workspaceParts[1]
600+
}
601+
workspaceAgent,err:=getWorkspaceAgent(workspace,agentName)
602+
iferr!=nil {
603+
return codersdk.Workspace{}, codersdk.WorkspaceAgent{},err
604+
}
605+
606+
returnworkspace,workspaceAgent,nil
607+
}
608+
609+
funcgetWorkspaceAgent(workspace codersdk.Workspace,agentNamestring) (workspaceAgent codersdk.WorkspaceAgent,errerror) {
597610
resources:=workspace.LatestBuild.Resources
598611

599612
agents:=make([]codersdk.WorkspaceAgent,0)
600613
for_,resource:=rangeresources {
601614
agents=append(agents,resource.Agents...)
602615
}
603616
iflen(agents)==0 {
604-
return codersdk.Workspace{}, codersdk.WorkspaceAgent{},xerrors.Errorf("workspace %q has no agents",workspace.Name)
617+
return codersdk.WorkspaceAgent{},xerrors.Errorf("workspace %q has no agents",workspace.Name)
605618
}
606-
varworkspaceAgent codersdk.WorkspaceAgent
607-
iflen(workspaceParts)>=2 {
619+
ifagentName!="" {
608620
for_,otherAgent:=rangeagents {
609-
ifotherAgent.Name!=workspaceParts[1] {
621+
ifotherAgent.Name!=agentName {
610622
continue
611623
}
612624
workspaceAgent=otherAgent
613625
break
614626
}
615627
ifworkspaceAgent.ID==uuid.Nil {
616-
return codersdk.Workspace{}, codersdk.WorkspaceAgent{},xerrors.Errorf("agent not found by name %q",workspaceParts[1])
628+
return codersdk.WorkspaceAgent{},xerrors.Errorf("agent not found by name %q",agentName)
617629
}
618630
}
619631
ifworkspaceAgent.ID==uuid.Nil {
620632
iflen(agents)>1 {
621633
workspaceAgent,err=cryptorand.Element(agents)
622634
iferr!=nil {
623-
return codersdk.Workspace{}, codersdk.WorkspaceAgent{},err
635+
return codersdk.WorkspaceAgent{},err
624636
}
625637
}else {
626638
workspaceAgent=agents[0]
627639
}
628640
}
629-
630-
returnworkspace,workspaceAgent,nil
641+
returnworkspaceAgent,nil
631642
}
632643

633644
// Attempt to poll workspace autostop. We write a per-workspace lockfile to

‎codersdk/workspaces.go‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,11 @@ func (c *Client) WatchWorkspace(ctx context.Context, id uuid.UUID) (<-chan Works
219219
iferr!=nil {
220220
return
221221
}
222-
wc<-ws
222+
select {
223+
case<-ctx.Done():
224+
return
225+
casewc<-ws:
226+
}
223227
}
224228
}
225229
}()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp