Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* SonarLint Language Server
* Copyright (C) 2009-2023 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonarsource.sonarlint.ls.settings;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.lsp4j.ConfigurationItem;
import org.eclipse.lsp4j.ConfigurationParams;
import org.sonarsource.sonarlint.core.clientapi.backend.rules.StandaloneRuleConfigDto;
import org.sonarsource.sonarlint.ls.SonarLintExtendedLanguageClient;
import org.sonarsource.sonarlint.ls.backend.BackendServiceFacade;
import org.sonarsource.sonarlint.ls.folders.WorkspaceFolderLifecycleListener;
import org.sonarsource.sonarlint.ls.folders.WorkspaceFolderWrapper;
import org.sonarsource.sonarlint.ls.folders.WorkspaceFoldersManager;
import org.sonarsource.sonarlint.ls.log.LanguageClientLogOutput;
import org.sonarsource.sonarlint.ls.util.Utils;
import static java.lang.String.format;
import static java.util.Arrays.stream;
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.sonarsource.sonarlint.ls.util.Utils.interrupted;
public class SettingsManager implements WorkspaceFolderLifecycleListener {
private static final String ORGANIZATION_KEY = "organizationKey";
private static final String DISABLE_NOTIFICATIONS = "disableNotifications";
private static final String PROJECT = "project";
public static final String DEFAULT_CONNECTION_ID = "";
private static final String SERVER_URL = "serverUrl";
private static final String SERVER_ID = "serverId";
private static final String TOKEN = "token";
private static final String CONNECTION_ID = "connectionId";
public static final String SONARLINT_CONFIGURATION_NAMESPACE = "sonarlint";
public static final String DOTNET_DEFAULT_SOLUTION_PATH = "dotnet.defaultSolution";
public static final String OMNISHARP_USE_MODERN_NET = "omnisharp.useModernNet";
public static final String OMNISHARP_LOAD_PROJECT_ON_DEMAND = "omnisharp.enableMsBuildLoadProjectsOnDemand";
public static final String OMNISHARP_PROJECT_LOAD_TIMEOUT = "omnisharp.projectLoadTimeout";
private static final String DISABLE_TELEMETRY = "disableTelemetry";
private static final String RULES = "rules";
private static final String TEST_FILE_PATTERN = "testFilePattern";
static final String ANALYZER_PROPERTIES = "analyzerProperties";
private static final String OUTPUT = "output";
private static final String SHOW_ANALYZER_LOGS = "showAnalyzerLogs";
private static final String SHOW_VERBOSE_LOGS = "showVerboseLogs";
private static final String PATH_TO_NODE_EXECUTABLE = "pathToNodeExecutable";
private static final String PATH_TO_COMPILE_COMMANDS = "pathToCompileCommands";
private static final String FOCUS_ON_NEW_CODE = "focusOnNewCode";
private static final String WORKSPACE_FOLDER_VARIABLE = "${workspaceFolder}";
public static final String SONAR_CS_FILE_SUFFIXES = "sonar.cs.file.suffixes";
private final SonarLintExtendedLanguageClient client;
private final WorkspaceFoldersManager foldersManager;
private WorkspaceSettings currentSettings = null;
private final CountDownLatch initLatch = new CountDownLatch(1);
// Setting that are normally specific per workspace folder, but we also keep a cache of global values to analyze files outside any
// workspace
private WorkspaceFolderSettings currentDefaultSettings = null;
private final ExecutorService executor;
private final List globalListeners = new ArrayList<>();
private final List folderListeners = new ArrayList<>();
private final BackendServiceFacade backendServiceFacade;
private final LanguageClientLogOutput logOutput;
public SettingsManager(SonarLintExtendedLanguageClient client, WorkspaceFoldersManager foldersManager,
BackendServiceFacade backendServiceFacade, LanguageClientLogOutput logOutput) {
this(client, foldersManager, Executors.newCachedThreadPool(Utils.threadFactory("SonarLint settings manager", false)), backendServiceFacade, logOutput);
}
SettingsManager(SonarLintExtendedLanguageClient client, WorkspaceFoldersManager foldersManager,
ExecutorService executor, BackendServiceFacade backendServiceFacade, LanguageClientLogOutput logOutput) {
this.client = client;
this.foldersManager = foldersManager;
this.executor = executor;
this.backendServiceFacade = backendServiceFacade;
this.logOutput = logOutput;
}
/**
* Get workspace level settings, waiting for them to be initialized
*/
public WorkspaceSettings getCurrentSettings() {
try {
if (initLatch.await(1, TimeUnit.MINUTES)) {
return currentSettings;
}
} catch (InterruptedException e) {
interrupted(e, logOutput);
}
throw new IllegalStateException("Unable to get settings in time");
}
public Map getStandaloneRuleConfigByKey() {
var standaloneRuleConfigByKey = new HashMap();
currentSettings.getRuleParameters().forEach(((ruleKey, paramValueByKey) -> {
var active = currentSettings.getIncludedRules().contains(ruleKey);
standaloneRuleConfigByKey.put(ruleKey.toString(), new StandaloneRuleConfigDto(active, paramValueByKey));
}));
return standaloneRuleConfigByKey;
}
/**
* Get default workspace folder level settings, waiting for them to be initialized
*/
public WorkspaceFolderSettings getCurrentDefaultFolderSettings() {
try {
if (initLatch.await(1, TimeUnit.MINUTES)) {
return currentDefaultSettings;
}
} catch (InterruptedException e) {
interrupted(e, logOutput);
}
throw new IllegalStateException("Unable to get settings in time");
}
public void didChangeConfiguration() {
executor.execute(() -> {
try {
var workspaceSettingsMap = requestSonarLintAndOmnisharpConfigurationAsync(null).get(1, TimeUnit.MINUTES);
var newWorkspaceSettings = parseSettings(workspaceSettingsMap);
var oldWorkspaceSettings = currentSettings;
this.currentSettings = newWorkspaceSettings;
var newDefaultFolderSettings = parseFolderSettings(workspaceSettingsMap, null);
var oldDefaultFolderSettings = currentDefaultSettings;
this.currentDefaultSettings = newDefaultFolderSettings;
if (initLatch.getCount() != 0) {
initLatch.countDown();
backendServiceFacade.initialize(getCurrentSettings().getServerConnections());
} else {
backendServiceFacade.didChangeConnections(getCurrentSettings().getServerConnections());
backendServiceFacade.updateStandaloneRulesConfiguration(getStandaloneRuleConfigByKey());
}
foldersManager.getAll().forEach(f -> updateWorkspaceFolderSettings(f, true));
notifyListeners(newWorkspaceSettings, oldWorkspaceSettings, newDefaultFolderSettings, oldDefaultFolderSettings);
} catch (InterruptedException e) {
interrupted(e, logOutput);
} catch (Exception e) {
logOutput.error("Unable to update configuration", e.getMessage());
} finally {
client.readyForTests();
}
});
}
private void notifyListeners(WorkspaceSettings newWorkspaceSettings, WorkspaceSettings oldWorkspaceSettings, WorkspaceFolderSettings newDefaultFolderSettings,
WorkspaceFolderSettings oldDefaultFolderSettings) {
if (!Objects.equals(oldWorkspaceSettings, newWorkspaceSettings)) {
logOutput.debug(format("Global settings updated: %s", newWorkspaceSettings));
globalListeners.forEach(l -> l.onChange(oldWorkspaceSettings, newWorkspaceSettings));
}
if (!Objects.equals(oldDefaultFolderSettings, newDefaultFolderSettings)) {
logOutput.debug(format("Default settings updated: %s", newDefaultFolderSettings));
folderListeners.forEach(l -> l.onChange(null, oldDefaultFolderSettings, newDefaultFolderSettings));
}
}
// Visible for testing
CompletableFuture