Skip to content

Commit df2f1ce

Browse files
committed
fix: Map folder for tools cache
1 parent 0d02771 commit df2f1ce

8 files changed

Lines changed: 73 additions & 49 deletions

File tree

bin/codacy-analysis-cli.sh

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ log_error() {
1010
cat >&2 <<-EOF
1111
We encountered a problem with your Docker setup:
1212
> ${message}
13-
13+
1414
Please check https://github.com/codacy/codacy-analysis-cli for alternative instructions.
15-
15+
1616
EOF
1717
exit 3
1818
}
@@ -25,6 +25,17 @@ test_docker_socket() {
2525
fi
2626
}
2727

28+
set_cache_directory() {
29+
CODACY_CACHE_FOLDER="$(pwd)/.codacy/codacy-analysis-cli"
30+
31+
if [[ "$OSTYPE" == "darwin"* ]]; then
32+
CODACY_CACHE_FOLDER="$HOME/Library/Caches/Codacy/codacy-analysis-cli"
33+
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
34+
CODACY_CACHE_FOLDER="$HOME/.cache/codacy/codacy-analysis-cli"
35+
#TODO: Add support for Windows
36+
fi
37+
}
38+
2839
run() {
2940
local output_volume="";
3041
if [ -n "${OUTPUT_DIRECTORY}" ]; then
@@ -37,10 +48,12 @@ run() {
3748
--env CODACY_PROJECT_TOKEN="$CODACY_PROJECT_TOKEN" \
3849
--env CODACY_API_TOKEN="$CODACY_API_TOKEN" \
3950
--env CODACY_API_BASE_URL="$CODACY_API_BASE_URL" \
51+
--env CODACY_CACHE_FOLDER="$CODACY_CACHE_FOLDER" \
4052
--volume /var/run/docker.sock:/var/run/docker.sock \
4153
--volume "$CODACY_CODE":"$CODACY_CODE" \
4254
${output_volume} \
4355
--volume /tmp:/tmp \
56+
--volume "$CODACY_CACHE_FOLDER":"$CODACY_CACHE_FOLDER" \
4457
codacy/codacy-analysis-cli:${CODACY_ANALYSIS_CLI_VERSION} -- \
4558
"$@"
4659
}
@@ -119,6 +132,8 @@ prep_args_with_output_absolute_path() {
119132

120133
test_docker_socket
121134

135+
set_cache_directory
136+
122137
analysis_file "$@"
123138

124139
prep_args_with_output_absolute_path "$@"

cli/src/main/scala/com/codacy/analysis/cli/command/AnalyseCommand.scala

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ object AnalyseCommand {
5656
Formatter(configuration.analysis.output, environment.baseProjectDirectory(analyze.directory))
5757
val fileCollector: FileCollector[Try] = FileCollector.defaultCollector()
5858

59-
val toolSelector = new ToolSelector(toolRepository(apiUrl))
59+
val toolSelector = new ToolSelector(toolRepository(apiUrl, environment.baseProjectDirectory(analyze.directory)))
6060

6161
val analyseExecutor: AnalyseExecutor =
6262
new AnalyseExecutor(
@@ -71,17 +71,18 @@ object AnalyseCommand {
7171
new AnalyseCommand(analyze, configuration, analyseExecutor, uploaderOpt)
7272
}
7373

74-
private def toolRepository(codacyApiUrl: String) = {
74+
private def toolRepository(codacyApiUrl: String, currentWorkingDirectory: File) = {
7575
val actorSystem = ActorSystem("ToolsServiceActorSystem")
7676
val materializer = akka.stream.ActorMaterializer()(actorSystem)
7777
val httpClient: HttpRequest => Future[HttpResponse] =
7878
Http(actorSystem).singleRequest(_)
7979

8080
val toolsClient =
8181
ToolsClient(codacyApiUrl)(httpClient = httpClient, ec = actorSystem.dispatcher, mat = materializer)
82-
new ToolRepositoryRemote(toolsClient, ToolSpecDataStorage.apply, PatternSpecDataStorage.apply)(
83-
ec = actorSystem.dispatcher,
84-
mat = materializer)
82+
new ToolRepositoryRemote(
83+
toolsClient,
84+
ToolSpecDataStorage(currentWorkingDirectory, _),
85+
PatternSpecDataStorage(currentWorkingDirectory, _))(ec = actorSystem.dispatcher, mat = materializer)
8586
}
8687
}
8788

core/src/main/scala/com/codacy/analysis/core/storage/FileDataStorage.scala

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,23 @@
11
package com.codacy.analysis.core.storage
22

33
import better.files.File
4-
import better.files.File.home
54
import io.circe._
65
import io.circe.syntax._
76
import org.log4s.{Logger, getLogger}
87

98
import scala.util.{Failure, Success, Try}
109

11-
abstract class FileDataStorage[T](val storageFilename: String) {
10+
abstract class FileDataStorage[T](val currentWorkingDirectory: File, val storageFilename: String) {
1211

1312
implicit val encoder: Encoder[T]
1413
implicit val decoder: Decoder[T]
1514

1615
private val logger: Logger = getLogger
1716

1817
private val cacheFolder: File = {
19-
val defaultFolder = File.currentWorkingDirectory / ".codacy" / "codacy-analysis-cli"
20-
val osNameOpt = sys.props.get("os.name").map(_.toLowerCase)
21-
val result = osNameOpt match {
22-
case Some(sysName) if sysName.contains("mac") || sysName == "darwin" =>
23-
home / "Library" / "Caches" / "Codacy" / "codacy-analysis-cli"
24-
25-
case Some(sysName) if sysName.contains("nix") || sysName.contains("nux") =>
26-
home / ".cache" / "codacy" / "codacy-analysis-cli"
27-
28-
case Some(sysName) if sysName.contains("windows") =>
29-
sys.env.get("APPDATA").fold(defaultFolder) { windowsCacheDir =>
30-
File(windowsCacheDir) / "Codacy" / "codacy-analysis-cli"
31-
}
32-
33-
case _ => defaultFolder
34-
}
18+
val defaultFolder = currentWorkingDirectory / ".codacy" / "codacy-analysis-cli"
19+
val cacheFolderOpt = sys.env.get("CODACY_CACHE_FOLDER").map(File(_))
20+
val result = cacheFolderOpt.getOrElse(defaultFolder)
3521

3622
result.createIfNotExists(asDirectory = true, createParents = true)
3723
result
@@ -56,7 +42,7 @@ abstract class FileDataStorage[T](val storageFilename: String) {
5642
}
5743

5844
def save(values: Seq[T]): Boolean = {
59-
logger.debug("Saving new values to storage")
45+
logger.debug(s"Saving new values to storage $storageFile")
6046
val storageListJson = values.asJson.toString
6147
writeToFile(storageListJson) match {
6248
case Success(_) =>

core/src/test/scala/com/codacy/analysis/core/storage/FileDataStorageSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ class FileDataStorageSpec extends Specification with NoLanguageFeatures with Moc
1212

1313
case class Test(name: String)
1414

15-
class StorageTest() extends FileDataStorage[Test]("") {
15+
class StorageTest() extends FileDataStorage[Test](File.currentWorkingDirectory, "") {
1616
override implicit val encoder: Encoder[Test] = deriveEncoder
1717
override implicit val decoder: Decoder[Test] = deriveDecoder
1818

toolRepository-remote/src/main/scala/com/codacy/toolRepository/remote/ToolRepositoryRemote.scala

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,28 @@ class ToolRepositoryRemote(toolsClient: ToolsClient,
2525
private val toolStorageInstance = toolsStorage(toolStorageFilename)
2626

2727
override lazy val list: Either[AnalyserError, Seq[ToolSpec]] = {
28+
toolStorageInstance.get() match {
29+
case Some(toolsFromStorage) =>
30+
logger.info(s"Using tools from cache")
31+
Right(toolsFromStorage)
32+
case None =>
33+
downloadToolsFromApi()
34+
}
35+
}
36+
37+
private def downloadToolsFromApi(): Either[AnalyserError, Seq[ToolSpec]] = {
38+
toolsFromApi() match {
39+
case Right(toolsFromApi) =>
40+
logger.info(s"Fetched tools")
41+
toolStorageInstance.save(toolsFromApi)
42+
Right(toolsFromApi)
43+
case Left(err) =>
44+
logger.error(s"Failed to fetch tools")
45+
Left(err)
46+
}
47+
}
48+
49+
private def toolsFromApi(): Either[AnalyserError, Seq[ToolSpec]] = {
2850
val source = PaginatedApiSourceFactory { cursor =>
2951
toolsClient.listTools(cursor).value.map {
3052
case Right(ListToolsResponse.OK(ToolListResponse(data, None | Some(PaginationInfo(None, _, _))))) =>
@@ -45,14 +67,8 @@ class ToolRepositoryRemote(toolsClient: ToolsClient,
4567
source.runWith(Sink.seq).map(tools => Right(tools.map(toToolSpec))).recover {
4668
case e: Exception => Left(AnalyserError.FailedToFetchTools(e.getMessage))
4769
}
48-
val result = Await.result(toolsF, 1 minute)
49-
result match {
50-
case Right(tools) =>
51-
toolStorageInstance.save(tools)
52-
Right(tools)
53-
case Left(err) =>
54-
toolStorageInstance.get().toRight(err)
55-
}
70+
71+
Await.result(toolsF, 1 minute)
5672
}
5773

5874
override def get(uuid: String): Either[AnalyserError, ToolSpec] =

toolRepository-remote/src/main/scala/com/codacy/toolRepository/remote/storage/PatternSpecDataStorage.scala

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package com.codacy.toolRepository.remote.storage
33
import com.codacy.analysis.core.model.PatternSpec
44
import com.codacy.analysis.core.storage.FileDataStorage
55
import io.circe.{Decoder, Encoder}
6+
import better.files.File
67

7-
case class PatternSpecDataStorage(override val storageFilename: String)
8-
extends FileDataStorage[PatternSpec](storageFilename) {
8+
case class PatternSpecDataStorage(override val currentWorkingDirectory: File, override val storageFilename: String)
9+
extends FileDataStorage[PatternSpec](currentWorkingDirectory, storageFilename) {
910

1011
override implicit val encoder: Encoder[PatternSpec] =
1112
ToolPatternsSpecsEncoders.toolPatternEncoder

toolRepository-remote/src/main/scala/com/codacy/toolRepository/remote/storage/ToolSpecDataStorage.scala

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@ package com.codacy.toolRepository.remote.storage
33
import com.codacy.analysis.core.model.ToolSpec
44
import com.codacy.analysis.core.storage.FileDataStorage
55
import io.circe.{Decoder, Encoder}
6+
import better.files.File
67

7-
case class ToolSpecDataStorage(override val storageFilename: String = "tools")
8-
extends FileDataStorage[ToolSpec](storageFilename) {
8+
case class ToolSpecDataStorage(override val currentWorkingDirectory: File,
9+
override val storageFilename: String = "tools")
10+
extends FileDataStorage[ToolSpec](currentWorkingDirectory, storageFilename) {
911

1012
override implicit val encoder: Encoder[ToolSpec] =
1113
ToolPatternsSpecsEncoders.toolEncoder

toolRepository-remote/src/test/scala/com/codacy/toolRespository/remote/ToolRepositoryRemoteSpec.scala

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.codacy.toolRespository.remote
33
import akka.actor.ActorSystem
44
import akka.http.scaladsl.model.{HttpHeader, HttpResponse}
55
import akka.stream.ActorMaterializer
6+
import better.files.File
67
import cats.data.EitherT
78
import com.codacy.analysis.clientapi.definitions._
89
import com.codacy.analysis.clientapi.tools.{ListPatternsResponse, ListToolsResponse, ToolsClient}
@@ -92,29 +93,31 @@ class ToolRepositoryRemoteSpec extends Specification with Mockito with EitherMat
9293
private val patternA: Pattern = getPattern("internalId - A")
9394
private val patternB: Pattern = getPattern("internalId - B")
9495

95-
val mockToolsDataEmptyStorage: ToolSpecDataStorage = new ToolSpecDataStorage {
96+
val mockToolsDataEmptyStorage: ToolSpecDataStorage = new ToolSpecDataStorage(File.currentWorkingDirectory) {
9697
override def save(tools: Seq[ToolSpec]): Boolean = true
9798

9899
override def get(): Option[Seq[ToolSpec]] = None
99100
}
100101

101-
val mockToolsDataWithStorage: ToolSpecDataStorage = new ToolSpecDataStorage {
102+
val mockToolsDataWithStorage: ToolSpecDataStorage = new ToolSpecDataStorage(File.currentWorkingDirectory) {
102103
override def save(tools: Seq[ToolSpec]): Boolean = true
103104

104105
override def get(): Option[Seq[ToolSpec]] = Some(Seq(toolSpec(toolA.uuid)))
105106
}
106107

107-
val mockPatternDataEmptyStorage: PatternSpecDataStorage = new PatternSpecDataStorage(toolA.uuid) {
108-
override def save(tools: Seq[PatternSpec]): Boolean = true
108+
val mockPatternDataEmptyStorage: PatternSpecDataStorage =
109+
new PatternSpecDataStorage(File.currentWorkingDirectory, toolA.uuid) {
110+
override def save(tools: Seq[PatternSpec]): Boolean = true
109111

110-
override def get(): Option[Seq[PatternSpec]] = None
111-
}
112+
override def get(): Option[Seq[PatternSpec]] = None
113+
}
112114

113-
val mockPatternDataWithStorage: PatternSpecDataStorage = new PatternSpecDataStorage(toolA.uuid) {
114-
override def save(tools: Seq[PatternSpec]): Boolean = true
115+
val mockPatternDataWithStorage: PatternSpecDataStorage =
116+
new PatternSpecDataStorage(File.currentWorkingDirectory, toolA.uuid) {
117+
override def save(tools: Seq[PatternSpec]): Boolean = true
115118

116-
override def get(): Option[Seq[PatternSpec]] = Some(Seq(patternSpec(patternA.id)))
117-
}
119+
override def get(): Option[Seq[PatternSpec]] = Some(Seq(patternSpec(patternA.id)))
120+
}
118121

119122
def eitherListToolsResponse(
120123
listToolsResponse: ListToolsResponse): EitherT[Future, Either[Throwable, HttpResponse], ListToolsResponse] = {

0 commit comments

Comments
 (0)