internal/core/properties.go (192 lines of code) (raw):

/* * Copyright 2021-2024 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package core import ( "fmt" "os" "path/filepath" "sort" "strconv" "strings" "github.com/JetBrains/qodana-cli/internal/cloud" "github.com/JetBrains/qodana-cli/internal/core/corescan" "github.com/JetBrains/qodana-cli/internal/platform" "github.com/JetBrains/qodana-cli/internal/platform/product" "github.com/JetBrains/qodana-cli/internal/platform/qdenv" "github.com/JetBrains/qodana-cli/internal/platform/qdyaml" "github.com/JetBrains/qodana-cli/internal/platform/strutil" log "github.com/sirupsen/logrus" ) func getPropertiesMap( prefix string, dotNet qdyaml.DotNet, deviceIdSalt []string, plugins []string, analysisId string, coverageDir string, repositoryRoot string, ) map[string]string { properties := map[string]string{ "-Didea.headless.enable.statistics": strconv.FormatBool(cloud.Token.IsAllowedToSendFUS()), "-Didea.headless.statistics.device.id": deviceIdSalt[0], "-Didea.headless.statistics.salt": deviceIdSalt[1], "-Dqodana.automation.guid": strutil.QuoteIfSpace(analysisId), "-XX:MaxRAMPercentage": "70", //only in docker? } if coverageDir != "" { properties["-Dqodana.coverage.input"] = strutil.QuoteIfSpace(coverageDir) } if repositoryRoot != "" && repositoryRoot != "." { properties["-Dqodana.path.to.project.dir.from.project.root"] = strutil.QuoteIfSpace(repositoryRoot) } if len(plugins) > 0 { properties["-Didea.required.plugins.id"] = strings.Join(plugins, ",") } if prefix == "Rider" { if dotNet.Project != "" { properties["-Dqodana.net.project"] = strutil.QuoteIfSpace(dotNet.Project) } else if dotNet.Solution != "" { properties["-Dqodana.net.solution"] = strutil.QuoteIfSpace(dotNet.Solution) } if dotNet.Configuration != "" { properties["-Dqodana.net.configuration"] = strutil.QuoteIfSpace(dotNet.Configuration) } if dotNet.Platform != "" { properties["-Dqodana.net.platform"] = strutil.QuoteIfSpace(dotNet.Platform) } if dotNet.Frameworks != "" { properties["-Dqodana.net.targetFrameworks"] = strutil.QuoteIfSpace(dotNet.Frameworks) } else if qdenv.IsContainer() { // We don't want to scan .NET Framework projects in Linux containers properties["-Dqodana.net.targetFrameworks"] = "!net48;!net472;!net471;!net47;!net462;!net461;!net46;!net452;!net451;!net45;!net403;!net40;!net35;!net20;!net11" } } log.Debugf("properties: %v", properties) return properties } // GetCommonProperties computes common properties for installPlugins and qodana executuion func GetCommonProperties(c corescan.Context) []string { systemDir := filepath.Join(c.CacheDir(), "idea", c.Prod().GetVersionBranch()) pluginsDir := filepath.Join(c.CacheDir(), "plugins", c.Prod().GetVersionBranch()) lines := []string{ fmt.Sprintf("-Didea.config.path=%s", strutil.QuoteIfSpace(c.ConfigDir())), fmt.Sprintf("-Didea.system.path=%s", strutil.QuoteIfSpace(systemDir)), fmt.Sprintf("-Didea.plugins.path=%s", strutil.QuoteIfSpace(pluginsDir)), fmt.Sprintf("-Didea.log.path=%s", strutil.QuoteIfSpace(c.LogDir())), } treatAsRelease := os.Getenv(qdenv.QodanaTreatAsRelease) if treatAsRelease == "true" { lines = append(lines, "-Deap.require.license=release") } return lines } func GetInstallPluginsProperties(c corescan.Context) []string { lines := GetCommonProperties(c) lines = append( lines, "-Didea.headless.enable.statistics=false", "-Dqodana.application=true", "-Dintellij.platform.load.app.info.from.resources=true", fmt.Sprintf("-Dqodana.build.number=%s-%s", c.Prod().IdeCode, c.Prod().Build), ) sort.Strings(lines) return lines } // GetScanProperties writes key=value `props` to file `f` having later key occurrence win func GetScanProperties(c corescan.Context) []string { yaml := c.QodanaYamlConfig() yamlProps := yaml.Properties dotNetOptions := yaml.DotNet plugins := getPluginIds(yaml.Plugins) lines := GetCommonProperties(c) lines = append( lines, fmt.Sprintf("-Xlog:gc*:%s", strutil.QuoteIfSpace(filepath.Join(c.LogDir(), "gc.log"))), ) if c.JvmDebugPort() > 0 { lines = append( lines, fmt.Sprintf("-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:%s", containerJvmDebugPort), ) } customPluginPathsValue := getCustomPluginPaths(c.Prod()) if customPluginPathsValue != "" { lines = append(lines, fmt.Sprintf("-Dplugin.path=%s", customPluginPathsValue)) } disabledPluginsFile := c.Prod().DisabledPluginsFilePath() if _, err := os.Stat(disabledPluginsFile); err == nil { lines = append(lines, fmt.Sprintf("-Ddisabled.plugins.file.path=%s", disabledPluginsFile)) } cliProps, flags := c.PropertiesAndFlags() for _, f := range flags { if f != "" && !strutil.Contains(lines, f) { lines = append(lines, f) } } props := getPropertiesMap( c.Prod().ParentPrefix(), dotNetOptions, platform.GetDeviceIdSalt(), plugins, c.AnalysisId(), c.CoverageDir(), c.ProjectDirPathRelativeToRepositoryRoot(), ) for k, v := range yamlProps { // qodana.yaml – overrides vmoptions if !strings.HasPrefix(k, "-") { k = fmt.Sprintf("-D%s", k) } props[k] = v } for k, v := range cliProps { // CLI – overrides anything if !strings.HasPrefix(k, "-") { k = fmt.Sprintf("-D%s", k) } props[k] = v } for k, v := range props { lines = append(lines, fmt.Sprintf("%s=%s", k, v)) } sort.Strings(lines) return lines } func getCustomPluginPaths(prod product.Product) string { path := prod.CustomPluginsPath() if _, err := os.Stat(path); os.IsNotExist(err) { return "" } files, err := os.ReadDir(path) if err != nil { log.Fatal(err) } var paths []string for _, file := range files { paths = append(paths, filepath.Join(path, file.Name())) } return strings.Join(paths, ",") } // writeProperties writes the given key=value `props` to file `f` (sets the environment variable) func writeProperties(c corescan.Context) { // opts.confDirPath(Prod().version) opts.vmOptionsPath(Prod().version) properties := GetScanProperties(c) err := os.WriteFile(c.VmOptionsPath(), []byte(strings.Join(properties, "\n")), 0o644) if err != nil { log.Fatal(err) } err = os.Setenv(c.Prod().VmOptionsEnv(), c.VmOptionsPath()) if err != nil { log.Fatal(err) } } func setInstallPluginsVmoptions(c corescan.Context) { vmOptions := GetInstallPluginsProperties(c) log.Debugf("install plugins options:%s", vmOptions) err := os.WriteFile(c.InstallPluginsVmOptionsPath(), []byte(strings.Join(vmOptions, "\n")), 0o644) if err != nil { log.Fatal(err) } err = os.Setenv(c.Prod().VmOptionsEnv(), c.InstallPluginsVmOptionsPath()) if err != nil { log.Fatal(err) } } func getPluginIds(plugins []qdyaml.Plugin) []string { ids := make([]string, len(plugins)) for i, plugin := range plugins { ids[i] = plugin.Id } return ids }