aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache
diff options
context:
space:
mode:
Diffstat (limited to 'sonar-scanner-engine/src/main/java/org/sonar/scanner/cache')
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheEnabled.java35
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheLoader.java87
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheMemoryStorage.java59
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheProvider.java83
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheStorage.java30
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ReadCacheImpl.java47
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ScannerWriteCache.java27
-rw-r--r--sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/WriteCacheImpl.java81
8 files changed, 449 insertions, 0 deletions
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheEnabled.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheEnabled.java
new file mode 100644
index 00000000000..b93150ae944
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheEnabled.java
@@ -0,0 +1,35 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import org.sonar.api.config.Configuration;
+
+public class AnalysisCacheEnabled {
+ static final String PROP_KEY = "sonar.analysisCache.enabled";
+ private final Configuration configuration;
+
+ public AnalysisCacheEnabled(Configuration configuration) {
+ this.configuration = configuration;
+ }
+
+ public boolean isEnabled() {
+ return configuration.getBoolean(PROP_KEY).orElse(false);
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheLoader.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheLoader.java
new file mode 100644
index 00000000000..420a5d5f852
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheLoader.java
@@ -0,0 +1,87 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.util.Optional;
+import java.util.zip.InflaterInputStream;
+import org.sonar.api.scanner.fs.InputProject;
+import org.sonar.core.util.Protobuf;
+import org.sonar.scanner.bootstrap.DefaultScannerWsClient;
+import org.sonar.scanner.protocol.internal.ScannerInternal;
+import org.sonar.scanner.protocol.internal.ScannerInternal.AnalysisCacheMsg;
+import org.sonar.scanner.scan.branch.BranchConfiguration;
+import org.sonar.scanner.scan.branch.BranchType;
+import org.sonarqube.ws.client.GetRequest;
+import org.sonarqube.ws.client.WsResponse;
+
+/**
+ * Loads plugin cache into the local storage
+ */
+public class AnalysisCacheLoader {
+ static final String CONTENT_ENCODING = "Content-Encoding";
+ static final String ACCEPT_ENCODING = "Accept-Encoding";
+ private static final String URL = "api/scanner_cache/get";
+
+ private final DefaultScannerWsClient wsClient;
+ private final InputProject project;
+ private final BranchConfiguration branchConfiguration;
+
+ public AnalysisCacheLoader(DefaultScannerWsClient wsClient, InputProject project, BranchConfiguration branchConfiguration) {
+ this.project = project;
+ this.branchConfiguration = branchConfiguration;
+ this.wsClient = wsClient;
+ }
+
+ public Optional<AnalysisCacheMsg> load() {
+ String url = URL + "?project=" + project.key();
+ if (branchConfiguration.branchType() == BranchType.BRANCH && branchConfiguration.branchName() != null) {
+ url = url + "&branch=" + branchConfiguration.branchName();
+ }
+
+ GetRequest request = new GetRequest(url).setHeader(ACCEPT_ENCODING, "gzip");
+
+ try (WsResponse response = wsClient.call(request)) {
+ if (response.code() == HttpURLConnection.HTTP_NOT_FOUND) {
+ return Optional.empty();
+ }
+ try (InputStream is = response.contentStream()) {
+ Optional<String> contentEncoding = response.header(CONTENT_ENCODING);
+ if (contentEncoding.isPresent() && contentEncoding.get().equals("gzip")) {
+ return Optional.of(decompress(is));
+ } else {
+ return Optional.of(Protobuf.read(is, AnalysisCacheMsg.parser()));
+ }
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to download cache", e);
+ }
+ }
+ }
+
+ private static AnalysisCacheMsg decompress(InputStream is) {
+ try (InflaterInputStream iis = new InflaterInputStream(is)) {
+ return Protobuf.read(iis, ScannerInternal.AnalysisCacheMsg.parser());
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to decompress plugin cache", e);
+ }
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheMemoryStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheMemoryStorage.java
new file mode 100644
index 00000000000..420bd1711a8
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheMemoryStorage.java
@@ -0,0 +1,59 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.io.InputStream;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.scanner.protocol.internal.ScannerInternal.AnalysisCacheMsg;
+
+public class AnalysisCacheMemoryStorage implements AnalysisCacheStorage {
+ private final AnalysisCacheLoader loader;
+ @Nullable
+ private AnalysisCacheMsg cache;
+
+ public AnalysisCacheMemoryStorage(AnalysisCacheLoader loader) {
+ this.loader = loader;
+ }
+
+ @Override
+ @CheckForNull
+ public InputStream get(String key) {
+ if (cache == null) {
+ return null;
+ }
+ if (cache.containsMap(key)) {
+ return cache.getMapOrThrow(key).newInput();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean contains(String key) {
+ if (cache == null) {
+ return false;
+ }
+ return cache.containsMap(key);
+ }
+
+ public void load() {
+ cache = loader.load().orElse(null);
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheProvider.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheProvider.java
new file mode 100644
index 00000000000..b340261f569
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheProvider.java
@@ -0,0 +1,83 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.io.InputStream;
+import java.util.Map;
+import org.jetbrains.annotations.Nullable;
+import org.sonar.api.batch.sensor.cache.ReadCache;
+import org.springframework.context.annotation.Bean;
+
+import static java.util.Collections.emptyMap;
+
+public class AnalysisCacheProvider {
+ @Bean("ReadCache")
+ public ReadCache provideReader(AnalysisCacheEnabled analysisCacheEnabled, AnalysisCacheMemoryStorage storage) {
+ if (analysisCacheEnabled.isEnabled()) {
+ storage.load();
+ return new ReadCacheImpl(storage);
+ }
+ return new NoOpReadCache();
+ }
+
+ @Bean("WriteCache")
+ public ScannerWriteCache provideWriter(AnalysisCacheEnabled analysisCacheEnabled, ReadCache readCache) {
+ if (analysisCacheEnabled.isEnabled()) {
+ return new WriteCacheImpl(readCache);
+ }
+ return new NoOpWriteCache();
+ }
+
+
+ static class NoOpWriteCache implements ScannerWriteCache {
+ @Override
+ public void write(String s, InputStream inputStream) {
+ // no op
+ }
+
+ @Override
+ public void write(String s, byte[] bytes) {
+ // no op
+ }
+
+ @Override
+ public void copyFromPrevious(String s) {
+ // no op
+ }
+
+ @Override
+ public Map<String, byte[]> getCache() {
+ return emptyMap();
+ }
+ }
+
+ static class NoOpReadCache implements ReadCache {
+ @Nullable
+ @Override
+ public InputStream read(String s) {
+ return null;
+ }
+
+ @Override
+ public boolean contains(String s) {
+ return false;
+ }
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheStorage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheStorage.java
new file mode 100644
index 00000000000..5fb7765da38
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/AnalysisCacheStorage.java
@@ -0,0 +1,30 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.io.InputStream;
+import javax.annotation.CheckForNull;
+
+public interface AnalysisCacheStorage {
+ @CheckForNull
+ InputStream get(String key);
+
+ boolean contains(String key);
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ReadCacheImpl.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ReadCacheImpl.java
new file mode 100644
index 00000000000..4a94e0ae7b0
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ReadCacheImpl.java
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.io.InputStream;
+import org.sonar.api.batch.sensor.cache.ReadCache;
+
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkNotNull;
+
+public class ReadCacheImpl implements ReadCache {
+ private final AnalysisCacheStorage cache;
+
+ public ReadCacheImpl(AnalysisCacheStorage storage) {
+ this.cache = storage;
+ }
+
+ @Override
+ public InputStream read(String key) {
+ checkNotNull(key);
+ checkArgument(contains(key));
+ return cache.get(key);
+ }
+
+ @Override
+ public boolean contains(String key) {
+ checkNotNull(key);
+ return cache.contains(key);
+ }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ScannerWriteCache.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ScannerWriteCache.java
new file mode 100644
index 00000000000..4087db134b5
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/ScannerWriteCache.java
@@ -0,0 +1,27 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.util.Map;
+import org.sonar.api.batch.sensor.cache.WriteCache;
+
+public interface ScannerWriteCache extends WriteCache {
+ Map<String, byte[]> getCache();
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/WriteCacheImpl.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/WriteCacheImpl.java
new file mode 100644
index 00000000000..adeb6216d23
--- /dev/null
+++ b/sonar-scanner-engine/src/main/java/org/sonar/scanner/cache/WriteCacheImpl.java
@@ -0,0 +1,81 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2022 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.sonar.scanner.cache;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import org.sonar.api.batch.sensor.cache.ReadCache;
+
+import static java.util.Collections.unmodifiableMap;
+import static org.sonar.api.utils.Preconditions.checkArgument;
+import static org.sonar.api.utils.Preconditions.checkNotNull;
+
+public class WriteCacheImpl implements ScannerWriteCache {
+ private final ReadCache readCache;
+ private final Map<String, byte[]> cache = new HashMap<>();
+
+ public WriteCacheImpl(ReadCache readCache) {
+ this.readCache = readCache;
+ }
+
+ @Override
+ public void write(String key, InputStream data) {
+ checkNotNull(data);
+ checkKey(key);
+ try {
+ byte[] arr = data.readAllBytes();
+ cache.put(key, arr);
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to read stream", e);
+ }
+ }
+
+ @Override
+ public void write(String key, byte[] data) {
+ checkNotNull(data);
+ checkKey(key);
+ cache.put(key, Arrays.copyOf(data, data.length));
+ }
+
+ @Override
+ public void copyFromPrevious(String key) {
+ checkArgument(readCache.contains(key), "Previous cache doesn't contain key '%s'", key);
+ checkKey(key);
+
+ try {
+ cache.put(key, readCache.read(key).readAllBytes());
+ } catch (IOException e) {
+ throw new IllegalStateException("Failed to read plugin cache for key " + key, e);
+ }
+ }
+
+ @Override
+ public Map<String, byte[]> getCache() {
+ return unmodifiableMap(cache);
+ }
+
+ private void checkKey(String key) {
+ checkNotNull(key);
+ checkArgument(!cache.containsKey(key), "Cache already contains key '%s'", key);
+ }
+}