internal/platform/product/product.go (318 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 product
import (
"strings"
)
type Linter struct {
Name string
PresentableName string
ProductCode string
DockerImage string
SupportNative bool
IsPaid bool
SupportFixes bool
EapOnly bool
}
const (
ReleaseVersion = "2025.3"
ShortVersion = "253"
IsReleased = false
EapSuffix = "-EAP"
ReleaseVer = "release"
EapVer = "eap"
QDJVMC = "QDJVMC"
QDJVM = "QDJVM"
QDAND = "QDAND"
QDPHP = "QDPHP"
QDPY = "QDPY"
QDPYC = "QDPYC"
QDJS = "QDJS"
QDGO = "QDGO"
QDNET = "QDNET"
QDNETC = "QDNETC"
QDANDC = "QDANDC"
QDRST = "QDRST"
QDRUBY = "QDRUBY"
QDCLC = "QDCLC"
QDCPP = "QDCPP"
)
var (
UnknownLinter = Linter{}
JvmLinter = Linter{
PresentableName: "Qodana Ultimate for JVM",
Name: "qodana-jvm",
ProductCode: QDJVM,
DockerImage: "jetbrains/qodana-jvm",
SupportNative: true,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
JvmCommunityLinter = Linter{
PresentableName: "Qodana Community for JVM",
Name: "qodana-jvm-community",
ProductCode: QDJVMC,
DockerImage: "jetbrains/qodana-jvm-community",
SupportNative: true,
IsPaid: false,
SupportFixes: false,
EapOnly: false,
}
AndroidLinter = Linter{
PresentableName: "Qodana for Android",
Name: "qodana-android",
ProductCode: QDAND,
DockerImage: "jetbrains/qodana-android",
SupportNative: false,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
AndroidCommunityLinter = Linter{
PresentableName: "Qodana Community for Android",
Name: "qodana-jvm-android",
ProductCode: QDANDC,
DockerImage: "jetbrains/qodana-jvm-android",
SupportNative: false,
IsPaid: false,
SupportFixes: false,
EapOnly: false,
}
PhpLinter = Linter{
PresentableName: "Qodana for PHP",
Name: "qodana-php",
ProductCode: QDPHP,
DockerImage: "jetbrains/qodana-php",
SupportNative: true,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
PythonLinter = Linter{
PresentableName: "Qodana for Python",
Name: "qodana-python",
ProductCode: QDPY,
DockerImage: "jetbrains/qodana-python",
SupportNative: true,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
PythonCommunityLinter = Linter{
PresentableName: "Qodana Community for Python",
Name: "qodana-python-community",
ProductCode: QDPYC,
DockerImage: "jetbrains/qodana-python-community",
SupportNative: true,
IsPaid: false,
SupportFixes: false,
EapOnly: false,
}
JsLinter = Linter{
PresentableName: "Qodana for JS",
Name: "qodana-js",
ProductCode: QDJS,
DockerImage: "jetbrains/qodana-js",
SupportNative: true,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
DotNetLinter = Linter{
PresentableName: "Qodana for .NET",
Name: "qodana-dotnet",
ProductCode: QDNET,
DockerImage: "jetbrains/qodana-dotnet",
SupportNative: true,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
RubyLinter = Linter{
PresentableName: "Qodana for Ruby",
Name: "qodana-ruby",
ProductCode: QDRUBY,
DockerImage: "jetbrains/qodana-ruby",
SupportNative: false,
IsPaid: true,
SupportFixes: true,
EapOnly: true,
}
CppLinter = Linter{
PresentableName: "Qodana for C/C++",
Name: "qodana-cpp",
ProductCode: QDCPP,
DockerImage: "jetbrains/qodana-cpp",
SupportNative: true,
IsPaid: true,
SupportFixes: false,
EapOnly: true,
}
GoLinter = Linter{
PresentableName: "Qodana for Go",
Name: "qodana-go",
ProductCode: QDGO,
DockerImage: "jetbrains/qodana-go",
SupportNative: true,
IsPaid: true,
SupportFixes: true,
EapOnly: false,
}
RustLinter = Linter{
PresentableName: "Qodana for Rust",
Name: "qodana-rust",
ProductCode: QDRST,
DockerImage: "jetbrains/qodana-rust",
SupportNative: false,
IsPaid: true,
SupportFixes: false,
EapOnly: true,
}
DotNetCommunityLinter = Linter{
PresentableName: "Qodana Community for .NET",
Name: "qodana-cdnet",
ProductCode: QDNETC,
DockerImage: "jetbrains/qodana-cdnet",
SupportNative: false,
IsPaid: false,
SupportFixes: false,
EapOnly: true,
}
ClangLinter = Linter{
PresentableName: "Qodana Community for C/C++",
Name: "qodana-clang",
ProductCode: QDCLC,
DockerImage: "jetbrains/qodana-clang",
SupportNative: false,
IsPaid: false,
SupportFixes: false,
EapOnly: true,
}
// AllLinters Order is important for detection
AllLinters = []Linter{
JvmCommunityLinter,
JvmLinter,
AndroidCommunityLinter,
AndroidLinter,
PhpLinter,
PythonCommunityLinter,
PythonLinter,
JsLinter,
DotNetCommunityLinter,
DotNetLinter,
RubyLinter,
CppLinter,
GoLinter,
RustLinter,
ClangLinter,
}
)
func (linter *Linter) NativeAnalyzer() Analyzer {
return &NativeAnalyzer{
Linter: *linter,
Eap: linter.EapOnly,
}
}
func (linter *Linter) DockerAnalyzer() Analyzer {
return &DockerAnalyzer{
Linter: *linter,
Image: linter.Image(),
}
}
func (linter *Linter) Image() string {
//goland:noinspection GoBoolExpressions
if !IsReleased || linter.EapOnly {
return linter.DockerImage + ":" + ReleaseVersion + "-eap"
}
return linter.DockerImage + ":" + ReleaseVersion
}
// LangsToLinters is a map of languages to linters.
var LangsToLinters = map[string][]Linter{
"Java": {
JvmLinter,
JvmCommunityLinter,
AndroidLinter,
AndroidCommunityLinter,
},
"Kotlin": {
JvmLinter,
JvmCommunityLinter,
AndroidLinter,
AndroidCommunityLinter,
},
"PHP": {PhpLinter},
"Python": {PythonLinter, PythonCommunityLinter},
"JavaScript": {JsLinter},
"TypeScript": {JsLinter},
"Go": {GoLinter},
"C#": {DotNetLinter, DotNetCommunityLinter},
"F#": {DotNetLinter},
"Visual Basic .NET": {DotNetLinter, DotNetCommunityLinter},
"C": {CppLinter, ClangLinter, DotNetLinter},
"C++": {CppLinter, ClangLinter, DotNetLinter},
"Ruby": {RubyLinter},
"Rust": {RustLinter},
}
var AllSupportedFreeLinters = allLintersFiltered(AllLinters, func(linter *Linter) bool { return !linter.IsPaid })
var AllNativeLinters = allLintersFiltered(AllLinters, func(linter *Linter) bool { return linter.SupportNative })
func allImages(linters []Linter) []string {
var images []string
for _, linter := range linters {
images = append(images, linter.Image())
}
return images
}
func allProductCodes(linters []Linter) []string {
var images []string
for _, linter := range linters {
images = append(images, linter.ProductCode)
}
return images
}
func allLintersFiltered(linters []Linter, filter func(linter *Linter) bool) []Linter {
var filtered []Linter
for i := range linters {
if filter(&linters[i]) {
filtered = append(filtered, linters[i])
}
}
return filtered
}
// AllImages is a list of all supported linters.
var AllImages = allImages(AllLinters)
var AllNames = allNames(AllLinters)
func allNames(linters []Linter) []string {
var names []string
for _, linter := range linters {
names = append(names, linter.Name)
}
return names
}
var AllNativeProductCodes = allProductCodes(AllNativeLinters)
func FindLinterByImage(image string) Linter {
image = strings.TrimPrefix(image, "https://")
//goland:noinspection HttpUrlsUsage
image = strings.TrimPrefix(image, "http://")
if strings.HasPrefix(image, "registry.jetbrains.team/p/sa/containers/") {
image = strings.TrimPrefix(image, "registry.jetbrains.team/p/sa/containers/")
image = "jetbrains/" + image
}
for _, linter := range AllLinters {
if strings.HasPrefix(image, linter.DockerImage) {
return linter
}
}
return UnknownLinter
}
func FindLinterByProductCode(productCode string) Linter {
productCode = strings.TrimSuffix(productCode, EapSuffix)
for _, linter := range AllLinters {
if productCode == linter.ProductCode {
return linter
}
}
return UnknownLinter
}
func FindLinterByName(name string) Linter {
name = strings.TrimSuffix(name, EapSuffix)
for _, linter := range AllLinters {
if name == linter.Name {
return linter
}
}
return UnknownLinter
}