[Repair Utility] move to community

GitOrigin-RevId: af0c92f448088c53578857b0e1b84b95c2664a4e
This commit is contained in:
konstantin.annikov
2022-11-09 16:13:29 +00:00
committed by intellij-monorepo-bot
parent 893aeb087a
commit 01f61d2d78
48 changed files with 4765 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
/command/jbr/test_jbr_files/jbr-1.8/Contents/
/command/jbr/test_jbr_files/jbr-11/Contents/
/bin
+30
View File
@@ -0,0 +1,30 @@
ARG GOLANG_IMAGE
FROM --platform=${BUILDPLATFORM} ${GOLANG_IMAGE} AS build
ENV CGO_ENABLED=0
WORKDIR /src
COPY . .
ARG TARGETOS
ARG TARGETARCH
ARG DOWNLOADURL
RUN go mod download all
RUN GOOS=${TARGETOS} GOARCH=${TARGETARCH} go build -o /out/repair -ldflags "-X repair/helpers.EmbeededDownloadUrl=${DOWNLOADURL}" .
FROM scratch AS bin-linux-amd64
COPY --from=build /out/repair /repair-linux-amd64
FROM scratch AS bin-linux-arm64
COPY --from=build /out/repair /repair-linux-arm64
FROM scratch AS bin-darwin-amd64
COPY --from=build /out/repair /repair-darwin-amd64
FROM scratch AS bin-darwin-arm64
COPY --from=build /out/repair /repair-darwin-arm64
FROM scratch AS bin-windows-amd64
COPY --from=build /out/repair /repair.exe
FROM scratch AS bin-windows-arm64
COPY --from=build /out/repair /repair64a.exe
FROM bin-${TARGETOS}-${TARGETARCH} AS bin
+43
View File
@@ -0,0 +1,43 @@
Repair is the command line utility to troubleshoot startup problems of the IDE.
Repair binary should be launched from the command line if the IDE cannot start.
## Usage
`repair [aspect] [flags]` where
### [aspect] is one of
| Aspect | Description |
|:----------|:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| hashes | Hashes aspect generates(`-g`) or checks(`-c`, default) IDE integrity by inspecting checksums of all installation files.<br/> Hashes aspect returns Warning if some files are missing, or distribution has redundant files inside |
| log | Log aspect inspects idea.log file for exceptions and errors generated by plugins. In case of Warnings, it asks to remove caches and configs. |
| plugins | Plugins aspect scans all the installed plugins and suggest fixes if some of them are incompatible or require updates. |
| runtime | Runtime aspect finds the JDK used to start the IDE and checks if it is OK to use. Sets the bundled JDK in case of warnings. |
| vmoptions | Vmoptions aspect finds the .vmoptions file used by the IDE and analyzes its content for suspicious entries. If any of them found, one can edit the file manually, or reset VM options to default. |
If no aspects passed, all aspects will be executed one by one.
### [flags] are:
| Flag | Description |
|:----------------|:-----------------------------------------------------------------|
| --debug | Enable debug |
| -h , --help | show help for repair utility |
| -n, --no | Only check the installation. All the fixes will be skipped. |
| -y, --yes | Apply all the suggested fixes automatically |
| --path [string] | path to the IDE (default is the IDE where the script is located) |
### Help
To show usage overview, execute `./repair --help`
To list all available options of an aspect, execute `./repair <aspect> --help`
## Example
`/Applications/IntelliJ IDEA.app/Contents/bin/repair` - Checks the current IDE installation through all aspects one-by-one
`./repair hashes --path "/Applications/IntelliJ IDEA.app"` - Checks all the files of the defined IDE installation for consistency
`./repair plugins -y` - Find all installed IDEs on the computer and check its plugins. All fixes such as updaying will be executed automatically
+32
View File
@@ -0,0 +1,32 @@
#!/bin/bash
set -e
function retry() {
local limit=$1
shift
local attempt=1
while true; do
# shellcheck disable=SC2015
"$@" && { return 0; } || {
ec=$?
echo "Failed with exit code $ec. Attempt $attempt/$limit."
if [[ $attempt -ge limit ]]; then
return $ec
fi
((attempt++))
}
done
}
GOLANG_IMAGE=$(cat golang-image.txt)
retry 3 docker pull "$GOLANG_IMAGE"
for platform in "windows/amd64" "windows/arm64" "linux/amd64" "linux/arm64" "darwin/amd64" "darwin/arm64"
do
ENVVAR=$(echo $platform | sed 's/\//_/g')
DOWNLOADURL=$(eval "echo \${${ENVVAR}_url}" )
docker buildx build \
--target bin --output bin/ --platform $platform \
--build-arg "GOLANG_IMAGE=$GOLANG_IMAGE" \
--build-arg "DOWNLOADURL=$DOWNLOADURL" .
done
+35
View File
@@ -0,0 +1,35 @@
package cmd
import (
"github.com/spf13/cobra"
"repair/helpers"
"repair/logger"
)
func init() {
rootCmd.AddCommand(cachesCmd)
cachesCmd.PersistentFlags().BoolVarP(&helpers.ClearCachesFlag, "clear", "c", false, "Clear caches of all projects for the IDE")
}
var cachesCmd = &cobra.Command{
Use: "caches",
Short: "Invalidate caches when called with `--clear` flag",
Long: `Caches aspect with '--clear' flag provides an alternative for the "Invalidate caches and restart" action, which can run outside the IDE.`,
Run: func(cmd *cobra.Command, args []string) {
RunCachesAspect(args)
},
PreRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Caches aspect started")
},
PostRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Caches aspect finished")
},
}
func RunCachesAspect(args []string) {
if helpers.ClearCachesFlag {
helpers.CurrentIde.ClearSystemDirectory()
} else {
logger.InfoLogger.Println("Nothing to do here")
}
}
+53
View File
@@ -0,0 +1,53 @@
package cmd
import (
"github.com/spf13/cobra"
"repair/helpers"
"repair/logger"
"strings"
)
func init() {
rootCmd.AddCommand(hashesCmd)
hashesCmd.PersistentFlags().BoolVarP(&helpers.GenerateHashesFlag, "generate", "g", false, "Generate manifest file for IDE installation")
hashesCmd.PersistentFlags().BoolVarP(&helpers.CheckHashesFlag, "check", "c", false, "Generate manifest file for IDE installation and check it with the reference generated by JetBrains")
hashesCmd.PersistentFlags().StringVarP(&helpers.HashesOutputFile, "output-file", "o", "manifest.json", "output file for the manifest")
hashesCmd.PersistentFlags().StringVarP(&Algorithms, "algorithms", "a", "sha256,crc32", "Comma separated list of algorithms to generate hashes with. CRC32 and sha256 are supported now")
hashesCmd.PersistentFlags().BoolVarP(&helpers.CompareHashesFlag, "compare", "", false, "Compare two manifest files. Example: repair --compare --file1='/path/to/file1' --file2='/path/to/file2'")
hashesCmd.PersistentFlags().StringVarP(&helpers.CompareHashesFile1, "file1", "", "", "First manifest file to compare with")
hashesCmd.PersistentFlags().StringVarP(&helpers.CompareHashesFile2, "file2", "", "", "Second manifest file to compare with")
_ = hashesCmd.PersistentFlags().MarkHidden("file1")
_ = hashesCmd.PersistentFlags().MarkHidden("file2")
}
var Algorithms string
var hashesCmd = &cobra.Command{
Use: "hashes",
Short: "generates(-g) or checks(-c) IDE installation integrity",
Long: `Hashes aspect generates manifest file of an IDE installation and checks it against standard manifest file generated by JetBrains`,
Run: func(cmd *cobra.Command, args []string) {
RunHashesAspect(args)
},
PreRun: func(cmd *cobra.Command, args []string) {
parseFlags()
logger.InfoLogger.Println("Hashes aspect started")
},
PostRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Hashes aspect finished")
},
}
func parseFlags() {
Algorithms = strings.ToUpper(Algorithms)
helpers.Algorithms = strings.Split(Algorithms, ",")
}
func RunHashesAspect(args []string) {
if helpers.GenerateHashesFlag {
helpers.GenerateMainfestFile()
} else if helpers.CompareHashesFlag {
helpers.CompareHashes()
} else {
helpers.CheckHashes()
}
}
+49
View File
@@ -0,0 +1,49 @@
package cmd
import (
"github.com/spf13/cobra"
"repair/helpers"
"repair/logger"
)
func init() {
rootCmd.AddCommand(logCmd)
}
var logCmd = &cobra.Command{
Use: "log",
Short: "Check the idea.log file for errors",
Long: "Log aspect analyzes idea.log file for exceptions generated by plugins and other exceptions. ",
PreRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Logs aspect started")
},
Run: func(cmd *cobra.Command, args []string) {
RunLogAspect(args)
},
PostRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Logs aspect finished")
},
}
func RunLogAspect(args []string) {
ideaLogPath := helpers.GetIdeaLogPath(helpers.CurrentIde.Binary)
if ideaLogPath == "" {
logger.InfoLogger.Println("No idea.log file found")
return
}
helpers.CurrentIde.AskUserAndDisablePlugins(helpers.GetPluginsWithExceptionsInIdeaLog(ideaLogPath))
helpers.CurrentIde.AskUserToRunIdeAndCheckTheIssue()
exceptions := helpers.GetLogEntriesWithExceptions(ideaLogPath)
if len(exceptions) > 0 {
logger.ConsoleLogger.Println("There are exceptions unrelated to plugins in idea.log")
logExceptions(exceptions)
helpers.CurrentIde.AskUserAndClearSystemDirectory()
}
}
func logExceptions(exceptions []helpers.LogEntry) {
logger.DebugLogger.Println("The following exceptions occurred:")
for _, exception := range exceptions {
logger.DebugLogger.Println("\n" + exception.DateAndTime + " " + exception.Severity + " " + exception.Header + "\n" + exception.Body)
}
}
+75
View File
@@ -0,0 +1,75 @@
package cmd
import (
"repair/helpers"
"repair/logger"
"github.com/spf13/cobra"
)
func init() {
rootCmd.AddCommand(pluginsCmd)
}
var pluginsCmd = &cobra.Command{
Use: "plugins",
Short: "Check if broken, or old plugins are installed",
Long: "Plugins aspect checks every installed plugin for versions mismatch, available updates and deprecation notices. Connection to https://plugins.jetbrains.com is required.",
PreRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Plugins aspect started")
},
Run: func(cmd *cobra.Command, args []string) {
RunPluginsAspect(args)
},
PostRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Plugins aspect finished")
},
}
func RunPluginsAspect(args []string) {
incompatiblePluginsList := helpers.CurrentIde.CustomPluginsList().FilterIncompatible()
logger.DebugLogger.Printf("Detected plugins: \n%s", helpers.CustomPluginsList.ToString())
if len(incompatiblePluginsList) > 0 {
helpers.CurrentIde.AskUserAndUpdatePlugins(incompatiblePluginsList.FilterUpdatable())
helpers.CurrentIde.AskUserAndDisablePlugins(incompatiblePluginsList.FilterDeprecated())
helpers.CurrentIde.RefreshPluginsList()
helpers.CurrentIde.AskUserToRunIdeAndCheckTheIssue()
} else {
logger.InfoLogger.Println("No suspicious plugins found")
if isAspectPassed() && len(helpers.PluginsList.FilterEnabled()) > 0 {
logger.InfoLogger.Println("As \"plugins\" aspect has been defined explicitly, let's disable them all.")
disablePluginsOneByOne()
}
}
}
func disablePluginsOneByOne() {
question := "Let's try to disable all custom plugins to check if the error is caused by them?"
options := []string{"y", "n"}
if helpers.AskQuestionWithOptions(question, options) == "y" {
helpers.CurrentIde.DisableAllCustomPlugins(false)
issueIsStillHere := helpers.CurrentIde.AskUserToRunIdeAndCheckTheIssue()
if issueIsStillHere == false {
helpers.CurrentIde.DisableAllCustomPlugins(true)
question := "Repair utility will try to disable custom plugins one-by-one to find the exact one causing the issue, ok?"
options := []string{"y", "n"}
if helpers.ForceAskQuestionWithOptions(question, options) == "y" {
for _, plugin := range helpers.PluginsList {
helpers.CurrentIde.DisablePlugin(plugin)
logger.InfoLogger.Println("Plugin \"" + plugin.Name + "\" has been disabled.")
issueIsStillHere := helpers.CurrentIde.AskUserToRunIdeAndCheckTheIssue()
if issueIsStillHere == false {
logger.InfoLogger.Println("Plugin to blame: " + plugin.Name)
break
} else {
helpers.CurrentIde.EnablePlugin(plugin)
}
}
}
} else {
logger.ConsoleLogger.Println("That means that the problem is not caused by plugins.")
helpers.CurrentIde.DisableAllCustomPlugins(true)
}
}
}
+122
View File
@@ -0,0 +1,122 @@
package cmd
import (
"github.com/spf13/cobra"
"os"
"path/filepath"
"repair/helpers"
"repair/logger"
)
var (
initialArgs []string
ideaBinary string
rootCmd = &cobra.Command{
Use: "repair",
Short: "repair is the utility to check IntelliJ-based IDEs",
Long: `repair is a simple and automated way to fix the IDE when it cannot start.`,
RunE: func(cmd *cobra.Command, args []string) error {
return nil
},
}
)
func init() {
rootCmd.PersistentFlags().StringVar(&ideaBinary, "path", "", "path to the IDE (default is the IDE where the script is located)")
rootCmd.PersistentFlags().BoolVarP(&helpers.YesToAll, "yes", "y", false, "Apply all the suggested fixes automatically")
rootCmd.PersistentFlags().BoolVarP(&logger.DebugEnabled, "debug", "", false, "Enable debug")
rootCmd.PersistentFlags().BoolVarP(&helpers.NoToAll, "no", "n", false, "Only check the installation. All the fixes will be skipped.")
rootCmd.InitDefaultHelpCmd()
if !isHelpPassed() && !isCompareHashesPassed() {
cobra.OnInitialize(initPath)
}
}
func Execute() {
if err := rootCmd.Execute(); err != nil {
logger.ConsoleLogger.Println(err)
os.Exit(1)
}
if !isAspectPassed() && !isHelpPassed() {
logger.InfoLogger.Println("Starting repair utility for all aspects")
runAllAspects()
logger.InfoLogger.Println("Repair utility finished execution.")
if answer := helpers.ForceAskQuestionWithOptions("Is the error still here?", []string{"y", "n"}); answer == "y" {
resetIdeSettingsAndDisableCustomPlugins()
}
}
}
func initPath() {
var err error
if ideaBinary != "" {
passedBinary := ideaBinary
ideaBinary, err = helpers.DetectInstallationByInnerPath(ideaBinary, true)
if err != nil {
logger.ConsoleLogger.Fatal("You passed \"--path\" argument with \"" + passedBinary + "\" value, but there is no IDE binary here.")
}
} else if possibleIdeaBinary, _ := helpers.DetectInstallationByInnerPath(filepath.Dir(os.Args[0]), true); len(possibleIdeaBinary) > 0 {
ideaBinary = possibleIdeaBinary
helpers.CurrentIde.MarkRepairAsBundled()
} else {
ideaBinary, err = helpers.SelectIdeaBinary()
logger.ExitWithExceptionOnError(err)
}
helpers.CurrentIde.SetBinaryToWrokWith(ideaBinary)
}
//returns true if user called repair command with help argument
func isHelpPassed() bool {
for _, argument := range os.Args {
if argument == "help" || argument == "--help" {
return true
}
}
return false
}
func isCompareHashesPassed() bool {
for _, argument := range os.Args {
if argument == "compare" || argument == "--compare" {
return true
}
}
return false
}
//returns true if user called repair command with an aspect
func isAspectPassed() bool {
if len(initialArgs) == 0 {
initialArgs = os.Args
}
for _, argument := range initialArgs {
for _, aspect := range rootCmd.Commands() {
if aspect.Name() == argument {
return true
}
}
}
return false
}
func runAllAspects() {
for _, command := range rootCmd.Commands() {
if command.Name() != "help" {
os.Args = append([]string{os.Args[0], command.Name()})
_, _ = command.ExecuteC()
}
}
}
func resetIdeSettingsAndDisableCustomPlugins() {
pluginsNotice := ""
if len(helpers.CurrentIde.CustomPluginsList().FilterEnabled()) > 0 {
pluginsNotice = " and disable custom plugins"
}
question := "Let's try to restore default settings" + pluginsNotice + " as a last troubleshooting step?"
answer := []string{"y", "n"}
if helpers.AskQuestionWithOptions(question, answer) == "y" {
if len(pluginsNotice) > 0 {
helpers.CurrentIde.DisableAllCustomPlugins(false)
}
logger.InfoLogger.Printf("Restoring default settings...")
helpers.CurrentIde.RemoveConfigurationDirectory()
}
}
+70
View File
@@ -0,0 +1,70 @@
package cmd
import (
"errors"
"github.com/spf13/cobra"
"repair/helpers"
"repair/logger"
)
func init() {
rootCmd.AddCommand(runtimeCmd)
}
var runtimeCmd = &cobra.Command{
Use: "runtime",
Short: "Check the runtime that starts IDE",
Long: "Runtime aspect finds the JDK used to start the IDE and checks if it is OK to use.",
PreRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Runtime aspect started")
},
Run: func(cmd *cobra.Command, args []string) {
RunJbrAspect(args)
},
PostRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("Runtime aspect finished")
},
}
var (
errorsToBeFixed []error
warnings []error
)
func RunJbrAspect(args []string) {
errorsToBeFixed, warnings = []error{}, []error{}
helpers.RuntimeInUse = helpers.RuntimeInfo{}
var err error
helpers.RuntimeInUse, err = helpers.DetectRuntimeInUse(helpers.GetIdeaBinaryToWrokWith())
logger.ExitWithExceptionOnError(err)
logger.DebugLogger.Println(
"Runtime info: \nbinary: " + helpers.RuntimeInUse.BinaryPath +
"\nbinary defined at: " + helpers.RuntimeInUse.BinaryPathDefinedAt +
"\nbinary defined as: " + helpers.RuntimeInUse.BinaryPathDefinedAs +
"\nversion: " + helpers.RuntimeInUse.Version + " (" + helpers.RuntimeInUse.Architecture + " bit)",
)
helpers.CollectErrorsToBeFixed(helpers.RuntimeVersionLessThan17(helpers.RuntimeInUse), &errorsToBeFixed)
helpers.CollectErrorsToBeFixed(helpers.RuntimeArchitectureCorrectness(), &errorsToBeFixed)
helpers.CollectErrorsToBeFixed(helpers.RuntimeIsBundled(), &errorsToBeFixed)
if len(warnings) > 0 {
warn := errors.New("\n" + helpers.FormatCollectedWarnings(warnings))
logger.WarningLogger.Println(warn)
}
if len(errorsToBeFixed) > 0 {
err = errors.New("\n" + helpers.FormatCollectedErrors(errorsToBeFixed))
logger.ErrorLogger.Println(err)
if helpers.IdeHasBundledRuntime(helpers.GetIdeaBinaryToWrokWith()) {
userAccepted := helpers.SuggestResettingRuntime()
if userAccepted {
logger.InfoLogger.Println("Reverting runtime to default")
err = helpers.ResetRuntimeInUse(helpers.RuntimeInUse)
logger.ExitWithExceptionOnError(err)
}
} else {
helpers.SuggestToChangeIdeToOneWithBundledRuntime()
}
}
if len(errorsToBeFixed) == 0 && len(warnings) == 0 {
logger.InfoLogger.Println("Default runtime is in use. No need to take actions.")
}
}
+63
View File
@@ -0,0 +1,63 @@
package cmd
import (
"bytes"
"os"
"repair/helpers"
"repair/logger"
"strings"
"testing"
)
func TestRunJbrAspect(t *testing.T) {
helpers.CurrentIde.SetBinaryToWrokWith(helpers.GetRandomIdeInstallationBinary())
type args struct {
args []string
ideaBinary string
}
tests := []struct {
name string
args args
testJdk helpers.RuntimeInfo
wantErr string
}{
{
name: "runtime8",
args: args{
args: []string{},
},
testJdk: helpers.RuntimeInfo{
BinaryPath: helpers.GetAbsolutePath("../helpers/test_helpers_files/jbr_packages/jbr-1.8/Contents/Home/bin/java"),
BinaryPathDefinedAt: helpers.CurrentIde.GetDefaultConfigurationDirectory() + "idea.jdk",
BinaryPathDefinedAs: helpers.GetAbsolutePath("../helpers/test_helpers_files/jbr_packages/jbr-1.8/"),
Version: "1.8",
Architecture: "64",
IsBundled: false,
},
wantErr: "but recomended version is 11",
}, {
name: "bundledRuntime",
args: args{
args: []string{},
},
testJdk: helpers.RuntimeInfo{
IsBundled: true,
},
wantErr: "false",
},
}
for _, tt := range tests {
helpers.PrepareEnvironent(tt.testJdk)
t.Run(tt.name, func(t *testing.T) {
var buf bytes.Buffer
logger.ErrorLogger.SetOutput(&buf)
RunJbrAspect(tt.args.args)
if tt.wantErr != "false" && !strings.Contains(buf.String(), tt.wantErr) {
t.Errorf("RunJbrAspect() console ouput = %v, wantErr %v", buf.String(), tt.wantErr)
}
})
helpers.ClearEnvironemnt(tt.testJdk)
logger.RemoveLogFile()
logger.ErrorLogger.SetOutput(os.Stdout)
}
}
+36
View File
@@ -0,0 +1,36 @@
package cmd
import (
"github.com/spf13/cobra"
"repair/helpers"
"repair/logger"
)
var restoreVmoptionsFileBool bool
func init() {
rootCmd.AddCommand(vmoptionsCmd)
vmoptionsCmd.PersistentFlags().BoolVarP(&helpers.CheckVmoptionsFileBool, "check", "c", false, "Check .vmoptions file for correctness")
vmoptionsCmd.PersistentFlags().BoolVarP(&restoreVmoptionsFileBool, "restore", "r", false, "Reset .vmoptions file to default")
}
var vmoptionsCmd = &cobra.Command{
Use: "vmoptions",
Short: "Check for problems in .vmoptions file used to start the IDE",
Long: "Vmoptions aspect finds the .vmoptions file used by the IDE and analyzes its content. ",
SilenceUsage: true,
PreRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("VmOptions aspect started")
},
Run: func(cmd *cobra.Command, args []string) {
if restoreVmoptionsFileBool {
logger.ExitWithExceptionOnError(helpers.RestoreVmoptionsFile())
}
helpers.CheckVmoptionsFile()
},
PostRun: func(cmd *cobra.Command, args []string) {
logger.InfoLogger.Println("VmOptions aspect finished")
},
}
@@ -0,0 +1,66 @@
package cmd
import (
"io/ioutil"
"math/rand"
"os"
"repair/helpers"
"repair/logger"
"strings"
"testing"
"time"
)
func TestRunVmoptionAspect(t *testing.T) {
helpers.CurrentIde.SetBinaryToWrokWith(helpers.GetRandomIdeInstallationBinary())
testFiles := map[string]string{
helpers.GetAbsolutePath("../helpers/test_helpers_files/test_vmoptions_files/1.vmoptions"): "More than one Garbage Collector in use",
helpers.GetAbsolutePath("../helpers/test_helpers_files/test_vmoptions_files/2.vmoptions"): "Xmx value (current value 1048m) should be higher than Xms (current value 1228m)",
}
tests := []struct {
name string
wantErr bool
}{
{
name: "Check test .vmoptions files",
wantErr: true,
},
}
for testFile, testError := range testFiles {
createdFile := createTestVmoptionsFileForBinary(helpers.CurrentIde, testFile)
rootCmd.SetArgs([]string{"vmoptions", "--path=" + helpers.GetIdeaBinaryToWrokWith()})
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if err := vmoptionsCmd.Execute(); err != nil {
if !strings.Contains(err.Error(), testError) {
t.Errorf("RunVmoptionAspect() error = %v, wantErr %v", err, tt.wantErr)
}
}
})
}
err := os.Remove(createdFile)
logger.ExitWithExceptionOnError(err)
}
logger.RemoveLogFile()
}
func getRandomVmoptionFilelocation(ide helpers.IDE) (vmOptionsFile string) {
ide.Package = helpers.GetIdeIdePackageByBinary(ide.Binary)
rand.Seed(time.Now().UnixNano())
i := rand.Intn(2)
switch i {
case 1:
return ide.Package + ".vmoptions"
case 0:
return ide.GetConfigurationDirectory() + "idea.vmoptions"
}
return ""
}
func createTestVmoptionsFileForBinary(ide helpers.IDE, testVmoptionsFile string) string {
testVmOptions, err := ioutil.ReadFile(testVmoptionsFile)
file := getRandomVmoptionFilelocation(ide)
err = ioutil.WriteFile(file, testVmOptions, 0644)
logger.ExitWithExceptionOnError(err)
return file
}
+10
View File
@@ -0,0 +1,10 @@
module repair
go 1.18
require github.com/spf13/cobra v1.1.3
require (
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
)
+286
View File
@@ -0,0 +1,286 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+1
View File
@@ -0,0 +1 @@
golang:1.17.2-alpine
@@ -0,0 +1,3 @@
package helpers
var ClearCachesFlag bool
@@ -0,0 +1,27 @@
package helpers
import "strconv"
func FormatCollectedWarnings(warningsToBePrinted []error) string {
return "The following WARNINGS were found: \n" + ConcatErrorsFromSlice(warningsToBePrinted)
}
func FormatCollectedErrors(errorsToBeFixed []error) string {
return "The following ERRORS were found: \n" + ConcatErrorsFromSlice(errorsToBeFixed)
}
func ConcatErrorsFromSlice(errorsToBePrinted []error) (errorText string) {
for i, err := range errorsToBePrinted {
errorText = errorText + (strconv.Itoa(i+1) + ". " + err.Error() + "\n")
}
return errorText
}
func CollectWarnings(warn error, warnings *[]error) {
if warn != nil {
*warnings = append(*warnings, warn)
}
}
func CollectErrorsToBeFixed(err error, errorsToBeFixed *[]error) {
if err != nil {
*errorsToBeFixed = append(*errorsToBeFixed, err)
}
}
@@ -0,0 +1,222 @@
package helpers
import (
"archive/zip"
"fmt"
"io"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"repair/logger"
"runtime"
"strings"
)
// DefaultEditor is vim because we're adults ;)
const DefaultEditor = "vim"
// GetPreferredEditorFromEnvironment returns the user's editor as defined by the
// `$EDITOR` environment variable, or the `DefaultEditor` if it is not set.
func GetPreferredEditorFromEnvironment() string {
editor := os.Getenv("EDITOR")
if editor == "" {
return DefaultEditor
}
return editor
}
func RemoveContentOfDir(dir string) error {
d, err := os.Open(dir)
if err != nil {
return err
}
defer d.Close()
names, err := d.Readdirnames(-1)
if err != nil {
return err
}
for _, name := range names {
err = os.RemoveAll(filepath.Join(dir, name))
if err != nil {
return err
}
}
return nil
}
func RemoveDir(dir string) (err error) {
err = RemoveContentOfDir(dir)
err = os.Remove(dir)
return err
}
func resolveEditorArguments(executable string, filename string) []string {
args := []string{filename}
if strings.Contains(executable, "Visual Studio Code.app") {
args = append([]string{"--wait"}, args...)
}
// Other common editors
return args
}
// OpenFileInEditor opens filename in a text editor.
func OpenFileInEditor(filename string) error {
// Get the full executable path for the editor.
executable, err := exec.LookPath(GetPreferredEditorFromEnvironment())
if err != nil {
return err
}
cmd := exec.Command(executable, resolveEditorArguments(executable, filename)...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
func WriteToFile(str string, filename string) {
f, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
logger.ExitWithExceptionOnError(err)
_, err = f.WriteString("\n" + str + "\n")
logger.ExitWithExceptionOnError(err)
defer f.Close()
}
func RemoveFromFile(str string, filename string) error {
read, err := ioutil.ReadFile(filename)
logger.ExitWithExceptionOnError(err)
newContents := strings.Replace(string(read), str, "", -1)
err = ioutil.WriteFile(filename, []byte(newContents), 0)
logger.ExitWithExceptionOnError(err)
return nil
}
func MoveFile(src, dst string) error {
sourceFileStat, err := os.Stat(src)
if err != nil {
return err
}
if !sourceFileStat.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file", src)
}
source, err := os.Open(src)
if err != nil {
return err
}
source.Close()
destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()
_, err = io.Copy(destination, source)
err = os.Remove(source.Name())
return err
}
func Unzip(src, dest string) error {
r, err := zip.OpenReader(src)
if err != nil {
return err
}
defer func() {
if err := r.Close(); err != nil {
panic(err)
}
}()
_ = os.MkdirAll(dest, 0755)
// Closure to address file descriptors issue with all the deferred .Close() methods
extractAndWriteFile := func(f *zip.File) error {
rc, err := f.Open()
if err != nil {
return err
}
defer func() {
if err := rc.Close(); err != nil {
panic(err)
}
}()
path := filepath.Join(dest, f.Name)
// Check for ZipSlip (Directory traversal)
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
return fmt.Errorf("illegal file path: %s", path)
}
if f.FileInfo().IsDir() {
err = os.MkdirAll(path, f.Mode())
logger.ExitWithExceptionOnError(err)
} else {
err = os.MkdirAll(filepath.Dir(path), 0755)
logger.ExitWithExceptionOnError(err)
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
defer func() {
if err := f.Close(); err != nil {
panic(err)
}
}()
_, err = io.Copy(f, rc)
if err != nil {
return err
}
}
return nil
}
for _, f := range r.File {
err := extractAndWriteFile(f)
if err != nil {
return err
}
}
return nil
}
func FileExists(dir string) bool {
//dir = filepath.Clean(dir)
if _, err := os.Open(dir); err == nil && len(dir) > 2 {
return true
}
return false
}
func getFrame(skipFrames int) runtime.Frame {
targetFrameIndex := skipFrames + 2
programCounters := make([]uintptr, targetFrameIndex+2)
n := runtime.Callers(0, programCounters)
frame := runtime.Frame{Function: "unknown"}
if n > 0 {
frames := runtime.CallersFrames(programCounters[:n])
for more, frameIndex := true, 0; more && frameIndex <= targetFrameIndex; frameIndex++ {
var frameCandidate runtime.Frame
frameCandidate, more = frames.Next()
if frameIndex == targetFrameIndex {
frame = frameCandidate
}
}
}
return frame
}
// GetCallerFunction returns the name of function - caller.
func GetCallerFunction() string {
// Skip GetCallerFunctionName and the function to get the caller of
return getFrame(2).Function
}
func (ide *IDE) RemoveConfigurationDirectory() {
configDir := ide.GetConfigurationDirectory()
if FileExists(configDir) {
if FileExists(configDir + ".old") {
logger.WarningLogger.Printf("Backup of configuration directory (%s) already exists. ", configDir)
if ForceAskQuestionWithOptions("Overwrite it?", []string{"y", "n"}) == "y" {
RemoveContentOfDir(strings.TrimSuffix(configDir, "/") + ".old")
os.Remove(strings.TrimSuffix(configDir, "/") + ".old")
}
}
err := os.Rename(configDir, strings.TrimSuffix(configDir, "/")+".old")
logger.ExitWithExceptionOnError(err)
}
logger.InfoLogger.Printf("Configuration directory %s been moved to %s.old", configDir, configDir[:len(configDir)])
}
@@ -0,0 +1,361 @@
package helpers
import (
"bufio"
"encoding/json"
"errors"
"io/ioutil"
"os"
"path/filepath"
"repair/logger"
"runtime"
"runtime/debug"
"strings"
)
type IntallationInfoLaunchInner struct {
Os string
JavaExecutablePath string
}
func (ide *IDE) GetConfigurationDirectory() (configDir string) {
configDir = ide.GetProperty("idea.config.path")
if len(configDir) == 0 {
configDir = ide.GetDefaultConfigurationDirectory()
}
if _, err := os.Create(configDir + "/test.tmp"); err == nil {
_ = os.Remove(configDir + "/test.tmp")
return filepath.Clean(configDir) + string(os.PathSeparator)
} else if FileExists(configDir) {
logger.ExitOnError(errors.New("Could not open configuration directory for writing \"" + configDir + "\". IDE requires writable directory to work"))
} else {
logger.ExitOnError(errors.New("Could not find IDE configuration directory. Most probably, this IDE has not been started yet."))
}
return ""
}
func (ide *IDE) GetDefaultConfigurationDirectory() (defaultConfigDir string) {
installationInfo := ide.GetInfo()
defaultConfigDir = strings.Replace(defaultConfigDirLocation[runtime.GOOS], "{dataDirectoryName}", installationInfo.DataDirectoryName, -1)
defaultConfigDir = os.ExpandEnv(defaultConfigDir)
return filepath.Clean(defaultConfigDir) + string(os.PathSeparator)
}
func (ide *IDE) GetIdeCustomPluginsDirectory() (pluginsDir string) {
if len(ide.GetProperty("idea.plugins.path")) > 1 {
pluginsDir = ide.GetProperty("idea.plugins.path")
} else if len(GetIdeVmoptionByName("-Didea.plugins.path")) > 1 {
pluginsDir = GetIdeVmoptionByName("-Didea.plugins.path")
} else {
pluginsDir = ide.GetConfigurationDirectory() + "plugins"
}
return filepath.Clean(pluginsDir) + string(os.PathSeparator)
}
func (ide *IDE) GetSystemDirectory() (systemDir string) {
if len(ide.GetProperty("idea.system.path")) > 1 {
systemDir = ide.GetProperty("idea.system.path")
} else if len(GetIdeVmoptionByName("-Didea.system.path")) > 1 {
systemDir = GetIdeVmoptionByName("-Didea.system.path")
} else {
systemDir = GetIdeDefaultSystemDir(ide.Binary)
}
return filepath.Clean(systemDir) + string(os.PathSeparator)
}
func GetIdeBundledPluginsDirectory(ideaBinary string) string {
return strings.Replace(defaultBundledPluginsDirLocation[runtime.GOOS], "{ideaPackage}", GetIdeIdePackageByBinary(ideaBinary), -1)
}
func GetIdeDefaultSystemDir(ideaBinary string) (defaultSystemDir string) {
installationInfo, err := GetIdeInfoByBinary(ideaBinary)
logger.ExitWithExceptionOnError(err)
defaultSystemDir = strings.Replace(defaultSystemDirLocation[runtime.GOOS], "{dataDirectoryName}", installationInfo.DataDirectoryName, -1)
defaultSystemDir = os.ExpandEnv(defaultSystemDir)
return filepath.Clean(defaultSystemDir) + string(os.PathSeparator)
}
func (ide *IDE) GetProperty(name string) (value string) {
if len(ide.Binary) < 1 {
logger.ExitWithExceptionOnError(errors.New("Trying to analyze undefined installation"))
}
if len(IdePropertiesMap) == 0 {
IdePropertiesMap = GetIdeProperties(ide.Binary)
}
if _, ok := IdePropertiesMap[name]; ok {
return IdePropertiesMap[name]
}
return ""
}
func GetIdePropertyByName(name string, ideaBinary string) (value string) {
if len(IdePropertiesMap) == 0 {
IdePropertiesMap = GetIdeProperties(ideaBinary)
}
if _, ok := IdePropertiesMap[name]; ok {
return IdePropertiesMap[name]
}
return ""
}
func GetIdeBasefileName(ideaBinary string) string {
for _, possibleBaseFileName := range possibleBaseFileNames {
if strings.HasSuffix(ideaBinary, possibleBaseFileName) {
return possibleBaseFileName
}
}
return ""
}
func GetIdeVmoptionByName(optionName string) (value string) {
vmOptionsFile, err := GetVmOptionsFile()
if err != nil {
return ""
}
vmOptionsAsSlice := GetVmoptionsAsSlice(vmOptionsFile)
return vmOptionsAsSlice[optionName]
}
//fixme: java properties (as ${user.home} could not be extended)
//possible solution is to call java binary to print list of resolved system properties.
func (ide *IDE) GetProperties() (collectedOptions map[string]string) {
if len(ide.Binary) < 1 {
logger.ExitWithExceptionOnError(errors.New("Trying to get properties of undefined IDE"))
}
var err error
var ideaPackage string
collectedOptions = make(map[string]string)
ide.Binary, err = DetectInstallationByInnerPath(ide.Binary, true)
ideaPackage, err = DetectInstallationByInnerPath(ide.Binary, false)
InstallationInfo, err = GetIdeInfoByBinary(ide.Binary)
logger.ExitWithExceptionOnError(err)
for _, possibleIdeaPropertiesFileLocation := range getOsDependentDir(possibleIdeaPropertiesFileLocations) {
possibleIdeaOptionsFile := strings.Replace(possibleIdeaPropertiesFileLocation, "{IDE_BasefileName}", strings.ToUpper(GetIdeBasefileName(ide.Binary)), -1)
possibleIdeaOptionsFile = strings.Replace(possibleIdeaOptionsFile, "{dataDirectoryName}", InstallationInfo.DataDirectoryName, -1)
possibleIdeaOptionsFile = strings.Replace(possibleIdeaOptionsFile, "{ideaPackage}", ideaPackage, -1)
possibleIdeaOptionsFile = os.ExpandEnv(possibleIdeaOptionsFile)
if FileExists(possibleIdeaOptionsFile) {
logger.DebugLogger.Println("found idea.properties file at: \"" + possibleIdeaOptionsFile + "\"")
fillIdePropertiesMap(possibleIdeaOptionsFile, collectedOptions)
} else {
logger.DebugLogger.Println("Checked " + possibleIdeaPropertiesFileLocation + ". There is no \"" + possibleIdeaOptionsFile + "\" file.")
}
}
var listOfCollectedOptions string
for option, value := range collectedOptions {
listOfCollectedOptions = listOfCollectedOptions + option + "=" + value + "\n"
}
logger.DebugLogger.Println("Collected idea properties:\n" + listOfCollectedOptions)
return collectedOptions
}
func GetIdeProperties(ideaBinary string) (collectedOptions map[string]string) {
var err error
var ideaPackage string
collectedOptions = make(map[string]string)
ideaBinary, err = DetectInstallationByInnerPath(ideaBinary, true)
ideaPackage, err = DetectInstallationByInnerPath(ideaBinary, false)
InstallationInfo, err = GetIdeInfoByBinary(ideaBinary)
logger.ExitWithExceptionOnError(err)
for _, possibleIdeaPropertiesFileLocation := range getOsDependentDir(possibleIdeaPropertiesFileLocations) {
possibleIdeaOptionsFile := strings.Replace(possibleIdeaPropertiesFileLocation, "{IDE_BasefileName}", strings.ToUpper(GetIdeBasefileName(ideaBinary)), -1)
possibleIdeaOptionsFile = strings.Replace(possibleIdeaOptionsFile, "{dataDirectoryName}", InstallationInfo.DataDirectoryName, -1)
possibleIdeaOptionsFile = strings.Replace(possibleIdeaOptionsFile, "{ideaPackage}", ideaPackage, -1)
possibleIdeaOptionsFile = os.ExpandEnv(possibleIdeaOptionsFile)
if FileExists(possibleIdeaOptionsFile) {
logger.DebugLogger.Println("found idea.properties file at: \"" + possibleIdeaOptionsFile + "\"")
fillIdePropertiesMap(possibleIdeaOptionsFile, collectedOptions)
} else {
logger.DebugLogger.Println("Checked " + possibleIdeaPropertiesFileLocation + ". There is no \"" + possibleIdeaOptionsFile + "\" file.")
}
}
var listOfCollectedOptions string
for option, value := range collectedOptions {
listOfCollectedOptions = listOfCollectedOptions + option + "=" + value + "\n"
}
logger.DebugLogger.Println("Collected idea properties:\n" + listOfCollectedOptions)
return collectedOptions
}
func getOsDependentDir(fromVariable map[string][]string) []string {
if len(fromVariable[runtime.GOOS]) > 0 {
return fromVariable[runtime.GOOS]
}
logger.ExitWithExceptionOnError(errors.New("This OS is not yet supported"))
return nil
}
func fillIdePropertiesMap(ideaOptionsFile string, optionsMap map[string]string) {
optionsSlice, err := ideaPropertiesFileToSliceOfStrings(ideaOptionsFile)
logger.ExitWithExceptionOnError(err)
for _, option := range optionsSlice {
if idx := strings.IndexByte(option, '='); idx >= 0 {
optionValue := option[idx+1:]
optionValue = os.ExpandEnv(optionValue)
optionName := option[:idx]
if _, exist := optionsMap[optionName]; !exist {
optionsMap[optionName] = optionValue
}
}
}
}
func ideaPropertiesFileToSliceOfStrings(ideaPropertiesFile string) (properties []string, err error) {
file, err := os.Open(ideaPropertiesFile)
logger.ExitWithExceptionOnError(err)
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var i int
for scanner.Scan() {
i++
option := scanner.Text()
if len(option) != 0 {
if option[0] == '#' {
} else {
properties = append(properties, option)
}
}
}
err = file.Close()
if err != nil {
return nil, err
}
return properties, err
}
func GetIdeInfoByPackage(ideaPackage string) (parameterValue IdeInfo, err error) {
var a IdeInfo
var fileContent []byte
fileContent, err = ioutil.ReadFile(ideaPackage + IdeProductInfoRelatedToInstallationPath[runtime.GOOS])
if err != nil {
for os, path := range IdeProductInfoRelatedToInstallationPath {
if content, er := ioutil.ReadFile(ideaPackage + path); er == nil {
fileContent = content
logger.WarningLogger.Printf("Could not find product-info.json for %s, but found it for %s ", runtime.GOOS, os)
}
}
}
err = json.Unmarshal(fileContent, &a)
return a, err
}
func GetIdeInfoByBinary(ideaBinary string) (parameterValue IdeInfo, err error) {
return GetIdeInfoByPackage(GetIdeIdePackageByBinary(ideaBinary))
}
//GetIdeBinaryByPackage return the location of idea(idea.exe) executable inside the IDE installation folder.
//if ideaPackage == /Users/konstantin.annikov/Downloads/IntelliJ IDEA.app
//then idaBinary == /Users/konstantin.annikov/Downloads/IntelliJ IDEA.app/Contents/MacOS/idea
func GetIdeBinaryByPackage(ideaPackage string) (ideaBinary string, err error) {
if len(CurrentIde.Binary) == 0 {
logger.DebugLogger.Printf("detecting IDE binary by package. %s is being checked. Stack is: %s", ideaPackage, string(debug.Stack()))
logger.DebugLogger.Printf("Binaries to check: %s", possibleBaseFileNames)
}
for _, possibleBaseFileName := range possibleBaseFileNames {
for operatingSystem, path := range IdeBinaryRelatedToInstallationPath {
currentBinaryToCheck := strings.Replace(path, "{possibleBaseFileName}", possibleBaseFileName, -1)
ideaBinary = ideaPackage + currentBinaryToCheck
if len(CurrentIde.Binary) == 0 {
logger.DebugLogger.Printf("IDE binary to check: %s", ideaBinary)
}
if FileExists(ideaBinary) {
if operatingSystem != runtime.GOOS {
logger.WarningLogger.Printf("Provided path is for %s, but repair utility is running at %s ", operatingSystem, runtime.GOOS)
}
if len(CurrentIde.Binary) == 0 {
logger.DebugLogger.Printf("Found %s binary at %s", ideaBinary, ideaPackage)
}
return filepath.Clean(ideaBinary), nil
}
_, err := os.Open(ideaBinary)
if len(CurrentIde.Binary) == 0 {
logger.DebugLogger.Printf("%s file does not exist, error: %s", ideaBinary, string(err.Error()))
}
}
}
return "", errors.New("Could not detect IDE binary in " + ideaPackage)
}
func GetIdePackageToWorkWith(ideaBinary string) (ideaPackage string) {
if len(ideaPackageToWorkWith) > 0 {
return ideaPackageToWorkWith
} else {
return GetIdeIdePackageByBinary(ideaBinary)
}
}
func GetIdeIdePackageByBinary(ideaBinary string) (ideaPackage string) {
var err error
if ideaPackageToWorkWith, err = DetectInstallationByInnerPath(ideaBinary, false); err == nil {
return ideaPackageToWorkWith
} else {
logger.ErrorLogger.Println("Could not get detect ide installation path by binary " + ideaBinary)
return ""
}
}
//If any part of providedPath is IDE installation path, DetectInstallationByInnerPath returns path or binary (based on returnBinary flag)
func DetectInstallationByInnerPath(providedPath string, returnBinary bool) (ideaBinary string, err error) {
providedPath = filepath.Clean(providedPath)
providedDeep := strings.Count(providedPath, string(os.PathSeparator))
basePath := providedPath
for i := 1; i < providedDeep; i++ {
if ideaBinary, err := GetIdeBinaryByPackage(basePath); err == nil {
if returnBinary {
return ideaBinary, nil
} else {
return basePath, nil
}
}
basePath = filepath.Dir(basePath)
}
return "", errors.New("Could not detect IDE by \"" + providedPath + "\" path")
}
func GetIdeaLogPath(ideaBinary string) (ideaLogPath string) {
if GetIdeDefaultLogsDir(ideaBinary) != "" {
return GetIdeDefaultLogsDir(ideaBinary) + "idea.log"
} else {
return ""
}
}
func GetIdeDefaultLogsDir(ideaBinary string) (defaultLogsDir string) {
if value := GetIdePropertyByName("idea.log.path", ideaBinary); len(value) != 0 {
if FileExists(value) {
return value
} else {
logger.FatalLogger.Fatal("'idea.log.path' property is defined, but directory does not exist")
}
}
installationInfo, err := GetIdeInfoByBinary(ideaBinary)
logger.ExitWithExceptionOnError(err)
defaultLogsDir = strings.Replace(defaultLogsDirLocation[runtime.GOOS], "{dataDirectoryName}", installationInfo.DataDirectoryName, -1)
defaultLogsDir = os.ExpandEnv(defaultLogsDir)
if FileExists(defaultLogsDir) {
return defaultLogsDir
} else {
logger.InfoLogger.Println(errors.New("Could not detect logs directory location"))
return ""
}
}
func GetVmOptionsFile() (string, error) {
if len(vmOptionsFile) > 0 {
return vmOptionsFile, nil
} else {
ideaBinary := CurrentIde.Binary
for _, possibleVmOptionsLocation := range possibleVmOptionsFileLocation[runtime.GOOS] {
possibleVmOptionsFile := os.ExpandEnv(possibleVmOptionsLocation)
possibleVmOptionsFile = strings.Replace(possibleVmOptionsFile, "{ideaPackage}", GetIdeIdePackageByBinary(ideaBinary), -1)
possibleVmOptionsFile = strings.Replace(possibleVmOptionsFile, "{IdeConfigDir}", CurrentIde.GetConfigurationDirectory(), -1)
possibleVmOptionsFile = strings.Replace(possibleVmOptionsFile, "{IDE_BaseFilename}", GetIdeBasefileName(GetIdeaBinaryToWrokWith()), -1)
if FileExists(possibleVmOptionsFile) {
logger.DebugLogger.Println(".vmoptions file to work with: \"" + possibleVmOptionsFile + "\"")
vmOptionsFile = possibleVmOptionsFile
return possibleVmOptionsFile, nil
} else {
logger.DebugLogger.Println("Checked " + possibleVmOptionsLocation + ". There is no \"" + possibleVmOptionsFile + "\" file. Next location to check: ")
}
}
err := errors.New("Couldn't detect custom .vmoptions file for " + ideaBinary + "\nThere is nothing to do with vmoptions aspect.")
return "", err
}
}
@@ -0,0 +1,72 @@
package helpers
import (
"repair/logger"
"runtime"
"testing"
)
func TestDetectInstallationByInnerPath(t *testing.T) {
ideaPackage, err := GetRandomIdeInstallationPackage()
ideaBinary, err := GetIdeBinaryByPackage(ideaPackage)
logger.ExitWithExceptionOnError(err)
type args struct {
providedPath string
returnBinary bool
}
tests := []struct {
name string
args args
wantIdeaBinary string
wantErr bool
}{
{
name: "detect binary by package name",
args: args{ideaPackage, true},
wantIdeaBinary: ideaBinary,
wantErr: false,
}, {
name: "detect package by binary name",
args: args{ideaBinary, false},
wantIdeaBinary: ideaPackage,
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotIdeaBinary, err := DetectInstallationByInnerPath(tt.args.providedPath, tt.args.returnBinary)
if (err != nil) != tt.wantErr {
t.Errorf("DetectInstallationByInnerPath() error = %v, wantErr %v", err, tt.wantErr)
return
}
if gotIdeaBinary != tt.wantIdeaBinary {
t.Errorf("DetectInstallationByInnerPath() gotIdeaBinary = %v, want %v", gotIdeaBinary, tt.wantIdeaBinary)
}
})
}
}
func TestGetIdeInstallationPathByBinary(t *testing.T) {
gotPossible_binaries, _ := FindInstalledIdePackages()
type args struct {
ideaBinary string
}
tests := []struct {
name string
args args
wantIdeaPackage string
}{
{
name: "",
args: args{gotPossible_binaries[0] + IdeBinaryRelatedToInstallationPath[runtime.GOOS]},
wantIdeaPackage: gotPossible_binaries[0],
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if gotIdeaPackage := GetIdeIdePackageByBinary(tt.args.ideaBinary); gotIdeaPackage != tt.wantIdeaPackage {
t.Errorf("GetIdeInstallationPathByBinary() = %v, want %v", gotIdeaPackage, tt.wantIdeaPackage)
}
})
}
}
@@ -0,0 +1,150 @@
package helpers
import (
"errors"
"os"
"repair/logger"
"runtime"
)
var (
PluginsList PluginInfoList
CustomPluginsList PluginInfoList
LogEntries []LogEntry
InstallationInfo IdeInfo
ideaPackageToWorkWith string
ideaBinaryToWorkWith string
CurrentIde IDE
RuntimeInUse RuntimeInfo
vmOptionsFile string
)
//Deprecated: use CurrentIde.Binary instead
func GetIdeaBinaryToWrokWith() string {
if len(CurrentIde.Binary) > 0 {
return CurrentIde.Binary
} else {
logger.ExitWithExceptionOnError(errors.New("There is no idea binary to work with"))
return ""
}
}
func UserHomeDir() string {
if runtime.GOOS == "windows" {
home := os.Getenv("HOMEDRIVE") + os.Getenv("HOMEPATH")
if home == "" {
home = os.Getenv("USERPROFILE")
}
return home
}
return os.Getenv("HOME")
}
//OS-dependent constants
var (
EmbeededDownloadUrl = ""
downloadsURL = "https://download.jetbrains.com"
ManifestFilesExclusions = map[string][]string{
"darwin": {},
"linux": {},
"windows": {".feed", ".symlink", "bin/Uninstall.exe.nsis"},
}
archiveExtension = map[string]string{
"darwin": ".dmg",
"linux": ".tar.gz",
"windows": ".exe",
}
possibleBaseFileNames = []string{"appcode", "clion", "datagrip", "dataspell", "goland", "idea", "phpstorm", "pycharm", "rubymine", "webstorm", "rider", "Draft", "aqua"}
possibleBinariesPaths = map[string][]string{
"darwin": {"/Applications/*.app/Contents/MacOS/{possibleBaseFileName}", "$HOME/Library/Application Support/JetBrains/Toolbox/apps/*/ch-*/*/*.app/Contents/MacOS/{possibleBaseFileName}"},
"linux": {"$HOME/.local/share/JetBrains/Toolbox/apps/*/ch-*/*/bin/{possibleBaseFileName}.sh"},
"windows": {os.Getenv("HOMEDRIVE") + "/Program Files/JetBrains/*" + IdeBinaryRelatedToInstallationPath["windows"], os.Getenv("LOCALAPPDATA") + "/JetBrains/Toolbox/apps/*/ch-*/*" + IdeBinaryRelatedToInstallationPath["windows"]},
}
IdeBinaryRelatedToInstallationPath = map[string]string{
"darwin": "/Contents/MacOS/{possibleBaseFileName}",
"linux": "/bin/{possibleBaseFileName}.sh",
"windows": "/bin/{possibleBaseFileName}64.exe",
}
IdeProductInfoRelatedToInstallationPath = map[string]string{
"darwin": "/Contents/Resources/product-info.json",
"linux": "/product-info.json",
"windows": "/product-info.json",
}
possibleIdeaPropertiesFileLocations = map[string][]string{
"darwin": {"${IDE_BasefileName}_PROPERTIES", UserHomeDir() + "/Library/Application Support/JetBrains/{dataDirectoryName}/idea.properties", UserHomeDir() + "/idea.properties", "{ideaPackage}/Contents/bin/idea.properties"},
"linux": {"${IDE_BasefileName}_PROPERTIES", UserHomeDir() + "/.config/JetBrains/{dataDirectoryName}/idea.properties", UserHomeDir() + "/idea.properties", "{ideaPackage}/bin/idea.properties"},
"windows": {"${IDE_BasefileName}_PROPERTIES", defaultSystemDirLocation[runtime.GOOS] + "/idea.properties", UserHomeDir() + "/idea.properties", "{ideaPackage}/bin/idea.properties"},
}
IdeRuntimeBinaryRelatedToInstallationPath = map[string]string{
"darwin": "/Contents/jbr/Contents/Home/bin/java",
"linux": "/jbr/bin/java",
"windows": "/jbr/bin/java.exe",
}
possibleRuntimeVariables = map[string][]string{
"darwin": {"${IDE_BASEFILENAME}_JDK"},
"linux": {"${IDE_BASEFILENAME}_JDK"},
"windows": {"${IDE_BASEFILENAME}_JDK_64"},
}
possibleRuntimeConfiguraitonFileLocations = map[string][]string{
"darwin": {"{IdeConfigDir}/{IDE_BaseFilename}.jdk"},
"linux": {"{IdeConfigDir}/{IDE_BaseFilename}.jdk"},
"windows": {"{IdeConfigDir}/{IDE_BaseFilename}64.exe.jdk"},
}
defaultLogsDirLocation = map[string]string{
"darwin": UserHomeDir() + "/Library/Logs/JetBrains/{dataDirectoryName}/",
"linux": UserHomeDir() + "/.cache/JetBrains/{dataDirectoryName}/log/",
"windows": os.Getenv("LOCALAPPDATA") + "/JetBrains/{dataDirectoryName}/log/",
}
defaultSystemDirLocation = map[string]string{
"darwin": "${HOME}/Library/Caches/JetBrains/{dataDirectoryName}/",
"linux": "${HOME}/.cache/JetBrains/{dataDirectoryName}/",
"windows": os.Getenv("LOCALAPPDATA") + "/JetBrains/{dataDirectoryName}/",
}
defaultConfigDirLocation = map[string]string{
"darwin": "${HOME}/Library/Application Support/JetBrains/{dataDirectoryName}/",
"linux": "${HOME}/.config/JetBrains/{dataDirectoryName}/",
"windows": os.Getenv("APPDATA") + "/JetBrains/{dataDirectoryName}/",
}
defaultBundledPluginsDirLocation = map[string]string{
"darwin": "{ideaPackage}/Contents/plugins",
"linux": "{ideaPackage}/plugins",
"windows": "{ideaPackage}/plugins",
}
//possibleVmOptionsFileLocation is the *ordered* list where .vmoptions files could be located
possibleVmOptionsFileLocation = map[string][]string{
"darwin": {"$IDEA_VM_OPTIONS", "{ideaPackage}.vmoptions", "{IdeConfigDir}/idea.vmoptions"},
"linux": {"$IDEA_VM_OPTIONS", "{ideaPackage}.vmoptions", "{IdeConfigDir}/idea.vmoptions"},
"windows": {"$IDEA64_VM_OPTIONS", "{ideaPackage}/bin/{IDE_BaseFilename}64.exe.vmoptions"},
}
IdePropertiesMap = map[string]string{}
)
type LogEntry struct {
DateAndTime string
TimeSinceStart string
Severity string
Class string
Header string
Body string
}
type PluginInfo struct {
Id string `xml:"id"`
Name string `xml:"name"`
Version string `xml:"version"`
Vendor string `xml:"vendor"`
MainJarPath string
PluginXmlId string
MarketplaceId int
IsDisabled bool
IdeaVersion IdeaVersion `xml:"idea-version"`
isBundled bool
IsDeprecated bool
}
type PluginInfoList []PluginInfo
type RuntimeInfo struct {
BinaryPath string
BinaryPathDefinedAt string
BinaryPathDefinedAs string
Version string
Architecture string
IsBundled bool
}
@@ -0,0 +1,318 @@
package helpers
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"hash/crc32"
"io"
"io/ioutil"
"net/http"
"os"
"path/filepath"
"repair/logger"
"runtime"
"strconv"
"strings"
"sync"
"time"
)
var (
GenerateHashesFlag bool
CheckHashesFlag bool
CompareHashesFlag bool
CompareHashesFile1 string
CompareHashesFile2 string
Algorithms []string
HashesOutputFile string
)
type fileInfo struct {
Path string `json:"Path"`
Size int64 `json:"Size,omitempty"`
SymlinkTo string `json:"SymlinkTo,omitempty"`
Mode os.FileMode `json:"Mode,omitempty"`
ModificationTime *time.Time `json:"ModificationTime,omitempty"`
Hashes map[string]string `json:"Hashes,omitempty"`
}
type hashesDiffMap map[string][]string
type manifestDiffStruct struct {
MissingLocalFiles []string
RedundantLocalFiles []string
HashesDiff hashesDiffMap
}
type manifestInstallationInfo struct {
Name string
Version string
BuildNumber string
ProductCode string
}
type ManifestStruct struct {
InstallationInfo manifestInstallationInfo
FilesInfo []fileInfo
}
var installationFilesWitHashes []fileInfo
var manifest ManifestStruct
func GetManifestStruct() ManifestStruct {
if len(manifest.FilesInfo) > 0 {
return manifest
} else {
return GenerateMainfest()
}
}
func GetInstallationFilesWithHashes() []fileInfo {
if len(installationFilesWitHashes) > 0 {
return installationFilesWitHashes
} else {
return GenerateFilesInfo()
}
}
func GenerateMainfest() (manifestAsStruct ManifestStruct) {
manifestAsStruct.FilesInfo = GetInstallationFilesWithHashes()
installationInfo := CurrentIde.GetInfo()
manifestAsStruct.InstallationInfo.Name = installationInfo.Name
manifestAsStruct.InstallationInfo.Version = installationInfo.Version
manifestAsStruct.InstallationInfo.BuildNumber = installationInfo.BuildNumber
manifestAsStruct.InstallationInfo.ProductCode = installationInfo.ProductCode
return manifestAsStruct
}
func GenerateMainfestFile() {
logger.ConsoleLogger.Println("hashes are being generated...")
filesInfoAsBytes := convertAnyToJson(GetManifestStruct())
if FileExists(HashesOutputFile) {
_ = os.Remove(HashesOutputFile)
}
WriteToFile(string(filesInfoAsBytes), HashesOutputFile)
}
func CompareHashes() {
file1, _ := ioutil.ReadFile(CompareHashesFile1)
file2, _ := ioutil.ReadFile(CompareHashesFile2)
manifestStruct1 := convertJsonToSlice(file1)
manifestStruct2 := convertJsonToSlice(file2)
if manifestDiff, err := compareManifests(manifestStruct1, manifestStruct2); err == nil {
if len(manifestDiff.HashesDiff) > 0 || len(manifestDiff.MissingLocalFiles) > 0 || len(manifestDiff.RedundantLocalFiles) > 0 {
if len(manifestDiff.HashesDiff) > 0 {
logger.DebugLogger.Println(string(convertAnyToJson(manifestDiff)))
logger.ErrorLogger.Println("Hashes for the following files do not match:" + sliceAsString(manifestDiff.HashesDiff.getFilesSlice()))
}
if len(manifestDiff.MissingLocalFiles) > 0 {
logger.ErrorLogger.Println(CompareHashesFile2 + " missing the following: " + sliceAsString(manifestDiff.MissingLocalFiles))
}
if len(manifestDiff.RedundantLocalFiles) > 0 {
logger.ErrorLogger.Println(CompareHashesFile1 + " missing the following: " + sliceAsString(manifestDiff.RedundantLocalFiles))
}
} else {
logger.InfoLogger.Println("No illegal files found")
}
} else {
logger.ErrorLogger.Println(err)
}
}
func CheckHashes() {
logger.InfoLogger.Println("Downloading manifest file")
manifestJson, err := downloadManifest(CurrentIde)
if err != nil {
logger.WarningLogger.Printf("Unable to download manifest file from %s: \n\t %s", generateManifestUrl(CurrentIde), err.Error())
return
} else {
logger.DebugLogger.Printf("Downloaded manifest from %s", generateManifestUrl(CurrentIde))
}
manifestStruct := convertJsonToSlice(manifestJson)
logger.InfoLogger.Println("Hashes are being checked")
if manifestDiff, err := compareManifests(manifestStruct, GetManifestStruct()); err == nil {
if len(manifestDiff.HashesDiff) > 0 {
logger.DebugLogger.Println(string(convertAnyToJson(manifestDiff)))
logger.ErrorLogger.Println("Hashes for the following files does not match the hashes generated by JetBrains:" + sliceAsString(manifestDiff.HashesDiff.getFilesSlice()))
AskUserToDownloadFreshInstallation()
} else if len(manifestDiff.MissingLocalFiles) > 0 {
logger.ErrorLogger.Println("The following files were not found in the installation:" + sliceAsString(manifestDiff.MissingLocalFiles))
} else if len(manifestDiff.RedundantLocalFiles) > 0 {
logger.WarningLogger.Println("Installation directory contains files which aren’t part of distribution:" + sliceAsString(manifestDiff.RedundantLocalFiles))
AskUserAndRemoveFiles(manifestDiff.RedundantLocalFiles)
} else {
logger.InfoLogger.Println("No illegal files found")
}
} else {
logger.ErrorLogger.Println(err)
}
}
func (m *hashesDiffMap) getFilesSlice() (slice []string) {
for i := range *m {
slice = append(slice, i)
}
return slice
}
func sliceAsString(slice []string) (sliceAsList string) {
for _, sliceElement := range slice {
sliceAsList = sliceAsList + "\n\t" + sliceElement
}
return sliceAsList
}
func compareManifests(remoteManifestStruct ManifestStruct, localManifestStruct ManifestStruct) (manifestDiffStruct, error) {
if !CheckIfManifestBalongsToInstallation(remoteManifestStruct.InstallationInfo, localManifestStruct.InstallationInfo) {
return manifestDiffStruct{}, errors.New("Manifest file does not belong to the local installation.")
}
var diff manifestDiffStruct
diff.HashesDiff = make(map[string][]string)
for i := 0; i < 2; i++ {
for _, remoteFile := range remoteManifestStruct.FilesInfo {
found := false
for _, localFile := range localManifestStruct.FilesInfo {
if remoteFile.Path == localFile.Path {
found = true
for alg := range remoteFile.Hashes {
if remoteFile.Hashes[alg] != localFile.Hashes[alg] && !(len(diff.HashesDiff[remoteFile.Path]) != 0) {
diff.HashesDiff[remoteFile.Path] = []string{remoteFile.Hashes[alg], localFile.Hashes[alg]}
}
}
break
}
}
if !found && !sliceOfStringsContains(ManifestFilesExclusions[runtime.GOOS], remoteFile.Path) {
diff.RedundantLocalFiles = append(diff.RedundantLocalFiles, remoteFile.Path)
}
}
if i == 0 {
remoteManifestStruct, localManifestStruct = localManifestStruct, remoteManifestStruct
diff.MissingLocalFiles, diff.RedundantLocalFiles = diff.RedundantLocalFiles, diff.MissingLocalFiles
}
}
return diff, nil
}
func CheckIfManifestBalongsToInstallation(remoteInfo manifestInstallationInfo, localInfo manifestInstallationInfo) bool {
if remoteInfo.BuildNumber == localInfo.BuildNumber {
return true
}
logger.InfoLogger.Println(remoteInfo.BuildNumber + "!=" + localInfo.BuildNumber)
return false
}
func convertJsonToSlice(manifestJson []byte) (manifest ManifestStruct) {
err := json.Unmarshal(manifestJson, &manifest)
if err == nil {
return manifest
}
logger.WarningLogger.Println("Error reading manifest file: " + err.Error())
return ManifestStruct{}
}
func downloadManifest(ide IDE) (json []byte, err error) {
if resp, err := http.Get(generateManifestUrl(ide)); err == nil {
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, errors.New("Error downloading Manifest file. Response status = " + strconv.Itoa(resp.StatusCode))
}
if json, err = ioutil.ReadAll(resp.Body); err == nil {
return json, err
}
}
return nil, err
}
func generateManifestUrl(ide IDE) string {
url := ide.GetDownloadUrl() + ".manifest"
return url
}
func convertAnyToJson(toConvert interface{}) (result []byte) {
marshal, _ := json.Marshal(toConvert)
return marshal
}
var manifestGenerationWorkGroup sync.WaitGroup
type ProtectedFilesStruct struct {
mu sync.Mutex
distrFiles []fileInfo
}
func GenerateFilesInfo() (distrFiles []fileInfo) {
ideaBinary := GetIdeaBinaryToWrokWith()
ideaPath := GetIdeIdePackageByBinary(ideaBinary)
timebeginning := time.Now().Unix()
var distrFilesThreaded ProtectedFilesStruct
manifestGenerationWorkGroup.Add(1)
go walkAndCollectHashes(ideaPath, &distrFilesThreaded)
manifestGenerationWorkGroup.Wait()
distrFiles = distrFilesThreaded.distrFiles
logger.InfoLogger.Printf("File struct size: %d, Time %d sec", len(distrFiles), time.Now().Unix()-timebeginning)
return distrFiles
}
func walkAndCollectHashes(currentPath string, distrFiles *ProtectedFilesStruct) {
defer manifestGenerationWorkGroup.Done()
visit := func(path string, file os.DirEntry, err error) error {
if file.IsDir() && path != currentPath {
manifestGenerationWorkGroup.Add(1)
go walkAndCollectHashes(path, distrFiles)
return filepath.SkipDir
}
var distrFile fileInfo
distrFile.Hashes = make(map[string]string)
distrFile.Path = filepath.ToSlash(strings.TrimPrefix(path, GetIdePackageToWorkWith(GetIdeaBinaryToWrokWith())+string(os.PathSeparator)))
if file.Type().IsRegular() {
fillFileInfoStruct(path, file, &distrFile)
} else if file.Type()&os.ModeSymlink != 0 {
link, _ := os.Readlink(path)
distrFile.SymlinkTo = link
} else if file.IsDir() {
return nil
}
distrFiles.mu.Lock()
distrFiles.distrFiles = append(distrFiles.distrFiles, distrFile)
distrFiles.mu.Unlock()
return nil
}
_ = filepath.WalkDir(currentPath, visit)
}
func fillFileInfoStruct(path string, file os.DirEntry, distrFile *fileInfo) {
info, _ := file.Info()
distrFile.Size = info.Size()
distrFile.Mode = info.Mode()
date := info.ModTime().Local()
distrFile.ModificationTime = &date
for _, algorithm := range Algorithms {
distrFile.Hashes[algorithm] = getHash(path, algorithm)
}
}
func getHash(path string, algorithm string) string {
f, err := os.Open(path)
logger.ExitWithExceptionOnError(err)
defer func() {
_ = f.Close()
}()
copyBuf := make([]byte, 1024*1024)
if algorithm == "CRC32" {
tablePolynomial := crc32.MakeTable(0xedb88320)
h := crc32.New(tablePolynomial)
if _, err := io.CopyBuffer(h, f, copyBuf); err != nil {
logger.ExitWithExceptionOnError(err)
}
return hex.EncodeToString(h.Sum(nil))
} else if algorithm == "SHA256" {
h := sha256.New()
if _, err := io.CopyBuffer(h, f, copyBuf); err != nil {
logger.ExitWithExceptionOnError(err)
}
return hex.EncodeToString(h.Sum(nil))
} else {
logger.ExitWithExceptionOnError(errors.New(algorithm + " is not yet supported"))
return ""
}
}
+291
View File
@@ -0,0 +1,291 @@
package helpers
import (
"encoding/json"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"repair/logger"
"runtime"
"strconv"
"strings"
)
type IdeInfo struct {
Name string
Version string // 2022.2.1
BuildNumber string
ProductCode string
DataDirectoryName string
IsRepairBundled bool
Launch []struct {
Os string `json:"os"`
LauncherPath string `json:"launcherPath"`
JavaExecutablePath string `json:"javaExecutablePath"`
VmOptionsFilePath string `json:"vmOptionsFilePath"`
} `json:"launch"`
}
type IDE struct {
Binary string
Package string
Info IdeInfo
}
func (ide *IDE) MarkRepairAsBundled() {
ide.Info.IsRepairBundled = true
}
func (ide *IDE) IsRepairBundled() bool {
return ide.Info.IsRepairBundled
}
func (ide *IDE) SetBinaryToWrokWith(ideaBinary string) {
if _, err := GetIdeInfoByBinary(ideaBinary); err == nil {
ide.Binary = ideaBinary
}
}
func (ide *IDE) GetInfo() IdeInfo {
if len(ide.Package) == 0 {
ide.Package = GetIdePackageToWorkWith(ide.Binary)
}
if len(ide.Info.Name) == 0 {
var fileContent []byte
var err error
fileContent, err = ioutil.ReadFile(ide.Package + IdeProductInfoRelatedToInstallationPath[runtime.GOOS])
if err != nil {
for operatingSystem, path := range IdeProductInfoRelatedToInstallationPath {
if content, er := ioutil.ReadFile(ide.Package + path); er == nil {
fileContent = content
logger.WarningLogger.Printf("Could not find product-info.json for %s, but found it for %s ", runtime.GOOS, operatingSystem)
}
}
}
err = json.Unmarshal(fileContent, &ide.Info)
if err == nil {
return ide.Info
}
}
return ide.Info
}
func (ide *IDE) GetDownloadUrl() string {
if //goland:noinspection ALL
len(EmbeededDownloadUrl) > 0 && CurrentIde.IsRepairBundled() {
logger.DebugLogger.Println("Embedded download URL = " + EmbeededDownloadUrl)
return EmbeededDownloadUrl
}
ideInfo := ide.GetInfo()
ideBinary := filepath.Base(ideInfo.Launch[0].LauncherPath)
ideBinary = strings.TrimSuffix(ideBinary, ".sh")
ideBinary = strings.TrimSuffix(ideBinary, "64.exe")
architectureSuffix := ""
if runtime.GOOS == "darwin" && runtime.GOARCH == "arm64" {
architectureSuffix = "-aarch64"
}
//For example https://download.jetbrains.com/idea/ideaIU-2022.2.1.exe.manifest
url := downloadsURL + "/" + ideBinary + "/" + ideBinary + ideInfo.ProductCode + "-" + ideInfo.Version + architectureSuffix + archiveExtension[runtime.GOOS]
logger.DebugLogger.Println("No embedded download URL found. Generated download URL = " + url)
return url
}
func (ide *IDE) GetDisabledPluginsFilename() string {
return ide.GetConfigurationDirectory() + "disabled_plugins.txt"
}
func (ide *IDE) PluginsList() *PluginInfoList {
if len(PluginsList) > 0 {
return &PluginsList
}
pluginsDirs := ide.getPluginsDirectories()
for _, pluginsDir := range pluginsDirs {
ScanDirForPlugins(pluginsDir)
}
return &PluginsList
}
func (ide *IDE) CustomPluginsList() *PluginInfoList {
if len(CustomPluginsList) > 0 {
return &CustomPluginsList
}
if len(PluginsList) < 1 {
PluginsList = *ide.PluginsList()
}
for _, plugin := range PluginsList {
if !plugin.isBundled {
CustomPluginsList = append(CustomPluginsList, plugin)
}
}
return &CustomPluginsList
}
func (ide *IDE) DisableAllCustomPlugins(revert bool) {
disabledPluginsFilename := ide.GetDisabledPluginsFilename()
if revert {
logger.InfoLogger.Println("Enabling plugins back...")
logger.DebugLogger.Printf("Moving file %s to %s", disabledPluginsFilename+".backup", disabledPluginsFilename)
err := MoveFile(disabledPluginsFilename+".backup", disabledPluginsFilename)
logger.ExitWithExceptionOnError(err)
} else {
logger.InfoLogger.Println("Disabling all custom plugins...")
logger.DebugLogger.Println("Creating the list of already disabled plugins and disabling the rest")
if _, err := os.Stat(disabledPluginsFilename); err == nil {
logger.DebugLogger.Printf("Moving file %s to %s", disabledPluginsFilename, disabledPluginsFilename+".backup")
err = MoveFile(disabledPluginsFilename, disabledPluginsFilename+".backup")
logger.ExitWithExceptionOnError(err)
}
CustomPluginsList = *CurrentIde.CustomPluginsList()
ide.disablePlugins(&CustomPluginsList)
logger.InfoLogger.Println("Custom plugins were disabled")
}
return
}
func (ide *IDE) RefreshPluginsList() {
PluginsList = *new(PluginInfoList)
CustomPluginsList = *new(PluginInfoList)
PluginsList = *ide.PluginsList()
CustomPluginsList = *ide.CustomPluginsList()
}
func (ide *IDE) getPluginsDirectories() (pluginsDirs []string) {
pluginsDirs = append(pluginsDirs, GetIdeBundledPluginsDirectory(ide.Binary))
pluginsDirs = append(pluginsDirs, ide.GetIdeCustomPluginsDirectory())
//pluginsDirs = append(pluginsDirs, GetIdeCustomPluginsDirectory(ide.Binary))
for i, pluginsDir := range pluginsDirs {
pluginsDirs[i] = filepath.Clean(pluginsDir) + string(os.PathSeparator)
}
return pluginsDirs
}
func (ide *IDE) EnablePlugin(plugin PluginInfo) {
disabledPluginsFilename := ide.GetDisabledPluginsFilename()
disabledPluginRecord := GetDisabledPluginRecord(plugin)
err := RemoveFromFile(disabledPluginRecord, disabledPluginsFilename)
logger.ExitWithExceptionOnError(err)
logger.ConsoleLogger.Printf("%s has been enabled", plugin.Name)
return
}
func (ide *IDE) disablePlugins(pluginsList *PluginInfoList) {
disabledPluginsFilename := ide.GetDisabledPluginsFilename()
var allPluginsRecords string
for _, plugin := range *pluginsList {
allPluginsRecords = allPluginsRecords + "\n" + GetDisabledPluginRecord(plugin)
plugin.IsDisabled = true
}
WriteToFile(allPluginsRecords, disabledPluginsFilename)
}
func (ide *IDE) DisablePlugin(plugin PluginInfo) {
disabledPluginsFilename := ide.GetDisabledPluginsFilename()
disabledPluginRecord := GetDisabledPluginRecord(plugin)
WriteToFile(disabledPluginRecord, disabledPluginsFilename)
logger.ConsoleLogger.Println("\"" + plugin.Name + "\" has been disabled")
return
}
func (ide *IDE) updatePlugin(plugin PluginInfo) {
ide.removePlugin(plugin)
ide.installPlugin(downloadLatestCompatibleVersionOfPlugin(ide.Binary, plugin))
}
func (ide *IDE) updatePlugins(pluginsList []PluginInfo) {
for _, plugin := range pluginsList {
ide.updatePlugin(plugin)
logger.ConsoleLogger.Println("\"" + plugin.Name + "\" has been updated to compatible version")
}
}
func (ide *IDE) installPlugin(pluginZipPath string) {
err := Unzip(pluginZipPath, ide.GetIdeCustomPluginsDirectory())
logger.ExitWithExceptionOnError(err)
err = os.Remove(pluginZipPath)
logger.ExitWithExceptionOnError(err)
}
func (ide *IDE) removePlugins(plugins []PluginInfo) {
for _, plugin := range plugins {
ide.removePlugin(plugin)
}
}
func (ide *IDE) removePlugin(plugin PluginInfo) {
pluginsDir := ide.GetIdeCustomPluginsDirectory()
pluginFiles := strings.TrimPrefix(plugin.MainJarPath, pluginsDir)
pluginFiles = strings.TrimPrefix(pluginFiles, string(os.PathSeparator))
if idx := strings.Index(pluginFiles, string(os.PathSeparator)); idx != -1 {
pluginFiles = pluginFiles[:idx]
}
filesToRemove := pluginsDir + pluginFiles
matches, _ := filepath.Glob(filesToRemove)
for _, match := range matches {
fileToRemove := GetAbsolutePath(match)
err := os.RemoveAll(fileToRemove)
logger.ExitWithExceptionOnError(err)
}
}
func (ide *IDE) ClearSystemDirectory() {
logger.InfoLogger.Println("Clearing system directory...")
ideSystemDirectory := ide.GetSystemDirectory()
err := RemoveContentOfDir(ideSystemDirectory)
logger.ExitWithExceptionOnError(err)
}
func (ide *IDE) AskUserAndUpdatePlugins(pluginsToUpdateList PluginInfoList) {
if len(pluginsToUpdateList) > 0 {
logger.ConsoleLogger.Printf("The following plugins could be updated:\n" + pluginsToUpdateList.ToString())
question := "Update the above plugins?"
options := []string{"y", "n"}
if AskQuestionWithOptions(question, options) == "y" {
logger.ConsoleLogger.Println("Updaing plugins...")
ide.updatePlugins(pluginsToUpdateList)
}
}
}
func (ide *IDE) AskUserAndDisablePlugins(pluginsToDisableList PluginInfoList) {
if len(pluginsToDisableList) > 0 {
alertMessage := "The following plugins should be disabled as "
function := GetCallerFunction()
if strings.HasSuffix(function, "RunPluginsAspect") {
alertMessage = alertMessage + "there is no compatible version for the IDE"
} else if strings.HasSuffix(function, "RunLogAspect") {
alertMessage = alertMessage + "there are errors from these plugins in idea.log"
}
logger.ConsoleLogger.Println(alertMessage+"\n", pluginsToDisableList.ToString())
question := "Disable the above plugins?"
options := []string{"y", "n"}
if AskQuestionWithOptions(question, options) == "y" {
logger.ConsoleLogger.Println("Disabling the above plugins...")
ide.disablePlugins(&pluginsToDisableList)
}
}
}
func (ide *IDE) AskUserAndClearSystemDirectory() {
question := "Clear system directory as a general troubleshooting step? \n\t Note: Local history will be removed!"
options := []string{"y", "n"}
if AskQuestionWithOptions(question, options) == "y" {
ide.ClearSystemDirectory()
}
}
func (ide *IDE) AskUserToRunIdeAndCheckTheIssue() bool {
question := "Let's try to start the IDE to check if the issue is still here?"
options := []string{"y", "n"}
if ForceAskQuestionWithOptions(question, options) == "y" {
process := ide.RunIde()
question = "The issue still here?"
options = []string{"y", "n"}
if AskQuestionWithOptions(question, options) == "y" {
logger.InfoLogger.Println("Shutting down the IDE and continue repairing")
err := process.Kill()
logger.WriteToLogOnError(err, logger.WarningLogger)
return true
} else {
return false
}
} else {
question = "Then restart the IDE manually. Can the issue be reproduced now?"
options = []string{"y", "n"}
if ForceAskQuestionWithOptions(question, options) == "y" {
return true
} else {
return false
}
}
}
func (ide *IDE) RunIde() *os.Process {
cmd := exec.Command(ide.Binary)
err := cmd.Start()
if err != nil {
log.Fatal(err)
}
logger.DebugLogger.Println("Started the IDE with PID " + strconv.Itoa(cmd.Process.Pid))
return cmd.Process
}
@@ -0,0 +1,69 @@
package helpers
import (
"os"
"path/filepath"
"repair/logger"
"strconv"
"strings"
)
func SelectIdeaBinary() (path string, err error) {
logger.InfoLogger.Println("----------Scanning system for IDE installations----------")
var installedIdes []string
installedIdes, err = FindInstalledIdePackages()
if err != nil {
return "", err
}
for i, idePackage := range installedIdes {
info, _ := GetIdeInfoByPackage(idePackage)
logger.ConsoleLogger.Printf("[%v] %v %v (%v-%v) - %v \n", i, info.Name, info.Version, info.ProductCode, info.BuildNumber, beautifyPackageName(idePackage))
}
logger.ConsoleLogger.Printf("Please choose one of the above installations to perform operations with\n" +
"You can either type the digit, or define absolute path to the IDE installation")
input, err := ReadUserInput()
input = strings.TrimSpace(input)
if number, convertible := strconv.Atoi(input); convertible == nil && number < len(installedIdes) {
path, err = GetIdeBinaryByPackage(installedIdes[number])
logger.ExitWithExceptionOnError(err)
} else if number >= len(installedIdes) {
logger.ConsoleLogger.Fatal(input + " is out of range. Please use 1.." + strconv.Itoa(len(installedIdes)-1) + " to choose the IDE to work with")
} else {
path = strings.TrimSpace(input)
}
path = filepath.Clean(path)
_, err = os.Open(path)
if err != nil {
logger.DebugLogger.Println(err)
logger.ConsoleLogger.Fatal("Seems you tried to enter the path to the IDE binary, but there is no IDE binary in the \"" + path + "\" path")
}
logger.DebugLogger.Println("IDE binary to work with:" + path)
return path, err
}
func beautifyPackageName(idePackage string) string {
if strings.Contains(idePackage, "oolbox") {
return "From ToolBox app"
}
return idePackage
}
func FindIdeInstallationsByMask(path string) (foundIdePackages []string, err error) {
for _, possibleBaseFileName := range possibleBaseFileNames {
currentPath := strings.Replace(path, "{possibleBaseFileName}", possibleBaseFileName, -1)
matches, _ := filepath.Glob(os.ExpandEnv(currentPath))
for _, match := range matches {
match = GetIdeIdePackageByBinary(match)
foundIdePackages = append(foundIdePackages, match)
}
}
return foundIdePackages, err
}
func FindInstalledIdePackages() (installedIdes []string, err error) {
for _, path := range getOsDependentDir(possibleBinariesPaths) {
var foundInstallations []string
foundInstallations, err = FindIdeInstallationsByMask(path)
installedIdes = append(installedIdes, foundInstallations...)
}
return installedIdes, err
}
@@ -0,0 +1,58 @@
package helpers
import (
"os"
"repair/logger"
"runtime"
"testing"
)
func TestMain(m *testing.M) {
code := m.Run()
if code == 0 {
logger.RemoveLogFile()
}
os.Exit(code)
}
var tests = []struct {
name string
wantPossible_binaries map[string][]string
wantErr bool
}{
{name: "in /Applications folder",
wantPossible_binaries: map[string][]string{"darwin": []string{"/Applications/IntelliJ IDEA.app"}, "windows": []string{"C:\\Program Files\\JetBrains\\IntelliJ IDEA 2021.1.2"}},
wantErr: false,
},
}
func TestFindPossibleIdeInstallations(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotPossible_binaries, err := FindInstalledIdePackages()
if (err != nil) != tt.wantErr {
t.Errorf("FindInstalledIdePackages() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !sliceContainsAll(gotPossible_binaries, tt.wantPossible_binaries[runtime.GOOS]) {
t.Errorf("FindInstalledIdePackages() gotPossible_binaries = %v, want %v", gotPossible_binaries, tt.wantPossible_binaries)
}
})
}
}
func sliceContainsAll(allValues []string, mandatoryValues []string) (containsAll bool) {
for _, mandatoryElement := range mandatoryValues {
for _, element := range allValues {
if mandatoryElement == element {
containsAll = true
break
}
}
if containsAll == false {
return false
}
}
return true
}
@@ -0,0 +1,42 @@
package helpers
import (
"io/ioutil"
"os"
"os/exec"
"repair/logger"
"runtime"
"strings"
)
func GetJavaProperty(javaBinary string, property string) (output string, err error) {
javaText := "class Main {" +
"public static void main(String[] ideBinary) {" +
"System.out.print(System.getProperty(\"" + property + "\"));" +
"}" +
"}"
return RunJavaProgram(javaBinary, javaText)
}
func RunJavaProgram(javaBinary string, javaText string) (output string, err error) {
if runtime.GOOS == "windows" {
javaBinary = strings.TrimRight(javaBinary, ".exe")
}
javacBinary := javaBinary + "c"
if runtime.GOOS == "windows" {
javacBinary = javacBinary + ".exe"
}
className := "Main"
err = ioutil.WriteFile(className+".java", []byte(javaText), 0644)
logger.ExitWithExceptionOnError(err)
_, err = exec.Command(javacBinary, className+".java").CombinedOutput()
logger.ExitWithExceptionOnError(err)
outputBytes, err := exec.Command(javaBinary, className).CombinedOutput()
logger.ExitWithExceptionOnError(err)
output = string(outputBytes)
err = os.Remove(className + ".class")
logger.WriteToLogOnError(err, logger.DebugLogger)
err = os.Remove(className + ".java")
logger.WriteToLogOnError(err, logger.DebugLogger)
return output, nil
}
+191
View File
@@ -0,0 +1,191 @@
package helpers
import (
"bufio"
"io"
"log"
"os"
"regexp"
"repair/logger"
"strings"
)
var pluginsWithExceptions PluginInfoList
var logEntriesWithExceptions []LogEntry
func GetPluginsWithExceptionsInIdeaLog(logfile string) PluginInfoList {
if len(LogEntries) == 0 {
LogEntries = ParseIdeaLogFile(logfile)
}
return pluginsWithExceptions
}
func GetLogEntriesWithExceptions(logfile string) []LogEntry {
if len(LogEntries) == 0 {
LogEntries = ParseIdeaLogFile(logfile)
}
return logEntriesWithExceptions
}
func ParseIdeaLogFile(logfile string) (logEntries []LogEntry) {
reader, err := os.Open(logfile)
logger.ExitWithExceptionOnError(err)
logger.InfoLogger.Println("Parsing idea.log file...")
bufReader := bufio.NewReader(reader)
for {
currentString, err := bufReader.ReadString('\n')
if getTimeStampFromString(currentString) != "" {
if len(logEntries) > 0 && lastLogEntryHasException(logEntries) {
logEntriesWithExceptions = append(logEntriesWithExceptions, logEntries[len(logEntries)-1])
}
currentEntry := parseLogString(currentString)
if entryContainsPluginToBlame(currentEntry) && len(logEntries) >= 4 {
collectPluginsWithExceptions(currentEntry)
logEntriesWithExceptions = logEntriesWithExceptions[:len(logEntriesWithExceptions)-1]
}
logEntries = append(logEntries, currentEntry)
} else if len(logEntries) > 0 {
logEntries[len(logEntries)-1].Body = logEntries[len(logEntries)-1].Body + currentString
}
if err == io.EOF {
break
}
if err != nil {
log.Fatalf("ERROR: %s", err)
}
}
return logEntries
}
func lastLogEntryHasException(logEntries []LogEntry) bool {
if len(logEntries[len(logEntries)-1].Body) > 0 && logEntries[len(logEntries)-1].Severity == "ERROR" {
return true
}
return false
}
func collectPluginsWithExceptions(currentEntry LogEntry) {
if getEnabledPluginByBlameString(currentEntry) != nil &&
!pluginsWithExceptions.Contains(*getEnabledPluginByBlameString(currentEntry)) {
pluginsWithExceptions = append(pluginsWithExceptions, *getEnabledPluginByBlameString(currentEntry))
}
}
func getEnabledPluginByBlameString(currentEntry LogEntry) *PluginInfo {
pluginName := getPluginNameByBlameString(currentEntry.Header)
PluginsList = *CurrentIde.PluginsList()
for _, plugin := range PluginsList {
if plugin.Name == pluginName && plugin.IsDisabled == false {
return &plugin
}
}
logger.DebugLogger.Println("There are exceptions regarding " + pluginName + " plugin, but it is uninstalled.")
return nil
}
func getPluginNameByBlameString(logHeader string) string {
logHeader = strings.TrimPrefix(strings.TrimSpace(logHeader), "Plugin to blame: ")
versionMatcher := regexp.MustCompile("version:.*")
logHeader = strings.TrimSpace(versionMatcher.ReplaceAllString(logHeader, "${1}"))
return logHeader
}
func entryContainsPluginToBlame(entry LogEntry) bool {
if strings.HasPrefix(strings.TrimSpace(entry.Header), "Plugin to blame") {
return true
}
return false
}
func isTimeStamp(str string) bool {
if getTimeStampFromString(str) != "" {
return true
}
return false
}
func parseLogString(logEntryAsString string) (currentEntry LogEntry) {
logEntryAsString = strings.TrimLeft(logEntryAsString, "\n")
classEndPosition := 0
HeaderEndPosition := 0
currentEntry.DateAndTime = getTimeStampFromString(logEntryAsString)
trimFoundPart(&logEntryAsString, currentEntry.DateAndTime)
rawTimeSinceStart := getRawTimeSinceStart(&logEntryAsString)
currentEntry.TimeSinceStart = getTimeSinceStart(rawTimeSinceStart)
trimFoundPart(&logEntryAsString, rawTimeSinceStart)
currentEntry.Severity = getSeverity(&logEntryAsString)
trimFoundPart(&logEntryAsString, currentEntry.Severity)
//todo make that without for loop and unify
for i := range logEntryAsString {
if currentEntry.Class == "" && getClass(logEntryAsString[0:i]) != "" {
classEndPosition = i
currentEntry.Class = getClass(logEntryAsString[0:i])
}
if classEndPosition != 0 {
HeaderEndPosition = strings.IndexAny(logEntryAsString, "\n")
if HeaderEndPosition == -1 {
currentEntry.Header = strings.TrimSpace(logEntryAsString[classEndPosition:])
break
} else {
//todo check if this is needed
currentEntry.Header = logEntryAsString[classEndPosition:HeaderEndPosition]
}
}
if HeaderEndPosition > 0 {
currentEntry.Body = logEntryAsString[HeaderEndPosition:]
break
}
}
return currentEntry
}
func getRawTimeSinceStart(str *string) string {
dateMatcher := regexp.MustCompile("\\[(.*?)]")
if dateMatcher.MatchString(*str) {
return dateMatcher.FindString(*str)
}
return ""
}
func trimFoundPart(stringToCut *string, part string) {
*stringToCut = strings.TrimSpace(*stringToCut)
*stringToCut = strings.TrimPrefix(*stringToCut, part)
}
func getClass(s string) string {
s = strings.TrimSpace(s)
if len(s) > 2 && s[0] == '-' && s[len(s)-1] == '-' {
return strings.TrimSpace(s[1 : len(s)-1])
}
return ""
}
func getSeverity(s *string) string {
*s = strings.TrimSpace(*s)
severities := []string{"INFO", "ERROR", "DEBUG", "WARN"}
for _, severity := range severities {
if strings.HasPrefix(*s, severity) {
return severity
}
}
return ""
}
func getTimeSinceStart(s string) string {
s = strings.TrimSpace(s)
if len(s) > 8 && s[0] == '[' && s[len(s)-1] == ']' {
s = s[1 : len(s)-1]
return strings.TrimSpace(s)
}
return ""
}
func getTimeStampFromString(str string) string {
dateMatcher := regexp.MustCompile("^(\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}[.,]\\d{3})")
if dateMatcher.MatchString(str) {
return dateMatcher.FindString(str)
}
return ""
}
File diff suppressed because one or more lines are too long
+70
View File
@@ -0,0 +1,70 @@
package helpers
import (
"strconv"
)
type IdeaVersion struct {
SinceBuild string `xml:"since-build,attr"`
UntilBuild string `xml:"until-build,attr"`
}
var disabledPlugins []string
func (plugins *PluginInfoList) ToString() (pluginsAsString string) {
for i, plugin := range *plugins {
pluginsAsString = pluginsAsString + " " + strconv.Itoa(i+1) + ". " + plugin.Name + "\n"
}
return
}
func (plugins *PluginInfoList) Contains(pluginToCheck PluginInfo) bool {
for _, plugin := range *plugins {
if pluginToCheck == plugin {
return true
}
}
return false
}
func (plugins *PluginInfoList) FilterIncompatible() (incompatiblePlugins PluginInfoList) {
ideBuildAsFloat := ConvertBuildNumberToFloat(CurrentIde.GetInfo().BuildNumber)
for _, plugin := range *plugins {
pluginSinceBuildAsFloat := ConvertBuildNumberToFloat(plugin.IdeaVersion.SinceBuild)
pluginUntilBuildAsFloat := ConvertBuildNumberToFloat(plugin.IdeaVersion.UntilBuild)
if ((pluginSinceBuildAsFloat > ideBuildAsFloat) || (pluginUntilBuildAsFloat < ideBuildAsFloat)) && plugin.IsDisabled == false {
incompatiblePlugins = append(incompatiblePlugins, plugin)
}
}
return incompatiblePlugins
}
func (plugins *PluginInfoList) FilterDisabled() (disabledPluginsList PluginInfoList) {
for _, plugin := range *plugins {
if plugin.IsDisabled {
disabledPluginsList = append(disabledPluginsList, plugin)
}
}
return disabledPluginsList
}
func (plugins *PluginInfoList) FilterEnabled() (enabledPluginsList PluginInfoList) {
for _, plugin := range *plugins {
if !plugin.IsDisabled {
enabledPluginsList = append(enabledPluginsList, plugin)
}
}
return enabledPluginsList
}
func (plugins *PluginInfoList) FilterUpdatable() (updatablePlugins PluginInfoList) {
for _, plugin := range *plugins {
if CheckIfPluginHasCompatibleVersion(CurrentIde.Binary, &plugin) {
updatablePlugins = append(updatablePlugins, plugin)
}
}
return
}
func (plugins *PluginInfoList) FilterDeprecated() (deprecatedPlugins PluginInfoList) {
for _, plugin := range *plugins {
if !CheckIfPluginHasCompatibleVersion(CurrentIde.Binary, &plugin) {
deprecatedPlugins = append(deprecatedPlugins, plugin)
}
}
return
}
@@ -0,0 +1,203 @@
package helpers
import (
"archive/zip"
"bufio"
"bytes"
"encoding/json"
"encoding/xml"
"io"
"io/ioutil"
"net/http"
"os"
"path"
"path/filepath"
"repair/logger"
"strconv"
"strings"
)
func downloadLatestCompatibleVersionOfPlugin(ideaBinary string, plugin PluginInfo) (downloadedZipPath string) {
url := "https://plugins.jetbrains.com/plugin/download?" +
"pluginId=" + GetDisabledPluginRecord(plugin) +
"&version=" + RequestLatestCompatibleVersionFromMarketplace(ideaBinary, &plugin)
downloadedZipPath = DownloadFile(url)
return downloadedZipPath
}
func RequestLatestCompatibleVersionFromMarketplace(ideaBinary string, plugin *PluginInfo) string {
ideInfo, _ := GetIdeInfoByBinary(ideaBinary)
ideBuildNumber := ideInfo.ProductCode + "-" + ideInfo.BuildNumber
type ServerResponse []struct {
Id int `json:"id"`
PluginId int `json:"pluginId"`
PluginXmlId string `json:"pluginXmlId"`
Version string `json:"version"`
}
var m ServerResponse
url := "https://plugins.jetbrains.com/api/search/compatibleUpdates"
var jsonStr = []byte(`{"build":"` + ideBuildNumber + `","pluginXMLIds":["` + GetDisabledPluginRecord(*plugin) + `"]}`)
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonStr))
logger.ExitWithExceptionOnError(err)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
logger.ExitWithExceptionOnError(err)
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
err = json.Unmarshal(body, &m)
for _, newPlugin := range m {
if newPlugin.PluginXmlId == plugin.PluginXmlId {
plugin.MarketplaceId = newPlugin.PluginId
return newPlugin.Version
}
}
return ""
}
func DownloadFile(url string) (downloadPath string) {
downloadFolder := GetAbsolutePath("downloads/")
// Get the data
resp, err := http.Get(url)
logger.ExitWithExceptionOnError(err)
finalURL := resp.Request.URL.Path
downloadPath = downloadFolder + string(os.PathSeparator) + path.Base(finalURL)
defer resp.Body.Close()
// Create the
if _, err := os.Stat(downloadFolder); os.IsNotExist(err) {
_ = os.Mkdir(downloadFolder, 0755)
}
out, err := os.Create(downloadPath)
logger.ExitWithExceptionOnError(err)
defer out.Close()
// Write the body to file
_, err = io.Copy(out, resp.Body)
logger.ExitWithExceptionOnError(err)
return downloadPath
}
func GetPluginsToUpdateAndPluginsToDelete(ideaBinary string, incompatiblePluginsList []PluginInfo) (pluginsToUpdateList []PluginInfo, pluginsToDeleteList []PluginInfo) {
for _, incompatiblePlugin := range incompatiblePluginsList {
if CheckIfPluginHasCompatibleVersion(ideaBinary, &incompatiblePlugin) {
pluginsToUpdateList = append(pluginsToUpdateList, incompatiblePlugin)
} else {
pluginsToDeleteList = append(pluginsToDeleteList, incompatiblePlugin)
}
}
return pluginsToUpdateList, pluginsToDeleteList
}
func CheckIfPluginHasCompatibleVersion(ideaBinary string, plugin *PluginInfo) bool {
newPluginVersion := RequestLatestCompatibleVersionFromMarketplace(ideaBinary, plugin)
if (newPluginVersion != "") && (ConvertBuildNumberToFloat(plugin.Version) < ConvertBuildNumberToFloat(newPluginVersion)) {
return true
}
return false
}
func ScanDirForPlugins(pluginsDir string) {
jarFilesPaths := []string{pluginsDir + "/*/lib/*.jar", pluginsDir + "/*.jar"}
for _, jarFilesPath := range jarFilesPaths {
jarFiles, _ := filepath.Glob(jarFilesPath)
for _, jarFile := range jarFiles {
pluginDescriptionXmlContent := getPluginDescriptionFileContent(jarFile)
if pluginDescriptionXmlContent != nil {
currentPlugin := parsePluginXml(pluginDescriptionXmlContent)
currentPlugin.MainJarPath = jarFile
disabledPluginRecord := GetDisabledPluginRecord(currentPlugin)
currentPlugin.IsDisabled = checkIfPluginDisabled(disabledPluginRecord)
currentPlugin.PluginXmlId = GetDisabledPluginRecord(currentPlugin)
currentPlugin.isBundled = strings.HasPrefix(currentPlugin.MainJarPath, GetIdeBundledPluginsDirectory(GetIdeaBinaryToWrokWith()))
//todo: include XMLs defined in plugin.xml
if len(currentPlugin.PluginXmlId) > 1 {
PluginsList = append(PluginsList, currentPlugin)
}
}
}
}
}
func GetDisabledPluginRecord(plugin PluginInfo) string {
if len(plugin.PluginXmlId) > 0 {
return plugin.PluginXmlId
} else if len(plugin.Id) > 0 {
return plugin.Id
} else {
return plugin.Name
}
}
func ConvertBuildNumberToFloat(buildNumber string) (build float64) {
if buildNumber == "" {
buildNumber = "*.*"
}
buildNumber = strings.Replace(buildNumber, "*", "9999", 2)
if strings.Count(buildNumber, ".") >= 2 {
buildNumberSplit := strings.Split(buildNumber, ".")
buildNumber = buildNumberSplit[0] + "." + buildNumberSplit[1]
}
build, err := strconv.ParseFloat(buildNumber, 64)
if err != nil {
logger.DebugLogger.Println(err)
}
return build
}
func parsePluginXml(pluginDescriptionXmlContent []byte) PluginInfo {
var currentPluginInfo PluginInfo
_ = xml.Unmarshal(pluginDescriptionXmlContent, &currentPluginInfo)
return currentPluginInfo
}
func checkIfPluginDisabled(plugin string) bool {
disabledPluginsFile := CurrentIde.GetDisabledPluginsFilename()
parseDisabledPluginsFile(disabledPluginsFile)
return sliceOfStringsContains(disabledPlugins, plugin)
}
func sliceOfStringsContains(slice []string, value string) (contains bool) {
for _, element := range slice {
if value == element {
contains = true
break
}
}
return contains
}
func parseDisabledPluginsFile(disabledPluginsFile string) {
if len(disabledPlugins) == 0 {
file, err := os.Open(disabledPluginsFile)
if err == nil {
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
if len(scanner.Text()) > 0 {
disabledPlugins = append(disabledPlugins, scanner.Text())
}
}
}
}
}
func getPluginDescriptionFileContent(jarFile string) []byte {
var err error
var file *os.File
var fi os.FileInfo
var r *zip.Reader
file, err = os.Open(jarFile)
logger.ExitWithExceptionOnError(err)
defer file.Close()
fi, err = file.Stat()
logger.ExitWithExceptionOnError(err)
r, err = zip.NewReader(file, fi.Size())
logger.ExitWithExceptionOnError(err)
for _, f := range r.File {
var name = f.Name
if name == "META-INF/plugin.xml" {
file, err := f.Open()
logger.ExitWithExceptionOnError(err)
content, err := ioutil.ReadAll(file)
//Logger.DebugLogger.Println("Found " + jarFile + name + " file")
return content
}
}
return nil
}
@@ -0,0 +1,64 @@
package helpers
import (
"testing"
)
func TestRequestLatestCompatibleVersionFromMarketplace(t *testing.T) {
for {
CurrentIde.SetBinaryToWrokWith(GetRandomIdeInstallationBinary())
binaryInfo, err := GetIdeInfoByBinary(GetIdeaBinaryToWrokWith())
if err != nil {
return
}
if ConvertBuildNumberToFloat(binaryInfo.BuildNumber) > 201 && ConvertBuildNumberToFloat(binaryInfo.BuildNumber) < 212 {
break
}
}
ideInfo, _ := GetIdeInfoByBinary(GetIdeaBinaryToWrokWith())
wantPluginVersion := "0"
if ConvertBuildNumberToFloat(ideInfo.BuildNumber) > 203 && ConvertBuildNumberToFloat(ideInfo.BuildNumber) < 204 {
wantPluginVersion = "4.0.3"
} else if ConvertBuildNumberToFloat(ideInfo.BuildNumber) > 211 {
wantPluginVersion = "4.1.0"
} else if ConvertBuildNumberToFloat(ideInfo.BuildNumber) > 202 && ConvertBuildNumberToFloat(ideInfo.BuildNumber) < 203 {
wantPluginVersion = "3.2.3.202"
}
pluginToCheck := PluginInfo{
Id: "mobi.hsz.idea.gitignore",
Name: ".ignore",
Version: "4.0.3",
Vendor: "JetBrains",
MainJarPath: GetAbsolutePath(CurrentIde.GetIdeCustomPluginsDirectory() + "/.ignore/lib/idea-gitignore-4.0.3.jar"),
PluginXmlId: "mobi.hsz.idea.gitignore",
MarketplaceId: 0,
IsDisabled: false,
IdeaVersion: IdeaVersion{
SinceBuild: "203",
UntilBuild: "203.*",
},
}
type args struct {
ideaBinary string
plugin *PluginInfo
}
tests := []struct {
name string
args args
want string
}{
{
name: "detect binary by package name",
args: args{GetIdeaBinaryToWrokWith(), &pluginToCheck},
want: wantPluginVersion,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := RequestLatestCompatibleVersionFromMarketplace(tt.args.ideaBinary, tt.args.plugin); got != tt.want {
t.Errorf("RequestLatestCompatibleVersionFromMarketplace() = %v, want %v", got, tt.want)
}
})
}
}
@@ -0,0 +1,94 @@
package helpers
import (
"reflect"
"testing"
)
func TestGetPluginsList(t *testing.T) {
CurrentIde.SetBinaryToWrokWith(GetRandomIdeInstallationBinaryOfBuild("211"))
tests := []struct {
name string
ideBinary string
pluginsToInstall PluginInfoList
wantPluginsList PluginInfoList
wantIncompatiblePluginsList PluginInfoList
}{
{
name: "1 Enabled plugin",
ideBinary: GetIdeaBinaryToWrokWith(),
pluginsToInstall: []PluginInfo{
{
PluginXmlId: "mobi.hsz.idea.gitignore",
Version: "4.1.0",
},
{
PluginXmlId: "BashSupport",
Version: "1.7.15.192",
}},
wantPluginsList: []PluginInfo{
{
Id: "mobi.hsz.idea.gitignore",
Name: ".ignore",
Version: "4.1.0",
Vendor: "JetBrains",
MainJarPath: GetAbsolutePath(CurrentIde.GetIdeCustomPluginsDirectory() + "/.ignore/lib/idea-gitignore-4.1.0.jar"),
PluginXmlId: "mobi.hsz.idea.gitignore",
MarketplaceId: 0,
IsDisabled: false,
IdeaVersion: IdeaVersion{
SinceBuild: "211",
UntilBuild: "211.*",
},
isBundled: false,
},
{
Id: "",
Name: "BashSupport",
Version: "1.7.15.192",
Vendor: "Joachim Ansorg",
MainJarPath: GetAbsolutePath(CurrentIde.GetIdeCustomPluginsDirectory() + "/BashSupport/lib/bashsupport-1.7.15.192.jar"),
PluginXmlId: "BashSupport",
MarketplaceId: 0,
IsDisabled: false,
IdeaVersion: IdeaVersion{
SinceBuild: "192.0",
UntilBuild: "193.*",
},
isBundled: false,
}},
wantIncompatiblePluginsList: []PluginInfo{
{
Id: "",
Name: "BashSupport",
Version: "1.7.15.192",
Vendor: "Joachim Ansorg",
MainJarPath: GetAbsolutePath(CurrentIde.GetIdeCustomPluginsDirectory() + "/BashSupport/lib/bashsupport-1.7.15.192.jar"),
PluginXmlId: "BashSupport",
MarketplaceId: 0,
IsDisabled: false,
IdeaVersion: IdeaVersion{
SinceBuild: "192.0",
UntilBuild: "193.*",
},
isBundled: false,
}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
CurrentIde.TemporarilyRemovePluginsDir(false)
CurrentIde.TemporarilyRenameDisabledPluginsFile(false)
CurrentIde.downloadAndInstallPlugins(tt.pluginsToInstall)
if gotPluginsList := *CurrentIde.CustomPluginsList(); !reflect.DeepEqual(tt.wantPluginsList, gotPluginsList) {
t.Errorf("PluginsList() = %v, want %v", gotPluginsList, tt.wantPluginsList)
}
if gotPluginsList := CurrentIde.CustomPluginsList().FilterIncompatible(); !reflect.DeepEqual(tt.wantIncompatiblePluginsList, gotPluginsList) {
t.Errorf("\n IDE build %s \n FilterIncompatible() =\n %v want\n %v", CurrentIde.Info.BuildNumber, gotPluginsList.ToString(), tt.wantIncompatiblePluginsList.ToString())
}
CurrentIde.TemporarilyRemovePluginsDir(true)
CurrentIde.TemporarilyRenameDisabledPluginsFile(true)
})
}
}
@@ -0,0 +1,83 @@
package helpers
import (
"bufio"
"errors"
"os"
"repair/logger"
"strings"
)
var YesToAll bool
var NoToAll bool
func AskQuestionWithOptions(question string, options []string) (answer string) {
if YesToAll {
return "y"
}
if NoToAll {
return "n"
}
return ForceAskQuestionWithOptions(question, options)
}
func ForceAskQuestionWithOptions(question string, options []string) (answer string) {
var optionsList string
for i, option := range options {
if i == len(options)-1 {
optionsList = optionsList + option
} else {
optionsList = optionsList + option + "/"
}
}
logger.ConsoleLogger.Println(question + " [" + optionsList + "]")
answer, err := ReadUserInput()
logger.ExitWithExceptionOnError(err)
answer = strings.ToLower(strings.TrimSpace(answer))
if asnwerFitsOptions(answer, options) {
return answer
} else {
logger.ConsoleLogger.Println("There is no such option. Let me ask again:")
answer = ForceAskQuestionWithOptions(question, options)
return answer
}
}
func asnwerFitsOptions(answer string, options []string) bool {
for _, option := range options {
if strings.ToLower(answer) == strings.ToLower(option) {
return true
}
}
return false
}
func ReadUserInput() (input string, err error) {
stdin := bufio.NewReader(os.Stdin)
input, err = stdin.ReadString('\n')
input = strings.Replace(input, "\n", "", -1)
return input, err
}
func AskUserToDownloadFreshInstallation() {
baseFileName := GetIdeBasefileName(GetIdeaBinaryToWrokWith())
logger.ExitOnError(errors.New("Please download fresh copy of the installation from https://www.jetbrains.com/" + baseFileName + "/download/"))
}
func AskUserAndRemoveFiles(filesToRemove []string) {
question := "Remove the mentioned files?"
answers := []string{"y", "n"}
answer := AskQuestionWithOptions(question, answers)
if answer == "n" {
return
}
for _, file := range filesToRemove {
if _, err := os.Stat(GetIdeIdePackageByBinary(GetIdeaBinaryToWrokWith()) + "/" + file); err == nil {
file = GetIdeIdePackageByBinary(GetIdeaBinaryToWrokWith()) + "/" + file
}
if _, err := os.Stat(file); err == nil {
if err = os.Remove(file); err != nil {
logger.WarningLogger.Printf("Could not remove %s file", file)
}
} else {
logger.WarningLogger.Printf("Could not find %s file", file)
}
}
}
@@ -0,0 +1,209 @@
package helpers
import (
"bufio"
"errors"
"io/ioutil"
"os"
"path/filepath"
"repair/logger"
"runtime"
"strings"
)
func DetectRuntimeInUse(ideaBinary string) (runtimeInUse RuntimeInfo, err error) {
runtimeInUse.BinaryPath, runtimeInUse.BinaryPathDefinedAt, runtimeInUse.BinaryPathDefinedAs = getRuntimeBinary(ideaBinary)
logger.ExitWithExceptionOnError(err)
runtimeInUse.IsBundled = checkIfRuntimeBundled(runtimeInUse.BinaryPath)
runtimeInUse.Architecture = getRuntimeArchitecture(runtimeInUse.BinaryPath)
runtimeInUse.Version = getRuntimeVersion(runtimeInUse.BinaryPath)
return runtimeInUse, err
}
func getRuntimeVersion(runtimeBinaryPath string) string {
output, err := GetJavaProperty(runtimeBinaryPath, "java.version")
logger.ExitWithExceptionOnError(err)
return output
}
func getRuntimeArchitecture(runtimeBinaryPath string) string {
output, err := GetJavaProperty(runtimeBinaryPath, "sun.arch.data.model")
logger.ExitWithExceptionOnError(err)
return filepath.Clean(output)
}
func checkIfRuntimeBundled(path string) bool {
if strings.Contains(path, IdeRuntimeBinaryRelatedToInstallationPath[runtime.GOOS]) {
return true
} else {
return false
}
}
func getRuntimeBinary(ideaBinary string) (binaryPath string, binaryPathDefinedAt string, binaryPathDefinedAs string) {
for _, variable := range getOsDependentDir(possibleRuntimeVariables) {
runtimeLocation := os.ExpandEnv(expandRuntimeDefaultLocation(variable))
if runtimeLocation != "" {
return findRuntimeBinaryInsidePath(runtimeLocation), "$IDEA_JDK", runtimeLocation
}
}
for _, location := range getOsDependentDir(possibleRuntimeConfiguraitonFileLocations) {
location := expandRuntimeDefaultLocation(location)
if fileWithPossibleLocation, err := os.Open(location); err == nil {
runtimeLocation := getRuntimePathFromFile(fileWithPossibleLocation)
return findRuntimeBinaryInsidePath(runtimeLocation), location, runtimeLocation
}
}
if possibleLocation, err := getBundledRuntimeBinary(ideaBinary); err == nil {
return possibleLocation, "bundled", "bundled"
}
logger.ExitWithExceptionOnError(errors.New("could not detect IDE runtime definition"))
return "", "", ""
}
func expandRuntimeDefaultLocation(dir string) (expandedDir string) {
dir = strings.Replace(dir, "{IdeConfigDir}", CurrentIde.GetConfigurationDirectory(), -1)
dir = strings.Replace(dir, "{IDE_BASEFILENAME}", strings.ToUpper(GetIdeBasefileName(GetIdeaBinaryToWrokWith())), -1)
dir = strings.Replace(dir, "{IDE_BaseFilename}", GetIdeBasefileName(GetIdeaBinaryToWrokWith()), -1)
dir = filepath.Clean(dir)
return dir
}
func findRuntimeBinaryInsidePath(runtimePath string) (binaryPath string) {
runtimePath = filepath.Clean(runtimePath)
err := filepath.Walk(runtimePath,
func(path string, info os.FileInfo, err error) error {
if err == nil && strings.HasSuffix(path, "/bin/java") && !strings.Contains(path, "/jre") {
binaryPath = path
return nil
}
if err == nil && strings.HasSuffix(path, "\\bin\\java.exe") && !strings.Contains(path, "\\jre") && runtime.GOOS == "windows" {
binaryPath = path
return nil
}
return nil
})
if err != nil {
logger.ExitWithExceptionOnError(err)
}
return binaryPath
}
func getRuntimePathFromFile(file *os.File) string {
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
for scanner.Scan() {
definedLcoation := scanner.Text()
if len(definedLcoation) != 0 {
if FileExists(definedLcoation) {
return definedLcoation
}
}
}
return ""
}
func getBundledRuntimeBinary(ideaBinary string) (runtimeBinary string, err error) {
ideaPackage := GetIdeIdePackageByBinary(ideaBinary)
runtimeBinary = ideaPackage + IdeRuntimeBinaryRelatedToInstallationPath[runtime.GOOS]
if FileExists(runtimeBinary) {
return runtimeBinary, nil
} else {
return "", err
}
}
func PrepareEnvironent(wantRuntimeInUse RuntimeInfo) {
if wantRuntimeInUse.BinaryPathDefinedAt == "$IDEA_JDK" {
variable := strings.TrimPrefix(expandRuntimeDefaultLocation(getOsDependentDir(possibleRuntimeVariables)[0]), "$")
err := os.Setenv(variable, wantRuntimeInUse.BinaryPathDefinedAs)
logger.ExitWithExceptionOnError(err)
}
if strings.HasSuffix(wantRuntimeInUse.BinaryPathDefinedAt, "idea.jdk") {
err := ioutil.WriteFile(wantRuntimeInUse.BinaryPathDefinedAt, []byte(wantRuntimeInUse.BinaryPathDefinedAs), 0644)
logger.ExitWithExceptionOnError(err)
}
}
func ClearEnvironemnt(wantRuntimeInUse RuntimeInfo) {
if wantRuntimeInUse.BinaryPathDefinedAt == "$IDEA_JDK" {
err := os.Unsetenv("IDEA_JDK")
logger.ExitWithExceptionOnError(err)
}
if strings.HasSuffix(wantRuntimeInUse.BinaryPathDefinedAt, "idea.jdk") {
err := os.Remove(wantRuntimeInUse.BinaryPathDefinedAt)
logger.ExitWithExceptionOnError(err)
}
}
func RuntimeIsBundled() error {
if !RuntimeInUse.IsBundled {
return errors.New("Non-bundled runtime is in use. JetBrains Runtime (JBR) is recommended runtime to start JetBrains IDEs")
}
return nil
}
func RuntimeArchitectureCorrectness() error {
var is64Bit = uint64(^uintptr(0)) == ^uint64(0)
if !is64Bit {
if strings.HasPrefix(RuntimeInUse.Architecture, " 64") {
return errors.New("IDE uses 64-bit runtime on 32-bit OS")
}
}
return nil
}
func RuntimeVersionLessThan17(runtimeInfo RuntimeInfo) error {
if !strings.HasPrefix(runtimeInfo.Version, "17") && !runtimeInfo.IsBundled {
return errors.New("IDE uses java of version " + runtimeInfo.Version + ", but recomended version is 17")
} else {
return nil
}
}
func ResetRuntimeInUse(runtime RuntimeInfo) (err error) {
if runtime.BinaryPathDefinedAt == "bundled" {
return nil
} else if runtime.BinaryPathDefinedAt == "$IDEA_JDK" {
err = os.Unsetenv("$IDEA_JDK")
} else if strings.Contains(runtime.BinaryPathDefinedAt, "idea.jdk") {
err = ioutil.WriteFile(runtime.BinaryPathDefinedAt+".old", []byte(runtime.BinaryPathDefinedAs), 0644)
if err != nil {
logger.ExitWithExceptionOnError(errors.New("Could not make a backup of " + runtime.BinaryPathDefinedAt + ": " + err.Error()))
}
err = os.Remove(runtime.BinaryPathDefinedAt)
if err != nil {
logger.ExitWithExceptionOnError(errors.New("Could not remove " + runtime.BinaryPathDefinedAt + ": " + err.Error()))
}
} else {
err = errors.New("could not reset JDK")
}
return err
}
func IdeHasBundledRuntime(binaryToWorkWith string) bool {
info, _ := GetIdeInfoByBinary(binaryToWorkWith)
if len(info.Launch[0].JavaExecutablePath) > 0 {
return true
}
return false
}
func SuggestToChangeIdeToOneWithBundledRuntime() {
info, _ := GetIdeInfoByBinary(GetIdeaBinaryToWrokWith())
logger.ConsoleLogger.Println("There are errors related to runtime in use, but there is no default runtime for your IDE installation. \n" +
"Please install latest version of " + info.Name + "from https://jetbrains.com/")
}
func SuggestResettingRuntime() bool {
question := "Reset runtime to default?"
options := []string{"y", "n"}
var answer string
if !IsInTests() {
answer = AskQuestionWithOptions(question, options)
} else {
answer = "n"
}
if answer == "y" {
return true
}
return false
}
@@ -0,0 +1,71 @@
package helpers
import (
"reflect"
"repair/logger"
"testing"
)
func Test_detectRuntimeInUse(t *testing.T) {
randomIdeaBinary := GetRandomIdeInstallationBinary()
type args struct {
ideaBinary string
}
tests := []struct {
name string
args args
wantRuntimeInUse RuntimeInfo
wantErr bool
}{
{
name: "RuntimeDefinedInVar",
args: args{
ideaBinary: randomIdeaBinary,
},
wantRuntimeInUse: RuntimeInfo{
BinaryPath: GetAbsolutePath("./test_helpers_files/jbr_packages/jbr-11/Contents/Home/bin/java"),
BinaryPathDefinedAt: "$IDEA_JDK",
BinaryPathDefinedAs: GetAbsolutePath("./test_helpers_files/jbr_packages/jbr-11"),
Version: "11.0.7",
Architecture: "64",
IsBundled: false,
},
wantErr: false,
}, {
name: "RuntimeDefinedInDefaultConfDir",
args: args{
ideaBinary: randomIdeaBinary,
},
wantRuntimeInUse: RuntimeInfo{
BinaryPath: GetAbsolutePath("./test_helpers_files/jbr_packages/jbr-11/Contents/Home/bin/java"),
BinaryPathDefinedAt: GetAbsolutePath(expandRuntimeDefaultLocation(getOsDependentDir(possibleRuntimeConfiguraitonFileLocations)[0])),
BinaryPathDefinedAs: GetAbsolutePath("./test_helpers_files/jbr_packages/jbr-11"),
Version: "11.0.7",
Architecture: "64",
IsBundled: false,
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
PrepareEnvironent(tt.wantRuntimeInUse)
gotRuntimeInUse, err := DetectRuntimeInUse(tt.args.ideaBinary)
if (err != nil) != tt.wantErr {
t.Errorf("detectRuntimeInUse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(gotRuntimeInUse, tt.wantRuntimeInUse) {
error := "\nwant BinaryPathDefinedAt: " + tt.wantRuntimeInUse.BinaryPathDefinedAt
error = error + "\ngot BinaryPathDefinedAt: " + gotRuntimeInUse.BinaryPathDefinedAt
error = error + "\ngot BinaryPathDefinedAs: " + tt.wantRuntimeInUse.BinaryPathDefinedAs
error = error + "\ngot BinaryPathDefinedAs: " + gotRuntimeInUse.BinaryPathDefinedAs
error = error + "\ngot BinaryPath: " + tt.wantRuntimeInUse.BinaryPath
error = error + "\ngot BinaryPath: " + gotRuntimeInUse.BinaryPath
t.Errorf("%s", error)
}
ClearEnvironemnt(tt.wantRuntimeInUse)
logger.RemoveLogFile()
})
}
}
@@ -0,0 +1,111 @@
package helpers
import (
"errors"
"math/rand"
"os"
"path/filepath"
"repair/logger"
"strings"
"time"
)
func IsInTests() bool {
for _, arg := range os.Args {
if strings.HasPrefix(arg, "-test.v") {
return true
}
}
return false
}
func GetRandomIdeInstallationBinaryOfBuild(version string) (ideaBinary string) {
for i := 0; i < 20; i++ {
possibleBinary := GetRandomIdeInstallationBinary()
if info, _ := GetIdeInfoByBinary(possibleBinary); strings.Contains(info.BuildNumber, version) {
return possibleBinary
}
}
logger.ExitWithExceptionOnError(errors.New("Could not find IDE with " + version + " version"))
return ""
}
func GetRandomIdeInstallationBinary() (ideaBinary string) {
var err error
var packagePath string
if packagePath, err = GetRandomIdeInstallationPackage(); err == nil {
if ideaBinary, err = GetIdeBinaryByPackage(packagePath); err == nil {
logger.ConsoleLogger.Println("Idea Binary to work with:" + ideaBinary)
CurrentIde.SetBinaryToWrokWith(ideaBinary)
return ideaBinary
}
}
logger.ExitWithExceptionOnError(err)
return ""
}
func GetRandomIdeInstallationPackage() (packagePath string, err error) {
var possiblePackages []string
possiblePackages, err = FindInstalledIdePackages()
if len(possiblePackages) > 0 {
rand.Seed(time.Now().UnixNano())
for {
possibleackage := possiblePackages[rand.Intn(len(possiblePackages)-1)]
if _, err := GetIdeInfoByPackage(possibleackage); err == nil {
return possibleackage, nil
}
}
}
return "", errors.New("Could not find installed IDEs")
}
func GetAbsolutePath(relatedPath string) string {
path, err := filepath.Abs(relatedPath)
_, err = os.Stat(path)
if err != nil {
logger.WarningLogger.Println(err)
}
return path
}
func (ide *IDE) downloadAndInstallPlugins(plugins PluginInfoList) {
for _, plugin := range plugins {
ide.downloadAndInstallPlugin(plugin, plugin.Version)
}
}
func downloadAndInstallPlugins(ideaBinary string, plugins PluginInfoList) {
}
func (ide *IDE) downloadAndInstallPlugin(plugin PluginInfo, version string) {
zipFilePath := downloadPlugin(plugin, version)
ide.installPlugin(zipFilePath)
}
func downloadPlugin(plugin PluginInfo, version string) (downloadedZipPath string) {
url := "https://plugins.jetbrains.com/plugin/download?" +
"pluginId=" + GetDisabledPluginRecord(plugin) +
"&version=" + version
downloadedZipPath = DownloadFile(url)
return downloadedZipPath
}
func (ide *IDE) TemporarilyRemovePluginsDir(revert bool) {
pluginsDir := strings.TrimSuffix(ide.GetIdeCustomPluginsDirectory(), "/")
if revert {
err := RemoveDir(pluginsDir)
if FileExists(pluginsDir + ".old") {
err = os.Rename(pluginsDir+".old", pluginsDir)
}
logger.ExitWithExceptionOnError(err)
} else {
if FileExists(pluginsDir) {
err := os.Rename(pluginsDir, pluginsDir+".old")
logger.ExitWithExceptionOnError(err)
}
}
}
func (ide *IDE) TemporarilyRenameDisabledPluginsFile(revert bool) {
disabledPluginsFilename := ide.GetDisabledPluginsFilename()
if FileExists(disabledPluginsFilename) && revert == false {
err := MoveFile(disabledPluginsFilename, disabledPluginsFilename+".backup")
logger.ExitWithExceptionOnError(err)
}
if FileExists(disabledPluginsFilename+".backup") && revert == true {
err := MoveFile(disabledPluginsFilename+".backup", disabledPluginsFilename)
logger.ExitWithExceptionOnError(err)
}
return
}
@@ -0,0 +1 @@
Add content of JBR here to run tests with this runtime
@@ -0,0 +1 @@
Add content of JBR here to run tests with this runtime
@@ -0,0 +1,90 @@
2020-07-13 23:23:41,398 [182151486] ERROR - tellij.openapi.util.ObjectTree - Memory leak detected: 'org.nik.presentationAssistant.ActionInfoPanel[,0,0,508x40,invalid,layout=java.awt.BorderLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.border.EmptyBorder@de486dd,flags=16777224,maximumSize=,minimumSize=,preferredSize=]' of class org.nik.presentationAssistant.ActionInfoPanel
See the cause for the corresponding Disposer.register() stacktrace:
java.lang.RuntimeException: Memory leak detected: 'org.nik.presentationAssistant.ActionInfoPanel[,0,0,508x40,invalid,layout=java.awt.BorderLayout,alignmentX=0.0,alignmentY=0.0,border=javax.swing.border.EmptyBorder@de486dd,flags=16777224,maximumSize=,minimumSize=,preferredSize=]' of class org.nik.presentationAssistant.ActionInfoPanel
See the cause for the corresponding Disposer.register() stacktrace:
at com.intellij.openapi.util.ObjectTree.assertIsEmpty(ObjectTree.java:226)
at com.intellij.openapi.util.Disposer.assertIsEmpty(Disposer.java:130)
at com.intellij.openapi.util.Disposer.assertIsEmpty(Disposer.java:125)
at com.intellij.openapi.application.impl.ApplicationImpl.disposeContainer(ApplicationImpl.java:183)
at com.intellij.openapi.application.impl.ApplicationImpl.disposeSelf(ApplicationImpl.java:200)
at com.intellij.openapi.application.impl.ApplicationImpl.doExit(ApplicationImpl.java:621)
at com.intellij.openapi.application.impl.ApplicationImpl.exit(ApplicationImpl.java:589)
at com.intellij.openapi.application.impl.ApplicationImpl.restart(ApplicationImpl.java:536)
at com.intellij.ide.actions.InvalidateCachesAction.actionPerformed(InvalidateCachesAction.java:96)
at com.intellij.openapi.actionSystem.ex.ActionUtil.performActionDumbAware(ActionUtil.java:280)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.lambda$actionPerformed$0(ActionMenuItem.java:296)
at com.intellij.openapi.wm.impl.FocusManagerImpl.runOnOwnContext(FocusManagerImpl.java:281)
at com.intellij.openapi.wm.impl.IdeFocusManagerImpl.runOnOwnContext(IdeFocusManagerImpl.java:77)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem$ActionTransmitter.actionPerformed(ActionMenuItem.java:285)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.lambda$fireActionPerformed$0(ActionMenuItem.java:112)
at com.intellij.openapi.application.TransactionGuardImpl.performUserActivity(TransactionGuardImpl.java:94)
at com.intellij.openapi.actionSystem.impl.ActionMenuItem.fireActionPerformed(ActionMenuItem.java:112)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.JToggleButton$ToggleButtonModel.setPressed(JToggleButton.java:401)
at java.desktop/javax.swing.AbstractButton.doClick(AbstractButton.java:369)
at java.desktop/com.apple.laf.ScreenMenuItemCheckbox.itemStateChanged(ScreenMenuItemCheckbox.java:198)
at java.desktop/java.awt.CheckboxMenuItem.processItemEvent(CheckboxMenuItem.java:396)
at java.desktop/java.awt.CheckboxMenuItem.processEvent(CheckboxMenuItem.java:364)
at java.desktop/java.awt.MenuComponent.dispatchEventImpl(MenuComponent.java:375)
at java.desktop/java.awt.MenuComponent.dispatchEvent(MenuComponent.java:363)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:781)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:974)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:847)
at com.intellij.ide.IdeEventQueue.lambda$null$8(IdeEventQueue.java:449)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:741)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$9(IdeEventQueue.java:448)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:831)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:502)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
Caused by: java.lang.Throwable
at com.intellij.openapi.util.ObjectNode.<init>(ObjectNode.java:35)
at com.intellij.openapi.util.ObjectTree.createNodeFor(ObjectTree.java:106)
at com.intellij.openapi.util.ObjectTree.register(ObjectTree.java:70)
at com.intellij.openapi.util.Disposer.register(Disposer.java:65)
at com.intellij.util.Alarm.<init>(Alarm.java:139)
at com.intellij.util.Alarm.<init>(Alarm.java:108)
at org.nik.presentationAssistant.ActionInfoPanel.<init>(ActionInfoPanel.kt:46)
at org.nik.presentationAssistant.ShortcutPresenter.showActionInfo(ShortcutPresenter.kt:141)
at org.nik.presentationAssistant.ShortcutPresenter$enable$1.beforeActionPerformed(ShortcutPresenter.kt:66)
at jdk.internal.reflect.GeneratedMethodAccessor147.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.intellij.util.messages.impl.MessageBusImpl.invokeListener(MessageBusImpl.java:541)
at com.intellij.util.messages.impl.MessageBusConnectionImpl.deliverMessage(MessageBusConnectionImpl.java:143)
at com.intellij.util.messages.impl.MessageBusImpl.doPumpMessages(MessageBusImpl.java:465)
at com.intellij.util.messages.impl.MessageBusImpl.pumpWaitingBuses(MessageBusImpl.java:426)
at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:415)
at com.intellij.util.messages.impl.MessageBusImpl.sendMessage(MessageBusImpl.java:397)
at com.intellij.util.messages.impl.MessageBusImpl.lambda$createTopicHandler$3(MessageBusImpl.java:237)
at com.sun.proxy.$Proxy114.beforeActionPerformed(Unknown Source)
at com.intellij.openapi.actionSystem.impl.ActionManagerImpl.fireBeforeActionPerformed(ActionManagerImpl.java:1438)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:662)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processAction(IdeKeyEventDispatcher.java:619)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.processActionOrWaitSecondStroke(IdeKeyEventDispatcher.java:516)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.inInitState(IdeKeyEventDispatcher.java:470)
at com.intellij.openapi.keymap.impl.IdeKeyEventDispatcher.dispatchKeyEvent(IdeKeyEventDispatcher.java:219)
at com.intellij.ide.IdeEventQueue.dispatchKeyEvent(IdeEventQueue.java:896)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:841)
... 11 more
2020-07-13 23:23:41,398 [182151486] ERROR - tellij.openapi.util.ObjectTree - IntelliJ IDEA 2020.1.2 Build #IU-201.7846.76
2020-07-13 23:23:41,398 [182151486] ERROR - tellij.openapi.util.ObjectTree - JDK: 11.0.7; VM: OpenJDK 64-Bit Server VM; Vendor: JetBrains s.r.o.
2020-07-13 23:23:41,398 [182151486] ERROR - tellij.openapi.util.ObjectTree - OS: Mac OS X
2020-07-13 23:23:41,399 [182151487] ERROR - tellij.openapi.util.ObjectTree - Plugin to blame: Presentation Assistant version: 1.0.5
@@ -0,0 +1,166 @@
2021-02-15 18:09:37,188 [ 61174] ERROR - .wm.impl.ToolWindowManagerImpl - Already disposed: Project (name=HelloJava, containerState=DISPOSE_IN_PROGRESS, componentStore=/Users/konstantin.annikov/IdeaProjects/HelloJava)
java.lang.IllegalStateException: Already disposed: Project (name=HelloJava, containerState=DISPOSE_IN_PROGRESS, componentStore=/Users/konstantin.annikov/IdeaProjects/HelloJava)
at com.intellij.serviceContainer.ComponentManagerImpl.getMessageBus(ComponentManagerImpl.kt:139)
at com.intellij.ide.navigationToolbar.NavBarListener.subscribeTo(NavBarListener.java:71)
at com.intellij.ide.navigationToolbar.NavBarPanel.addNotify(NavBarPanel.java:777)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at java.desktop/java.awt.Container.addNotify(Container.java:2800)
at java.desktop/javax.swing.JComponent.addNotify(JComponent.java:4791)
at com.intellij.openapi.wm.impl.InternalDecorator.addNotify(InternalDecorator.java:292)
at java.desktop/java.awt.Container.addImpl(Container.java:1146)
at java.desktop/java.awt.Container.add(Container.java:436)
at com.intellij.openapi.ui.ThreeComponentsSplitter.doAddComponent(ThreeComponentsSplitter.java:541)
at com.intellij.openapi.ui.ThreeComponentsSplitter.setLastComponent(ThreeComponentsSplitter.java:506)
at com.intellij.openapi.wm.impl.ToolWindowsPane.setComponent(ToolWindowsPane.java:300)
at com.intellij.openapi.wm.impl.ToolWindowsPane.removeDecorator(ToolWindowsPane.java:233)
at com.intellij.openapi.wm.impl.ToolWindowManagerImpl.removeDecoratorWithoutUpdatingState(ToolWindowManagerImpl.kt:1067)
at com.intellij.openapi.wm.impl.ToolWindowManagerImpl.projectClosed(ToolWindowManagerImpl.kt:510)
at com.intellij.openapi.wm.impl.ToolWindowManagerImpl$ToolWindowManagerAppLevelHelper$2.projectClosed(ToolWindowManagerImpl.kt:216)
at jdk.internal.reflect.GeneratedMethodAccessor141.invoke(Unknown Source)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at com.intellij.util.messages.impl.MessageBusImpl.invokeListener(MessageBusImpl.java:541)
at com.intellij.util.messages.impl.MessageBusConnectionImpl.deliverMessage(MessageBusConnectionImpl.java:143)
at com.intellij.util.messages.impl.MessageBusImpl.doPumpMessages(MessageBusImpl.java:465)
at com.intellij.util.messages.impl.MessageBusImpl.pumpWaitingBuses(MessageBusImpl.java:426)
at com.intellij.util.messages.impl.MessageBusImpl.pumpMessages(MessageBusImpl.java:415)
at com.intellij.util.messages.impl.MessageBusImpl.sendMessage(MessageBusImpl.java:397)
at com.intellij.util.messages.impl.MessageBusImpl.lambda$createTopicHandler$3(MessageBusImpl.java:237)
at com.sun.proxy.$Proxy78.projectClosed(Unknown Source)
at com.intellij.openapi.project.impl.ProjectManagerImpl.fireProjectClosed(ProjectManagerImpl.java:807)
at com.intellij.openapi.project.impl.ProjectManagerImpl.lambda$closeProject$11(ProjectManagerImpl.java:694)
at com.intellij.openapi.application.impl.ApplicationImpl.runWriteAction(ApplicationImpl.java:976)
at com.intellij.openapi.project.impl.ProjectManagerImpl.closeProject(ProjectManagerImpl.java:687)
at com.intellij.openapi.project.impl.ProjectManagerImpl.closeAndDisposeAllProjects(ProjectManagerImpl.java:611)
at com.intellij.openapi.application.impl.ApplicationImpl.disposeSelf(ApplicationImpl.java:190)
at com.intellij.openapi.application.impl.ApplicationImpl.doExit(ApplicationImpl.java:621)
at com.intellij.openapi.application.impl.ApplicationImpl.exit(ApplicationImpl.java:589)
at com.intellij.openapi.application.impl.ApplicationImpl.exit(ApplicationImpl.java:569)
at com.intellij.ide.plugins.newui.MyPluginModel.runRestartButton(MyPluginModel.java:861)
at com.intellij.ide.plugins.newui.RestartButton.lambda$new$0(RestartButton.java:13)
at java.desktop/javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1967)
at java.desktop/javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2308)
at java.desktop/javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:405)
at java.desktop/javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:262)
at java.desktop/javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:270)
at java.desktop/java.awt.Component.processMouseEvent(Component.java:6650)
at java.desktop/javax.swing.JComponent.processMouseEvent(JComponent.java:3345)
at java.desktop/java.awt.Component.processEvent(Component.java:6415)
at java.desktop/java.awt.Container.processEvent(Container.java:2263)
at java.desktop/java.awt.Component.dispatchEventImpl(Component.java:5025)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2321)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4857)
at java.desktop/java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:4918)
at java.desktop/java.awt.LightweightDispatcher.processMouseEvent(Container.java:4547)
at java.desktop/java.awt.LightweightDispatcher.dispatchEvent(Container.java:4488)
at java.desktop/java.awt.Container.dispatchEventImpl(Container.java:2307)
at java.desktop/java.awt.Window.dispatchEventImpl(Window.java:2773)
at java.desktop/java.awt.Component.dispatchEvent(Component.java:4857)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:778)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:95)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:751)
at java.desktop/java.awt.EventQueue$5.run(EventQueue.java:749)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:748)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:974)
at com.intellij.ide.IdeEventQueue.dispatchMouseEvent(IdeEventQueue.java:912)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:844)
at com.intellij.ide.IdeEventQueue.lambda$null$8(IdeEventQueue.java:449)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:741)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$9(IdeEventQueue.java:448)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:831)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:502)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:117)
at java.desktop/java.awt.WaitDispatchSupport$2.run(WaitDispatchSupport.java:190)
at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:235)
at java.desktop/java.awt.WaitDispatchSupport$4.run(WaitDispatchSupport.java:233)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.desktop/java.awt.WaitDispatchSupport.enter(WaitDispatchSupport.java:233)
at java.desktop/java.awt.Dialog.show(Dialog.java:1063)
at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl$MyDialog.show(DialogWrapperPeerImpl.java:708)
at com.intellij.openapi.ui.impl.DialogWrapperPeerImpl.show(DialogWrapperPeerImpl.java:437)
at com.intellij.openapi.ui.DialogWrapper.doShow(DialogWrapper.java:1685)
at com.intellij.openapi.ui.DialogWrapper.show(DialogWrapper.java:1644)
at com.intellij.ide.actions.ShowSettingsUtilImpl.showSettingsDialog(ShowSettingsUtilImpl.java:80)
at com.intellij.ide.actions.ShowSettingsAction.perform(ShowSettingsAction.java:54)
at com.intellij.ui.mac.MacOSApplicationProvider$Worker.lambda$null$1(MacOSApplicationProvider.java:78)
at com.intellij.ui.mac.MacOSApplicationProvider$Worker.lambda$submit$7(MacOSApplicationProvider.java:175)
at com.intellij.openapi.application.TransactionGuardImpl$2.run(TransactionGuardImpl.java:201)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:831)
at com.intellij.openapi.application.impl.ApplicationImpl.lambda$invokeLater$4(ApplicationImpl.java:310)
at com.intellij.openapi.application.impl.FlushQueue.doRun(FlushQueue.java:80)
at com.intellij.openapi.application.impl.FlushQueue.runNextEvent(FlushQueue.java:128)
at com.intellij.openapi.application.impl.FlushQueue.flushNow(FlushQueue.java:46)
at com.intellij.openapi.application.impl.FlushQueue$FlushNow.run(FlushQueue.java:184)
at java.desktop/java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:313)
at java.desktop/java.awt.EventQueue.dispatchEventImpl(EventQueue.java:776)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:727)
at java.desktop/java.awt.EventQueue$4.run(EventQueue.java:721)
at java.base/java.security.AccessController.doPrivileged(Native Method)
at java.base/java.security.ProtectionDomain$JavaSecurityAccessImpl.doIntersectionPrivilege(ProtectionDomain.java:85)
at java.desktop/java.awt.EventQueue.dispatchEvent(EventQueue.java:746)
at com.intellij.ide.IdeEventQueue.defaultDispatchEvent(IdeEventQueue.java:974)
at com.intellij.ide.IdeEventQueue._dispatchEvent(IdeEventQueue.java:847)
at com.intellij.ide.IdeEventQueue.lambda$null$8(IdeEventQueue.java:449)
at com.intellij.openapi.progress.impl.CoreProgressManager.computePrioritized(CoreProgressManager.java:741)
at com.intellij.ide.IdeEventQueue.lambda$dispatchEvent$9(IdeEventQueue.java:448)
at com.intellij.openapi.application.impl.ApplicationImpl.runIntendedWriteActionOnCurrentThread(ApplicationImpl.java:831)
at com.intellij.ide.IdeEventQueue.dispatchEvent(IdeEventQueue.java:496)
at java.desktop/java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:203)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:124)
at java.desktop/java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:113)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:109)
at java.desktop/java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:101)
at java.desktop/java.awt.EventDispatchThread.run(EventDispatchThread.java:90)
2021-02-15 18:09:37,189 [ 61175] ERROR - .wm.impl.ToolWindowManagerImpl - IntelliJ IDEA 2020.1.4 Build #IU-201.8743.12
2021-02-15 18:09:37,190 [ 61176] ERROR - .wm.impl.ToolWindowManagerImpl - JDK: 11.0.7; VM: OpenJDK 64-Bit Server VM; Vendor: JetBrains s.r.o.
2021-02-15 18:09:37,190 [ 61176] ERROR - .wm.impl.ToolWindowManagerImpl - OS: Mac OS X
2021-02-15 18:09:37,190 [ 61176] ERROR - .wm.impl.ToolWindowManagerImpl - Last Action: EditorPaste
2021-02-15 18:09:37,210 [ 61196] INFO - penapi.project.DumbServiceImpl - cancel com.intellij.util.indexing.UnindexedFilesUpdater@35e0fbd8
2021-02-15 18:09:37,228 [ 61214] INFO - #cursive.repl.IdeReplServer - Closing IDE REPL server socket
2021-02-15 18:09:37,228 [ 61214] INFO - #cursive.repl.IdeReplServer - IDE REPL server socket closed.
2021-02-15 18:09:37,229 [ 61215] INFO - pl.local.NativeFileWatcherImpl - Watcher terminated with exit code 0
2021-02-15 18:09:37,231 [ 61217] INFO - org.jetbrains.io.BuiltInServer - web server stopped
2021-02-15 18:09:40,655 [ 64641] INFO - .idea.vim.command.CommandState - Push new mode state: COMMAND:NONE
2021-02-15 18:09:40,655 [ 64641] INFO - .idea.vim.command.CommandState - Push new mode state: COMMAND:NONE
2021-02-15 18:09:40,655 [ 64641] INFO - .idea.vim.command.CommandState - Push new mode state: COMMAND:NONE
2021-02-15 18:09:40,667 [ 64653] INFO - Types.impl.FileTypeManagerImpl - 8 auto-detected files. Detection took 373 ms
2021-02-15 18:09:40,668 [ 64654] INFO - il.indexing.FileBasedIndexImpl - START INDEX SHUTDOWN
2021-02-15 18:09:40,753 [ 64739] INFO - tellij.psi.stubs.StubIndexImpl - StubIndexExtension-s were unloaded
2021-02-15 18:09:40,820 [ 64806] INFO - il.indexing.FileBasedIndexImpl - END INDEX SHUTDOWN
2021-02-15 18:09:40,820 [ 64806] INFO - newvfs.persistent.PersistentFS - VFS dispose started
2021-02-15 18:09:40,828 [ 64814] INFO - newvfs.persistent.PersistentFS - VFS dispose completed
2021-02-15 18:09:40,828 [ 64814] INFO - stubs.SerializationManagerImpl - START StubSerializationManager SHUTDOWN
2021-02-15 18:09:40,828 [ 64814] INFO - stubs.SerializationManagerImpl - END StubSerializationManager SHUTDOWN
2021-02-15 18:09:40,829 [ 64816] INFO - plication.impl.ApplicationImpl - Write action Statistics:
Event number: 8
Total time spent: 262ms
Average duration: 32ms
Median duration: 25ms
Max duration: 73ms (it was 'write action (class com.intellij.openapi.module.impl.ModuleManagerImpl$$Lambda$1556/0x0000000801aec040)')
2021-02-15 18:09:40,830 [ 64816] INFO - plication.impl.ApplicationImpl - AnAction.update() Statistics:
Event number: 973
Total time spent: 629ms
Average duration: 0ms
Median duration: 0ms
Max duration: 209ms (it was 'Find Usages action update (class com.intellij.find.actions.FindUsagesAction)')
@@ -0,0 +1 @@
Add
@@ -0,0 +1,21 @@
-Xms128m
-Xmx2048m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-XX:CICompilerCount=2
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-XX:+UseZGC
-Djdk.attach.allowAttachSelf=true
-XX:+UseSerialGC
-Dkotlinx.coroutines.debug=off
-Djdk.module.illegalAccess.silent=true
-XX:ErrorFile=$USER_HOME/java_error_in_goland_%p.log
-XX:HeapDumpPath=$USER_HOME/java_error_in_goland.hprof
-Dide.no.platform.update=true
-Dsun.io.useCanonCaches=false
-XX:+UseParallelGC
-XX:ReservedCodeCacheSize=512m
-Didea.plugins.path=/Users/konstantin.annikov/Library/Application Support/JetBrains/Toolbox/apps/Goland/ch-0/203.6682.164/GoLand.app.plugins
@@ -0,0 +1,18 @@
-Xms1228m
-Xmx1048m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-XX:CICompilerCount=2
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Djdk.attach.allowAttachSelf=true
-Dkotlinx.coroutines.debug=off
-Djdk.module.illegalAccess.silent=true
-XX:ErrorFile=$USER_HOME/java_error_in_goland_%p.log
-XX:HeapDumpPath=$USER_HOME/java_error_in_goland.hprof
-Dide.no.platform.update=true
-Dsun.io.useCanonCaches=false
-XX:ReservedCodeCacheSize=512m
-Didea.plugins.path=/Users/konstantin.annikov/Library/Application Support/JetBrains/Toolbox/apps/Goland/ch-0/203.6682.164/GoLand.app.plugins
@@ -0,0 +1,148 @@
package helpers
import (
"bufio"
"os"
"repair/logger"
"strconv"
"strings"
)
var (
vmoptionsDelimeters = []string{"=", ":", " "}
listOfPossibleGarbageCollectors = []string{"-XX:+UseSerialGC", "-XX:+UseParallelGC", "-XX:+UseG1GC", "-XX:+UseShenandoahGC", "XX:+UseEpsilonGC", "-XX:+UseConcMarkSweepGC", "-XX:+UseZGC"}
vmOptionsFileAsSlice = make(MappedVmoptions)
)
type MappedVmoptions map[string]string
func GetVmoptionsAsSlice(vmOptionsFile string) (vmoptions MappedVmoptions) {
var err error
if len(vmOptionsFileAsSlice) == 0 {
vmOptionsFileAsSlice, _, _, err = ParseVmOptionsFile(vmOptionsFile)
logger.ExitWithExceptionOnError(err)
}
return vmOptionsFileAsSlice
}
func ParseVmOptionsFile(file string) (vmoptions MappedVmoptions, garbageCollectorsInUse []string, vmoptionsDuplicates map[string]string, err error) {
vmoptions = make(MappedVmoptions)
vmoptionsDuplicates = make(map[string]string)
vmOptionsAsSlice, err := vmOptionsFileToSliceOfStrings(file)
if err != nil {
return nil, nil, nil, err
}
for _, option := range vmOptionsAsSlice {
var optionName string
var optionValue string
optionName = getVmoptionName(option)
optionValue = getVmoptionValue(option, optionName)
collectGcInUse(option, &garbageCollectorsInUse)
if currentOptionIsDuplicate(vmoptions, optionName) {
vmoptionsDuplicates[optionName] = optionValue
} else {
vmoptions[optionName] = optionValue
}
}
vmOptionsFileAsSlice = vmoptions
return vmoptions, garbageCollectorsInUse, vmoptionsDuplicates, nil
}
func collectGcInUse(option string, garbageCollectorInUse *[]string) {
for _, possibleGC := range listOfPossibleGarbageCollectors {
if possibleGC == option {
*garbageCollectorInUse = append(*garbageCollectorInUse, option)
}
}
}
func getVmoptionValue(option string, name string) (value string) {
if isBoolean, isEnablingBoolean := isEnabingBooleanOption(option); isBoolean {
if isEnablingBoolean {
return "true"
} else {
return "false"
}
}
value = strings.TrimPrefix(option, name)
for _, delimiter := range vmoptionsDelimeters {
value = strings.TrimSpace(strings.TrimPrefix(value, delimiter))
}
return value
}
func getVmoptionName(option string) string {
if isBooleanOption(option) {
return option
}
delimiterPosition := findDelimiterPositionOfVmoption(option)
if delimiterPosition == -1 {
return option
} else {
return option[:delimiterPosition]
}
}
func vmOptionsFileToSliceOfStrings(vmOptionsFile string) (options []string, err error) {
file, err := os.Open(vmOptionsFile)
if err != nil {
return nil, err
}
scanner := bufio.NewScanner(file)
scanner.Split(bufio.ScanLines)
var i int
for scanner.Scan() {
i++
option := scanner.Text()
if len(option) != 0 {
if option[0] == '-' {
options = append(options, option)
} else if option[0] == '#' {
} else {
logger.DebugLogger.Println("There is a suspicious option: \"" + option + "\" at line " + strconv.Itoa(i))
}
}
}
err = file.Close()
if err != nil {
return nil, err
}
return options, err
}
func findDelimiterPositionOfVmoption(option string) (delimiterPosition int) {
if strings.HasPrefix(option, "-Xmx") || strings.HasPrefix(option, "-Xms") || strings.HasPrefix(option, "-Xmn") {
return 4
}
for _, delimeter := range vmoptionsDelimeters {
delimiterPosition = strings.Index(option, delimeter)
if delimiterPosition != -1 {
return delimiterPosition
}
}
return delimiterPosition
}
func isEnabingBooleanOption(option string) (isBoolean bool, isEnabling bool) {
if strings.HasPrefix(option, "-XX:+") {
return true, true
}
if strings.HasPrefix(option, "-XX:-") {
return true, false
}
return false, false
}
func isBooleanOption(option string) (result bool) {
if strings.HasPrefix(option, "-XX:-") || strings.HasPrefix(option, "-XX:+") {
return true
}
return false
}
func currentOptionIsDuplicate(vmoptions MappedVmoptions, name string) bool {
if vmoptions[name] != "" {
return true
}
return false
}
@@ -0,0 +1,181 @@
package helpers
import (
"errors"
"os"
"repair/logger"
"strconv"
)
var CheckVmoptionsFileBool bool
func RestoreVmoptionsFile() (err error) {
vmOptionsFile, err := GetVmOptionsFile()
if err != nil {
logger.InfoLogger.Println(err)
return nil
}
newName := vmOptionsFile + ".old"
err = os.Rename(vmOptionsFile, newName)
logger.ExitWithExceptionOnError(err)
logger.InfoLogger.Println("File has been moved to " + newName)
return err
}
func CheckVmoptionsFile() {
vmOptionsFile, err := GetVmOptionsFile()
if err != nil {
logger.InfoLogger.Println(err)
}
var errorsToBeFixed []error
var warnings []error
mappedOptions, garbageCollectorsInUse, vmoptionsDuplicates, err := ParseVmOptionsFile(vmOptionsFile)
if err != nil {
return
}
collectWarnings(getDuplicatedVmOptions(vmoptionsDuplicates), &warnings)
collectWarnings(checkIfThereIsJavaAgent(mappedOptions), &warnings)
collectErrorsToBeFixed(checkIfMoreThanOneGcInUse(garbageCollectorsInUse), &errorsToBeFixed)
collectErrorsToBeFixed(checkXmxOn32Bit(mappedOptions["-Xmx"]), &errorsToBeFixed)
collectErrorsToBeFixed(checkXmxVsXms(mappedOptions), &errorsToBeFixed)
if len(warnings) > 0 {
warn := errors.New("\n" + formatCollectedWarnings(warnings))
logger.WarningLogger.Println(warn)
}
if len(errorsToBeFixed) > 0 {
err = errors.New("\n" + formatCollectedErrors(errorsToBeFixed))
logger.ErrorLogger.Println(err)
if !IsInTests() || !CheckVmoptionsFileBool {
suggestToFixVmoptionsFile(vmOptionsFile)
checkVmoptionsFileAgain()
}
}
if len(errorsToBeFixed) == 0 && len(warnings) == 0 {
logger.InfoLogger.Println("VM options seems OK. No need to take actions.")
}
}
func checkVmoptionsFileAgain() {
logger.InfoLogger.Println("Checking .vmoptions file once again")
CheckVmoptionsFileBoolVal := CheckVmoptionsFileBool
CheckVmoptionsFileBool = true
CheckVmoptionsFile()
CheckVmoptionsFileBool = CheckVmoptionsFileBoolVal
}
func checkIfThereIsJavaAgent(options MappedVmoptions) error {
if options["-javaagent"] != "" {
return errors.New("Unknown java agent detected: " + options["-javaagent"])
}
return nil
}
func formatCollectedWarnings(warningsToBePrinted []error) string {
return "The following WARNINGS were found during .vmoptions file checking: \n" + ConcatErrorsFromSlice(warningsToBePrinted)
}
func formatCollectedErrors(errorsToBeFixed []error) string {
return "The following ERRORS were found during .vmoptions file checking: \n" + ConcatErrorsFromSlice(errorsToBeFixed)
}
func collectWarnings(warn error, warnings *[]error) {
if warn != nil {
*warnings = append(*warnings, warn)
}
}
func collectErrorsToBeFixed(err error, errorsToBeFixed *[]error) {
if err != nil {
*errorsToBeFixed = append(*errorsToBeFixed, err)
}
}
func checkIfMoreThanOneGcInUse(garbageCollectorsInUse []string) error {
if len(garbageCollectorsInUse) > 1 {
var gclist string
for _, gc := range garbageCollectorsInUse {
gclist += "\n\t" + gc
}
return errors.New("More than one Garbage Collector in use: " + gclist)
}
return nil
}
func checkXmxOn32Bit(xmxValue string) (err error) {
var is64Bit = uint64(^uintptr(0)) == ^uint64(0)
var xmxInBytes int
if !is64Bit {
xmxInBytes = toBytes(xmxValue)
logger.ExitWithExceptionOnError(err)
if xmxInBytes > 2576980377 {
return errors.New("Xmx value is too large for 32-bit OS " + strconv.Itoa(xmxInBytes))
}
}
return err
}
func checkXmxVsXms(options MappedVmoptions) (err error) {
xmxInBytes := toBytes(options["-Xmx"])
if xmxInBytes == -1 {
return errors.New("Couldn't convert -Xmx=" + options["-Xmx"] + " to bytes. ")
}
xmsInBytes := toBytes(options["-Xms"])
if xmsInBytes == -1 {
return errors.New("Couldn't convert -Xms=" + options["-Xms"] + " to bytes. ")
}
if xmxInBytes >= xmsInBytes {
return nil
} else {
return errors.New("Xmx value (current value " + options["-Xmx"] + ") should be higher than Xms (current value " + options["-Xms"] + ")")
}
}
func toBytes(initial string) (initialInBytes int) {
if len(initial) < 1 {
return -1
}
units := initial[len(initial)-1]
initial = initial[:len(initial)-1]
initialInt, _ := strconv.Atoi(initial)
switch units {
case 'k', 'K':
initialInBytes = initialInt << 10
return initialInBytes
case 'm', 'M':
initialInBytes = initialInt << 20
return initialInBytes
case 'g', 'G':
initialInBytes = initialInt << 30
return initialInBytes
}
return -1
}
func getDuplicatedVmOptions(vmoptionsDuplicates map[string]string) (err error) {
if len(vmoptionsDuplicates) == 0 {
return nil
}
var duplicatedOptions string
for option := range vmoptionsDuplicates {
duplicatedOptions += ("\n\t" + option)
}
err = errors.New("Duplicated VM options: " + duplicatedOptions)
return err
}
func suggestToFixVmoptionsFile(file string) {
question := "There are two options to fix the above error:\n" +
"\t 1. Reset .vmoptions file to default (current .vmoptions file will be backed up) \n" +
"\t 2. Open the .vmoptions file for editing and correct it manually \n" +
"Please choose"
options := []string{"1", "2"}
answer := AskQuestionWithOptions(question, options)
if answer == "1" || answer == "y" {
logger.InfoLogger.Println("Restoring default .vmoptions file")
logger.ExitWithExceptionOnError(RestoreVmoptionsFile())
} else if answer == "2" {
openVmoptionsEditor(file)
}
}
func openVmoptionsEditor(vmOptionsFile string) {
err := OpenFileInEditor(vmOptionsFile)
logger.WriteToLogOnError(err, logger.ErrorLogger)
}
+77
View File
@@ -0,0 +1,77 @@
package logger
import (
"errors"
"io"
"io/ioutil"
"log"
"os"
"runtime/debug"
)
type RepairLogger struct {
log *log.Logger
logtype string
}
var (
WarningLogger RepairLogger
InfoLogger RepairLogger
ErrorLogger RepairLogger
ConsoleLogger RepairLogger
FatalLogger RepairLogger
DebugLogger RepairLogger
DebugEnabled bool
LogFile *os.File
)
func init() {
dest, err := ioutil.TempDir("", "IntelliJRepairBinary")
LogFile, err = os.OpenFile(dest+string(os.PathSeparator)+"repair.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0666)
if err != nil {
log.Fatal(err)
}
mw := io.MultiWriter(os.Stdout, LogFile)
ConsoleLogger = RepairLogger{log.New(mw, "", 0), "console"}
InfoLogger = RepairLogger{log.New(mw, "INFO: ", log.Ldate|log.Ltime), "info"}
DebugLogger = RepairLogger{log.New(LogFile, "DEBUG: ", log.Ldate|log.Ltime|log.Lshortfile), "debug"}
WarningLogger = RepairLogger{log.New(mw, "WARNING: ", 0), "warning"}
ErrorLogger = RepairLogger{log.New(mw, "ERROR: ", 0), "error"}
FatalLogger = RepairLogger{log.New(mw, "FATAL ERROR: ", 0), "fatal"}
InfoLogger.Printf("Log file %s cretaed", LogFile.Name())
}
func RemoveLogFile() {
if _, err := os.Open(LogFile.Name()); err == nil {
_ = os.Remove(LogFile.Name())
}
}
func WriteToLogOnError(err error, log RepairLogger) {
if err != nil {
log.log.Println(err)
}
}
func ExitOnError(err error) {
if err != nil {
FatalLogger.log.Fatal(err)
}
}
func ExitWithExceptionOnError(err error) {
if err != nil {
err = errors.New(string(debug.Stack()) + err.Error())
FatalLogger.log.Fatal(err)
}
}
func (l *RepairLogger) Fatal(v ...interface{}) {
l.log.Fatal(v...)
}
func (l *RepairLogger) Println(v ...interface{}) {
l.log.Println(v...)
}
func (l *RepairLogger) Printf(format string, v ...interface{}) {
l.log.Printf(format, v...)
}
func (l *RepairLogger) SetOutput(w io.Writer) {
l.log.SetOutput(w)
}
+9
View File
@@ -0,0 +1,9 @@
package main
import (
"repair/cmd"
)
func main() {
cmd.Execute()
}