Skip to content

Commit a7e9e26

Browse files
AndreiIurkoandreiiuravafanasiev
authored andcommitted
🐛 QD-12352 Change exec.Command to functions from utils (#648)
* 🐛 QD-12352 Change exec.Command to functions from utils * 🐛 QD-12352 Add tests with spaces in archive path * 🐛 QD-12352 Fix space issues with other OS --------- Co-authored-by: Andrei Iurko <[email protected]> Co-authored-by: alexey.afanasiev <[email protected]>
1 parent 7d078c5 commit a7e9e26

File tree

4 files changed

+49
-25
lines changed

4 files changed

+49
-25
lines changed

cli/go.work.sum

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ go.etcd.io/etcd/client/v2 v2.305.12/go.mod h1:aQ/yhsxMu+Oht1FOupSr60oBvcS9cKXHrz
5050
go.etcd.io/etcd/client/v3 v3.5.12/go.mod h1:tSbBCakoWmmddL+BKVAJHa9km+O/E+bumDe9mSbPiqw=
5151
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
5252
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.49.0/go.mod h1:Mjt1i1INqiaoZOMGR1RIUJN+i3ChKoFRqzrRQhlkbs0=
53+
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
5354
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
55+
golang.org/x/mod v0.25.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
5456
golang.org/x/telemetry v0.0.0-20240521205824-bda55230c457/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
57+
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
58+
golang.org/x/tools v0.33.0/go.mod h1:CIJMaWEY88juyUfo7UbgPqbC8rU2OqfAV1h2Qp0oMYI=
5559
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
5660
google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o=
5761
google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds=

core/startup/installers.go

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,6 @@ import (
2121
"encoding/hex"
2222
"errors"
2323
"fmt"
24-
"github.com/JetBrains/qodana-cli/v2025/platform"
25-
"github.com/JetBrains/qodana-cli/v2025/platform/msg"
26-
"github.com/JetBrains/qodana-cli/v2025/platform/product"
27-
"github.com/JetBrains/qodana-cli/v2025/platform/strutil"
28-
"github.com/JetBrains/qodana-cli/v2025/platform/utils"
29-
cp "github.com/otiai10/copy"
30-
"github.com/pterm/pterm"
31-
log "github.com/sirupsen/logrus"
3224
"io"
3325
"io/fs"
3426
"math/rand"
@@ -37,6 +29,15 @@ import (
3729
"path/filepath"
3830
"runtime"
3931
"strings"
32+
33+
"github.com/JetBrains/qodana-cli/v2025/platform"
34+
"github.com/JetBrains/qodana-cli/v2025/platform/msg"
35+
"github.com/JetBrains/qodana-cli/v2025/platform/product"
36+
"github.com/JetBrains/qodana-cli/v2025/platform/strutil"
37+
"github.com/JetBrains/qodana-cli/v2025/platform/utils"
38+
cp "github.com/otiai10/copy"
39+
"github.com/pterm/pterm"
40+
log "github.com/sirupsen/logrus"
4041
)
4142

4243
func downloadAndInstallIDE(
@@ -210,13 +211,14 @@ func getIde(analyzer product.Analyzer) *ReleaseDownloadInfo {
210211

211212
// installIdeWindowsExe is used as a fallback, since it needs installation privileges and alters the registry
212213
func installIdeWindowsExe(archivePath string, targetDir string) error {
213-
output, err := exec.Command(
214-
archivePath,
214+
stdout, stderr, _, err := utils.RunCmdRedirectOutput(
215+
"",
216+
strutil.QuoteForWindows(archivePath),
215217
"/S",
216218
fmt.Sprintf("/D=%s", strutil.QuoteForWindows(targetDir)),
217-
).CombinedOutput()
219+
)
218220
if err != nil {
219-
return fmt.Errorf("%s: %s. Output: %s", archivePath, err, string(output))
221+
return fmt.Errorf("%s: %s. Stdout: %s. Stderr: %s", archivePath, err, stdout, stderr)
220222
}
221223
return nil
222224
}
@@ -237,16 +239,16 @@ func installIdeFromZip(archivePath string, targetDir string) error {
237239
if err != nil {
238240
return fmt.Errorf("couldn't create a temporary directory %w", err)
239241
}
240-
241-
output, err := exec.Command(
242+
stdout, stderr, _, err := utils.RunCmdRedirectOutput(
243+
"",
242244
"tar",
243245
"-xf",
244-
strutil.QuoteForWindows(archivePath),
246+
strutil.GetQuotedPath(archivePath),
245247
"-C",
246-
strutil.QuoteForWindows(tempDir),
247-
).CombinedOutput()
248+
strutil.GetQuotedPath(tempDir),
249+
)
248250
if err != nil {
249-
return fmt.Errorf("extracting files error: %w. Output: %s", err, string(output))
251+
return fmt.Errorf("extracting files error: %w. Stdout: %s. Stderr: %s", err, stdout, stderr)
250252
}
251253

252254
err = os.Rename(tempDir, targetDir)
@@ -276,17 +278,19 @@ func installIdeFromTar(archivePath string, targetDir string) error {
276278
if err := os.MkdirAll(targetDir, os.ModePerm); err != nil {
277279
log.Fatal("couldn't create a directory ", err.Error())
278280
}
279-
output, err := exec.Command(
281+
stdout, stderr, _, err := utils.RunCmdRedirectOutput(
282+
"",
280283
"tar",
281284
"-xf",
282-
archivePath,
285+
strutil.GetQuotedPath(archivePath),
283286
"-C",
284-
targetDir,
287+
strutil.GetQuotedPath(targetDir),
285288
"--strip-components",
286289
"1",
287-
).CombinedOutput()
290+
)
291+
288292
if err != nil {
289-
return fmt.Errorf("tar: %s. Output: %s", err, string(output))
293+
return fmt.Errorf("tar: %s. Stdout: %s. Stderr: %s", err, stdout, stderr)
290294
}
291295
return nil
292296
}
@@ -380,7 +384,7 @@ func downloadCustomPlugins(ideUrl string, targetDir string, spinner *pterm.Spinn
380384
return fmt.Errorf("error while downloading plugins: %v", err)
381385
}
382386

383-
_, err = exec.Command("tar", "-xf", archivePath, "-C", targetDir).Output()
387+
_, err = utils.RunCmd("", "tar", "-xf", strutil.GetQuotedPath(archivePath), "-C", strutil.GetQuotedPath(targetDir))
384388
if err != nil {
385389
return fmt.Errorf("tar: %s", err)
386390
}

core/startup/installers_test.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,30 @@ func TestInstallIdeFromZip(t *testing.T) {
108108
tests := []struct {
109109
name string
110110
useSymlink bool
111+
dirPattern string
111112
}{
112113
{
113114
name: "regular directory",
114115
useSymlink: false,
116+
dirPattern: "qodana_test",
115117
},
116118
{
117119
name: "symlink directory",
118120
useSymlink: true,
121+
dirPattern: "qodana_test",
122+
},
123+
{
124+
name: "arch path with space",
125+
useSymlink: true,
126+
dirPattern: "qodana _test",
119127
},
120128
}
121129

122130
for _, tt := range tests {
123131
t.Run(
124132
tt.name, func(t *testing.T) {
125133
// Create a temporary directory for the test
126-
tempDir, err := os.MkdirTemp("", "qodana_test_")
134+
tempDir, err := os.MkdirTemp("", tt.dirPattern)
127135
if err != nil {
128136
t.Fatalf("Failed to create temporary directory: %v", err)
129137
}

platform/strutil/strutil.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ func QuoteForWindows(s string) string {
8686
return s
8787
}
8888

89+
// GetQuotedPath returns a quoted path for the current OS.
90+
func GetQuotedPath(path string) string {
91+
if runtime.GOOS == "windows" {
92+
return QuoteForWindows(path)
93+
}
94+
return QuoteIfSpace(path)
95+
}
96+
8997
// IsStringQuoted checks if a string is already quoted with double quotes.
9098
func IsStringQuoted(s string) bool {
9199
return strings.HasPrefix(s, "\"") && strings.HasSuffix(s, "\"")

0 commit comments

Comments
 (0)