Skip to content

Commit dbe72d6

Browse files
committed
[jb] sync initial options
1 parent c74f84b commit dbe72d6

File tree

3 files changed

+95
-56
lines changed

3 files changed

+95
-56
lines changed

components/ide/jetbrains/image/status/go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,9 @@ require (
2626
github.com/golang/protobuf v1.5.2 // indirect
2727
github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3 // indirect
2828
github.com/hashicorp/go-version v1.4.0
29+
github.com/otiai10/copy v1.9.0
2930
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
30-
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d // indirect
31+
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect
3132
golang.org/x/text v0.3.7 // indirect
3233
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
3334
google.golang.org/genproto v0.0.0-20220822174746-9e6da59bd2fc // indirect

components/ide/jetbrains/image/status/go.sum

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

components/ide/jetbrains/image/status/main.go

Lines changed: 85 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,10 @@
55
package main
66

77
import (
8-
"bytes"
98
"context"
109
"encoding/json"
1110
"errors"
1211
"fmt"
13-
"io"
1412
"io/ioutil"
1513
"net"
1614
"net/http"
@@ -20,13 +18,13 @@ import (
2018
"os/signal"
2119
"path/filepath"
2220
"reflect"
23-
"regexp"
2421
"strconv"
2522
"strings"
2623
"syscall"
2724
"time"
2825

2926
"github.com/hashicorp/go-version"
27+
cp "github.com/otiai10/copy"
3028
"golang.org/x/xerrors"
3129
"google.golang.org/grpc"
3230
"google.golang.org/grpc/credentials/insecure"
@@ -50,6 +48,15 @@ var (
5048
const BackendPath = "/ide-desktop/backend"
5149
const ProductInfoPath = BackendPath + "/product-info.json"
5250

51+
type LaunchContext struct {
52+
alias string
53+
projectDir string
54+
configDir string
55+
systemDir string
56+
projectConfigDir string
57+
wsInfo *supervisor.WorkspaceInfoResponse
58+
}
59+
5360
// JB startup entrypoint
5461
func main() {
5562
log.Init(ServiceName, Version, true, false)
@@ -65,7 +72,13 @@ func main() {
6572
label = os.Args[3]
6673
}
6774

68-
backendVersion, err := resolveBackendVersion()
75+
info, err := resolveProductInfo()
76+
if err != nil {
77+
log.WithError(err).Error("failed to resolve product info")
78+
return
79+
}
80+
81+
backendVersion, err := version.NewVersion(info.Version)
6982
if err != nil {
7083
log.WithError(err).Error("failed to resolve backend version")
7184
return
@@ -77,8 +90,8 @@ func main() {
7790
return
7891
}
7992

80-
repoRoot := wsInfo.GetCheckoutLocation()
81-
gitpodConfig, err := parseGitpodConfig(repoRoot)
93+
projectDir := wsInfo.GetCheckoutLocation()
94+
gitpodConfig, err := parseGitpodConfig(projectDir)
8295
if err != nil {
8396
log.WithError(err).Error("failed to parse .gitpod.yml")
8497
}
@@ -95,10 +108,33 @@ func main() {
95108
log.WithError(err).Error("failed to configure vmoptions")
96109
}
97110

111+
// Set default config and system directories under /workspace to preserve between restarts
112+
qualifier := os.Getenv("JETBRAINS_BACKEND_QUALIFIER")
113+
if qualifier == "stable" {
114+
qualifier = ""
115+
} else {
116+
qualifier = "-" + qualifier
117+
}
118+
configDir := fmt.Sprintf("/workspace/.config/JetBrains%s", qualifier)
119+
launchCtx := &LaunchContext{
120+
alias: alias,
121+
wsInfo: wsInfo,
122+
projectDir: projectDir,
123+
configDir: configDir,
124+
systemDir: fmt.Sprintf("/workspace/.cache/JetBrains%s", qualifier),
125+
projectConfigDir: fmt.Sprintf("%s/RemoteDev-%s/%s", configDir, info.ProductCode, strings.ReplaceAll(projectDir, "/", "_")),
126+
}
127+
128+
// sync initial options
129+
err = syncOptions(launchCtx)
130+
if err != nil {
131+
log.WithError(err).Error("failed to sync initial options")
132+
}
133+
98134
// install project plugins
99135
version_2022_1, _ := version.NewVersion("2022.1")
100136
if version_2022_1.LessThanOrEqual(backendVersion) {
101-
err = installPlugins(repoRoot, gitpodConfig, alias)
137+
err = installPlugins(gitpodConfig, launchCtx)
102138
installPluginsCost := time.Now().Local().Sub(startTime).Milliseconds()
103139
if err != nil {
104140
log.WithError(err).WithField("cost", installPluginsCost).Error("installing repo plugins: done")
@@ -112,7 +148,7 @@ func main() {
112148
if err != nil {
113149
log.WithError(err).Error("failed to install gitpod-remote plugin")
114150
}
115-
go run(wsInfo, alias)
151+
go run(launchCtx)
116152

117153
debugAgentPrefix := "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:"
118154
http.HandleFunc("/debug", func(w http.ResponseWriter, r *http.Request) {
@@ -324,13 +360,13 @@ func resolveWorkspaceInfo(ctx context.Context) (*supervisor.WorkspaceInfoRespons
324360
return nil, errors.New("failed with attempt 10 times")
325361
}
326362

327-
func run(wsInfo *supervisor.WorkspaceInfoResponse, alias string) {
363+
func run(launchCtx *LaunchContext) {
328364
var args []string
329365
args = append(args, "run")
330-
args = append(args, wsInfo.GetCheckoutLocation())
331-
cmd := remoteDevServerCmd(args)
332-
cmd.Env = append(cmd.Env, "JETBRAINS_GITPOD_BACKEND_KIND="+alias)
333-
workspaceUrl, err := url.Parse(wsInfo.WorkspaceUrl)
366+
args = append(args, launchCtx.projectDir)
367+
cmd := remoteDevServerCmd(args, launchCtx)
368+
cmd.Env = append(cmd.Env, "JETBRAINS_GITPOD_BACKEND_KIND="+launchCtx.alias)
369+
workspaceUrl, err := url.Parse(launchCtx.wsInfo.WorkspaceUrl)
334370
if err == nil {
335371
cmd.Env = append(cmd.Env, "JETBRAINS_GITPOD_WORKSPACE_HOST="+workspaceUrl.Hostname())
336372
}
@@ -342,7 +378,7 @@ func run(wsInfo *supervisor.WorkspaceInfoResponse, alias string) {
342378
}
343379

344380
// Nicely handle SIGTERM sinal
345-
go handleSignal(wsInfo.GetCheckoutLocation())
381+
go handleSignal()
346382

347383
if err := cmd.Wait(); err != nil {
348384
log.WithError(err).Error("failed to wait")
@@ -351,28 +387,22 @@ func run(wsInfo *supervisor.WorkspaceInfoResponse, alias string) {
351387
os.Exit(cmd.ProcessState.ExitCode())
352388
}
353389

354-
func remoteDevServerCmd(args []string) *exec.Cmd {
390+
func remoteDevServerCmd(args []string, productContext *LaunchContext) *exec.Cmd {
355391
cmd := exec.Command(BackendPath+"/bin/remote-dev-server.sh", args...)
356392
cmd.Env = os.Environ()
357393

358394
// Set default config and system directories under /workspace to preserve between restarts
359-
qualifier := os.Getenv("JETBRAINS_BACKEND_QUALIFIER")
360-
if qualifier == "stable" {
361-
qualifier = ""
362-
} else {
363-
qualifier = "-" + qualifier
364-
}
365395
cmd.Env = append(cmd.Env,
366-
fmt.Sprintf("IJ_HOST_CONFIG_BASE_DIR=/workspace/.config/JetBrains%s", qualifier),
367-
fmt.Sprintf("IJ_HOST_SYSTEM_BASE_DIR=/workspace/.cache/JetBrains%s", qualifier),
396+
fmt.Sprintf("IJ_HOST_CONFIG_BASE_DIR=%s", productContext.configDir),
397+
fmt.Sprintf("IJ_HOST_SYSTEM_BASE_DIR=%s", productContext.systemDir),
368398
)
369399

370400
cmd.Stderr = os.Stderr
371401
cmd.Stdout = os.Stdout
372402
return cmd
373403
}
374404

375-
func handleSignal(projectPath string) {
405+
func handleSignal() {
376406
sigChan := make(chan os.Signal, 1)
377407
signal.Notify(sigChan, os.Interrupt, syscall.SIGTERM)
378408

@@ -488,10 +518,11 @@ func updateVMOptions(
488518
}
489519
*/
490520
type ProductInfo struct {
491-
Version string `json:"version"`
521+
Version string `json:"version"`
522+
ProductCode string `json:"productCode"`
492523
}
493524

494-
func resolveBackendVersion() (*version.Version, error) {
525+
func resolveProductInfo() (*ProductInfo, error) {
495526
f, err := os.Open(ProductInfoPath)
496527
if err != nil {
497528
return nil, err
@@ -504,52 +535,51 @@ func resolveBackendVersion() (*version.Version, error) {
504535

505536
var info ProductInfo
506537
err = json.Unmarshal(content, &info)
538+
return &info, err
539+
}
540+
541+
func syncOptions(launchCtx *LaunchContext) error {
542+
srcDir := fmt.Sprintf("%s/.gitpod/%s/options", launchCtx.projectDir, launchCtx.alias)
543+
srcStat, err := os.Stat(srcDir)
544+
if os.IsNotExist(err) {
545+
// nothing to sync
546+
return nil
547+
}
507548
if err != nil {
508-
return nil, err
549+
return err
550+
}
551+
if !srcStat.IsDir() {
552+
return fmt.Errorf("%s is not a directory", srcDir)
509553
}
510-
return version.NewVersion(info.Version)
554+
destDir := fmt.Sprintf("%s/options", launchCtx.projectConfigDir)
555+
_, err = os.Stat(destDir)
556+
if os.IsNotExist(err) {
557+
return cp.Copy(srcDir, destDir)
558+
}
559+
// already synced skipping, i.e. restart of jb backend
560+
return nil
511561
}
512562

513-
func installPlugins(repoRoot string, config *gitpod.GitpodConfig, alias string) error {
514-
plugins, err := getPlugins(config, alias)
563+
func installPlugins(config *gitpod.GitpodConfig, launchCtx *LaunchContext) error {
564+
plugins, err := getPlugins(config, launchCtx.alias)
515565
if err != nil {
516566
return err
517567
}
518568
if len(plugins) <= 0 {
519569
return nil
520570
}
521-
r, w, err := os.Pipe()
522-
if err != nil {
523-
return err
524-
}
525-
defer r.Close()
526-
527-
outC := make(chan string)
528-
go func() {
529-
var buf bytes.Buffer
530-
_, _ = io.Copy(&buf, r)
531-
outC <- buf.String()
532-
}()
533571

534572
var args []string
535573
args = append(args, "installPlugins")
536-
args = append(args, repoRoot)
574+
args = append(args, launchCtx.projectDir)
537575
args = append(args, plugins...)
538-
cmd := remoteDevServerCmd(args)
539-
cmd.Stdout = io.MultiWriter(w, os.Stdout)
576+
cmd := remoteDevServerCmd(args, launchCtx)
540577
installErr := cmd.Run()
541578

542579
// delete alien_plugins.txt to suppress 3rd-party plugins consent on startup to workaround backend startup freeze
543-
w.Close()
544-
out := <-outC
545-
configR := regexp.MustCompile("IDE config directory: (\\S+)\n")
546-
matches := configR.FindStringSubmatch(out)
547-
if len(matches) == 2 {
548-
configDir := matches[1]
549-
err := os.Remove(configDir + "/alien_plugins.txt")
550-
if err != nil {
551-
log.WithError(err).Error("failed to suppress 3rd-party plugins consent")
552-
}
580+
err = os.Remove(launchCtx.projectConfigDir + "/alien_plugins.txt")
581+
if err != nil {
582+
log.WithError(err).Error("failed to suppress 3rd-party plugins consent")
553583
}
554584

555585
if installErr != nil {

0 commit comments

Comments
 (0)