better.files.File Scala Examples

The following examples show how to use better.files.File. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: WorkspaceTests.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.workspacehandling

import better.files.Dsl._
import better.files.File
import io.shiftleft.semanticcpg.testing.MockCpg
import org.scalatest.{Matchers, WordSpec}

import scala.collection.mutable.ListBuffer

class WorkspaceTests extends WordSpec with Matchers {

  "toString" should {

    "return an \"empty\" when no projects are present" in {
      val workspace = new Workspace(ListBuffer())
      workspace.toString shouldBe "empty"
    }

    "return a valid row for a project" in {
      File.usingTemporaryDirectory("project") { project =>
        mkdir(project / "overlays")
        val inputPath = "/input/path"
        val projectFile = ProjectFile(inputPath, project.name)
        val cpg = MockCpg().withMetaData("C", List("foo", "bar"), List()).cpg
        val projects = ListBuffer(
          Project(projectFile, project.path, Some(cpg))
        )
        val workspace = new Workspace(projects)
        val output = workspace.toString
        val lines = output.split("\n")
        lines.length shouldBe 5
        lines(4).contains(project.name) shouldBe true
        lines(4).contains(inputPath)
        lines(4).contains("foo,bar")
      }

    }

  }

}

object WorkspaceTests {

  def createFakeProject(workspaceFile: File, projectName: String): File = {
    mkdir(workspaceFile / projectName)
    mkdir(workspaceFile / projectName / "overlays")
    (workspaceFile / projectName / "project.json")
      .write(s"""{"inputPath":"foo","name":"$projectName"}""")
    touch(workspaceFile / projectName / "cpg.bin")
  }

} 
Example 2
Source File: ExtractScriptGenConfig.scala    From comet-data-pipeline   with Apache License 2.0 5 votes vote down vote up
package com.ebiznext.comet.database.extractor

import better.files.File
import scopt.{OParser, RenderingMode}

case class ExtractScriptGenConfig(
  domain: String = "",
  scriptTemplateFile: File = File("."),
  scriptOutputDir: File = File(".")
)

object ExtractScriptGenConfig {

  val builder = OParser.builder[ExtractScriptGenConfig]

  def exists(name: String)(path: String): Either[String, Unit] =
    if (File(path).exists) Right(())
    else Left(s"$name at path $path does not exist")

  val parser: OParser[Unit, ExtractScriptGenConfig] = {
    import builder._
    OParser.sequence(
      programName("comet"),
      head("comet", "1.x"),
      note(
        """
          |The schemas should at least, specify :
          |     - a table name (schemas.name)
          |     - a file pattern (schemas.pattern) which is used as the export file base name
          |     - a write mode (schemas.metadata.write): APPEND or OVERWRITE
          |     - a delta column (schemas.merge.timestamp) if in APPEND mode : the column which is used to determine new rows for each exports
          |     - the columns to extract (schemas.attributes.name*)
          |
          |You also have to provide a Mustache (http://mustache.github.io/mustache.5.html) template file.
          |
          |In there you'll write your extraction export process (sqlplus for Oracle, pgsql for PostgreSQL as an example).
          |In that template you can use the following parameters:
          | - table_name  -> the table to export
          | - delimiter   -> the resulting dsv file delimiter
          | - columns     -> the columns to export
          |   columns is a Mustache map, it gives you access, for each column, to:
          |    - name               -> the column name
          |    - trailing_col_char  -> the separator to append to the column (, if there are more columns to come, "" otherwise)
          |                            Here is an example how to use it in a template:
          |                              SELECT
          |                              {{#columns}}
          |                              TO_CHAR({{name}}){{trailing_col_char}}
          |                              {{/columns}}
          |                              FROM
          |                              {{table_name}};
          | export_file -> the export file name
          | full_export -> if the export is a full or delta export (the logic is to be implemented in your script)
          |""".stripMargin
      ),
      cmd("script-gen"),
      opt[String]("domain")
        .action((x, c) => c.copy(domain = x))
        .required()
        .text("The domain for which to generate extract scripts"),
      opt[String]("templateFile")
        .validate(exists("Script template file"))
        .action((x, c) => c.copy(scriptTemplateFile = File(x)))
        .required()
        .text("Script template file"),
      opt[String]("scriptsOutputDir")
        .validate(exists("Script output folder"))
        .action((x, c) => c.copy(scriptOutputDir = File(x)))
        .required()
        .text("Scripts output folder")
    )
  }
  val usage: String = OParser.usage(parser, RenderingMode.TwoColumns)

  
  def parse(args: Seq[String]): Option[ExtractScriptGenConfig] =
    OParser.parse(parser, args, ExtractScriptGenConfig.apply())
} 
Example 3
Source File: Unpacker.scala    From comet-data-pipeline   with Apache License 2.0 5 votes vote down vote up
package com.ebiznext.comet.utils

import java.io.{BufferedInputStream, InputStream}
import java.nio.file.{Files, Paths}

import better.files.File
import org.apache.commons.compress.archivers.{
  ArchiveEntry,
  ArchiveInputStream,
  ArchiveStreamFactory
}
import org.apache.commons.compress.compressors.{CompressorInputStream, CompressorStreamFactory}
import org.apache.commons.compress.utils.IOUtils
import org.apache.commons.io.input.CloseShieldInputStream

import scala.util.Try

object Unpacker {

  def unpack(archiveFile: File, directory: File): Try[Unit] = {
    for {
      inputStream <- Try(Files.newInputStream(Paths.get(archiveFile.pathAsString)))
      it          <- open(inputStream)
    } yield {
      while (it.hasNext) {
        val (entry, is) = it.next()
        if (entry.isDirectory) {
          throw new Exception("Compressed archive cannot directories")
        }
        val targetFile = File(directory, entry.getName)
        val o = Files.newOutputStream(targetFile.path)
        try {
          IOUtils.copy(is, o)
        } finally {
          if (o != null) o.close()
        }
      }
    }
  }

  // https://alexwlchan.net/2019/09/unpacking-compressed-archives-in-scala/
  
  def open(inputStream: InputStream): Try[Iterator[(ArchiveEntry, InputStream)]] =
    for {
      uncompressedInputStream <- createUncompressedStream(inputStream)
      archiveInputStream      <- createArchiveStream(uncompressedInputStream)
      iterator = createIterator(archiveInputStream)
    } yield iterator

  private def createUncompressedStream(inputStream: InputStream): Try[CompressorInputStream] =
    Try {
      new CompressorStreamFactory().createCompressorInputStream(
        getMarkableStream(inputStream)
      )
    }

  private def createArchiveStream(
    uncompressedInputStream: CompressorInputStream
  ): Try[ArchiveInputStream] =
    Try {
      new ArchiveStreamFactory()
        .createArchiveInputStream(
          getMarkableStream(uncompressedInputStream)
        )
    }

  private def createIterator(
    archiveInputStream: ArchiveInputStream
  ): Iterator[(ArchiveEntry, InputStream)] =
    new Iterator[(ArchiveEntry, InputStream)] {
      var latestEntry: ArchiveEntry = _

      override def hasNext: Boolean = {
        latestEntry = archiveInputStream.getNextEntry
        latestEntry != null
      }

      override def next(): (ArchiveEntry, InputStream) =
        (latestEntry, new CloseShieldInputStream(archiveInputStream))
    }

  private def getMarkableStream(inputStream: InputStream): InputStream =
    if (inputStream.markSupported())
      inputStream
    else
      new BufferedInputStream(inputStream)

} 
Example 4
Source File: ModelsGen.scala    From bay-scalajs.g8   with Apache License 2.0 5 votes vote down vote up
package app.swagger

import app.SwaggerCodegen.property2Scala
import better.files.File
import io.swagger.models.Swagger
import utils.CaseClassMetaHelper
import utils.ScalaFmtHelper
import scala.meta._
import scala.meta.Source
import scala.meta.Stat
import better.files._
import scala.collection.JavaConversions._
import app._

object ModelsGen {
  def gen(swagger: Swagger, apiVersion: String, f: File): Unit = {
    println(s"- Starting Models Generator for ${f.pathAsString}")
    val modelsFolder = file"shared/src/main/scala/shared/models/swagger/${f.nameWithoutExtension}/$apiVersion"

    swagger.getDefinitions.toVector.foreach {
      case (name, model) =>
        val modelName = name.toUpperCamelCase

        val propertiesAsScala: Vector[String] = model.getProperties.toVector.map { e =>
          s"${e._1.toCamelCase}: ${property2Scala(e._2)}"
        }

        val modelAsCaseClass = s"case class $modelName(${propertiesAsScala.mkString(", ")})"

        val targetFile = modelsFolder./(s"$modelName.scala")
        if (targetFile.notExists) {
          // Create Template
          val template =
            s"""
               |package shared.models.swagger.${f.nameWithoutExtension}.$apiVersion
               |
            |import java.time._
               |
            |$modelAsCaseClass
          """.trim.stripMargin

          targetFile.createIfNotExists(createParents = true).overwrite(template)
        } else {
          // Update existing Source
          val source = targetFile.toJava.parse[Source].get
          val caseClassStat =
            modelAsCaseClass.parse[Stat].get
          val tree = CaseClassMetaHelper.updateOrInsert(source, caseClassStat)
          targetFile.write(ScalaFmtHelper.formatCode(tree.syntax))
        }
    }
  }

} 
Example 5
Source File: Runner.scala    From sansible   with MIT License 5 votes vote down vote up
package ansible

import scala.io.Source
import scala.sys.process.{Process, ProcessIO}

import ansible.IniEncode._
import ansible.IniEncoders._
import better.files.File
import com.typesafe.scalalogging.LazyLogging

object Runner extends LazyLogging {
  def runPlaybook(inv: Inventory)(pb: Playbook, opts: Option[String] = None): Unit = {
    val invFile = File.newTemporaryFile("ansible-inventory")
    val pbFile  = File.newTemporaryFile("ansible-playbook", ".yml")

    val pio = new ProcessIO(
      _ => (),
      out  => Source.fromInputStream(out).getLines.foreach(println),
      err => Source.fromInputStream(err).getLines.foreach(System.err.println)
    )

    val cmd = s"ansible-playbook ${opts.getOrElse("")} -i ${invFile.path} ${pbFile.path}"
    val env = Seq("ANSIBLE_FORCE_COLOR" -> "true")
    val process = Process(cmd, cwd = None, env: _*).run(pio)

    invFile.write(inv.iniEncode)
    pbFile.write(YAML.fromPlaybook(pb))
    logger.info(cmd)

    val exitCode = process.exitValue()
    logger.info(s"run completed with exit code: $exitCode")
    process.destroy()
  }
} 
Example 6
Source File: Utils.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.localfaas

import java.io.FileInputStream

import better.files.File
import org.apache.commons.compress.archivers.{ArchiveEntry, ArchiveStreamFactory}
import org.apache.commons.compress.utils.IOUtils

import scala.util.{Failure, Try}

object Utils {
  def unzip(source: File, target: File): Unit = {
    val inputStream   = new FileInputStream(source.path.toFile)
    val archiveStream = new ArchiveStreamFactory().createArchiveInputStream(ArchiveStreamFactory.ZIP, inputStream)

    def stream: Stream[ArchiveEntry] = archiveStream.getNextEntry match {
      case null  => Stream.empty
      case entry => entry #:: stream
    }

    def closeStreams = {
      archiveStream.close()
      inputStream.close()
    }

    Try {
      for (entry <- stream if !entry.isDirectory) {
        val outFile = (target / entry.getName).createIfNotExists(asDirectory = false, createParents = true).clear()
        val os      = outFile.newOutputStream

        Try { IOUtils.copy(archiveStream, os) } match {
          case Failure(e) => os.close(); throw e
          case _          => os.close()
        }
      }
    } match {
      case Failure(e) => closeStreams; throw e
      case _          => closeStreams
    }
  }
} 
Example 7
Source File: MappingActor.scala    From graphcool-framework   with Apache License 2.0 5 votes vote down vote up
package cool.graph.localfaas.actors

import akka.actor.Actor
import better.files.File
import cool.graph.localfaas.actors.MappingActor.{GetHandler, HandlerMap, SaveMapping}
import play.api.libs.json._

import scala.collection.mutable

object MappingActor {
  case class SaveMapping(projectId: String, functionName: String, handlerPath: String)
  case class GetHandler(projectId: String, functionName: String)

  type HandlerMap = mutable.HashMap[String, mutable.HashMap[String, String]]
}

case class MappingActor(handlerFile: File) extends Actor {
  import Conversions._

  // projectId -> functionName -> handlerPath
  val handlers = loadHandlers

  // load handlers on creation
  def loadHandlers: HandlerMap = {
    val content = handlerFile.contentAsString

    if (handlerFile.contentAsString.isEmpty) {
      new HandlerMap
    } else {
      Json.parse(content).validate[HandlerMap] match {
        case JsSuccess(result, _) => println("Using mapping from file."); result
        case JsError(_)           => println("Unable to parse handler map from file, using empty map."); new HandlerMap
      }
    }
  }

  def flush(): Unit = {
    val compactJson: String = Json.stringify(Json.toJson(handlers))
    handlerFile.overwrite(compactJson)
  }

  override def receive: Receive = {
    case GetHandler(pid, fnName) =>
      val projectHandlerMap = handlers.getOrElse(pid, new mutable.HashMap[String, String]())
      sender ! projectHandlerMap.getOrElse(fnName, "")

    case SaveMapping(pid, fnName, handlerPath) =>
      val projectHandlerMap = handlers.getOrElseUpdate(pid, new mutable.HashMap[String, String]())
      projectHandlerMap += fnName -> handlerPath
      flush()
  }
} 
Example 8
Source File: Operations.scala    From databus-maven-plugin   with GNU Affero General Public License v3.0 5 votes vote down vote up
package org.dbpedia.databus

import java.util

import better.files.File
import com.typesafe.scalalogging.LazyLogging
import org.apache.maven.plugin.AbstractMojo
import org.apache.maven.plugins.annotations.Parameter

object skipmodules {
  var skipmodules = false
}

abstract class Operations extends AbstractMojo with LazyLogging with Properties {

  @Parameter(
    property = "modules",
    defaultValue = "${project.modules}"
  )
  val modules: util.ArrayList[String] = new util.ArrayList[String]

  def listFiles(): List[File] = {
    val dir = File(s"$version")
    if (dir.isDirectory) {
      dir.list.toList
    } else {
      List[File]()
    }
  }

  def listFiles(artifact: String): List[File] = {
    val dir = File(s"$artifact/$version")
    if (dir.isDirectory) {
      dir.list.toList
    } else {
      List[File]()
    }

  }

} 
Example 9
Source File: RemoveVersion.scala    From databus-maven-plugin   with GNU Affero General Public License v3.0 5 votes vote down vote up
package org.dbpedia.databus

import java.util

import better.files.File
import com.typesafe.scalalogging.LazyLogging
import org.apache.maven.plugin.{AbstractMojo, MojoExecutionException}
import org.apache.maven.plugins.annotations.{LifecyclePhase, Mojo, Parameter}



@Mojo(name = "rm", requiresOnline = true, threadSafe = true)
class RemoveVersion extends Operations {


  @throws[MojoExecutionException]
  override def execute(): Unit = {

    getLog.info("the following version folders will be deleted:")

    if (isParent()) {
      skipmodules.skipmodules = true
      modules.forEach(m => {
        getLog.info(
          s"""${listFiles(m).size} files in ${File(s"$m/$version").toJava.getAbsoluteFile}""".stripMargin)
      })

      getLog.info("proceed? [y/N]")
      val c: String = scala.io.StdIn.readLine()
      if (c.trim.equalsIgnoreCase("y")) {
        getLog.info("deleting")
        modules.forEach(m => {
          //DELETE
          val vdir = File(s"$m/$version")
          vdir.delete(true)
          getLog.info(s"${!vdir.isDirectory} $vdir")
        })


      }else {
        println(s"aborted, read '$c'")
      }


    } else {
      if (!skipmodules.skipmodules) {
        getLog.info(
          s"""##########
             |databus:rm works only on group to delete current version of all artifacts, use:
             |rm -r $artifactId/$version"
           """.stripMargin)
      }
      return
    }
  }

} 
Example 10
Source File: ListVersionFiles.scala    From databus-maven-plugin   with GNU Affero General Public License v3.0 5 votes vote down vote up
package org.dbpedia.databus

import better.files.File
import org.apache.maven.plugin.MojoExecutionException
import org.apache.maven.plugins.annotations.Mojo



@Mojo(name = "ls", requiresOnline = true, threadSafe = true)
class ListVersionFiles extends Operations {

  val separator = ", "

  @throws[MojoExecutionException]
  override def execute(): Unit = {


    if (isParent()) {
      skipmodules.skipmodules = true
      modules.forEach(m => {
        //todo .map(_.relativize(File("")))
        getLog.info(
          s"""$m/$version (${listFiles(m).size} files)
             |${listFiles(m).mkString(separator)}
           """.stripMargin)

      })
    } else {
      if (skipmodules.skipmodules) {
        return
      }
      getLog.info(
        s"""$artifactId/$version  (${listFiles().size} files)
           |${listFiles().mkString(separator)}
           """.stripMargin)
    }

  }

} 
Example 11
Source File: WorkspaceLoaderTests.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.workspacehandling

import better.files.Dsl.mkdir
import better.files.File
import org.scalatest.{Matchers, WordSpec}

import scala.reflect.io.Directory

class WorkspaceLoaderTests extends WordSpec with Matchers {

  private val tmpDirPrefix = "workspace-tests"

  "WorkspaceLoader" should {

    "create workspace and workspace directory if nonexistent" in {
      val dir = File.newTemporaryDirectory(tmpDirPrefix)
      new Directory(dir.toJava).deleteRecursively()
      TestLoader().load(dir.path.toString)
      try {
        dir.exists shouldBe true
      } finally {
        new Directory(dir.toJava).deleteRecursively()
      }
    }

    "handle broken project.json gracefully by skipping project" in {
      File.usingTemporaryDirectory(tmpDirPrefix) { tmpDir =>
        mkdir(tmpDir / "1")
        (tmpDir / "1" / "project.json").write("{foo")
        TestLoader().load(tmpDir.path.toString).numberOfProjects shouldBe 0
      }
    }

    "load project correctly" in {
      File.usingTemporaryDirectory(tmpDirPrefix) { tmpDir =>
        val projectName = "foo"
        WorkspaceTests.createFakeProject(tmpDir, projectName)
        val project = TestLoader().loadProject((tmpDir / projectName).path)
        project match {
          case Some(p) =>
            p.name shouldBe "foo"
            p.inputPath shouldBe "foo"
            p.cpg shouldBe None
          case None => fail
        }
      }
    }

    "initialize workspace's project list correctly" in {
      File.usingTemporaryDirectory(tmpDirPrefix) { tmpDir =>
        val projectName = "foo"
        WorkspaceTests.createFakeProject(tmpDir, projectName)
        val workspace = TestLoader().load(tmpDir.toString)
        workspace.numberOfProjects shouldBe 1
      }
    }
  }

  "ProjectFile" should {

    import org.json4s.DefaultFormats
    import org.json4s.native.Serialization.{read => jsonRead, write => jsonWrite}
    implicit val formats: DefaultFormats.type = DefaultFormats

    "be serializable to json" in {
      jsonWrite(ProjectFile("foo", "aname")) shouldBe """{"inputPath":"foo","name":"aname"}"""
    }

    "be deserializable from json" in {
      val projectFile = jsonRead[ProjectFile]("""{"inputPath":"foo","name":"aname"}""")
      projectFile.inputPath shouldBe "foo"
      projectFile.name shouldBe "aname"
    }

  }

} 
Example 12
Source File: TemplateParamsSpec.scala    From comet-data-pipeline   with Apache License 2.0 5 votes vote down vote up
package com.ebiznext.comet.database.extractor

import java.util.regex.Pattern

import better.files.File
import com.ebiznext.comet.schema.model._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class TemplateParamsSpec extends AnyFlatSpec with Matchers {
  val scriptOutputFolder: File = File("/tmp")

  "fromSchema" should "generate the correct TemplateParams for a given Schema" in {
    val schema: Schema = Schema(
      name = "table1",
      pattern = Pattern.compile("output_file.*.csv"),
      List(Attribute(name = "col1"), Attribute(name = "col2")),
      metadata = Option(Metadata(write = Some(WriteMode.APPEND))),
      merge = Some(MergeOptions(List("col1", "col2"), None, timestamp = Some("updateCol"))),
      comment = None,
      presql = None,
      postsql = None
    )

    val expectedTemplateParams = TemplateParams(
      tableToExport = "table1",
      columnsToExport = List("col1", "col2"),
      fullExport = false,
      dsvDelimiter = ",",
      deltaColumn = Some("updateCol"),
      exportOutputFileBase = "output_file",
      scriptOutputFile = scriptOutputFolder / "EXTRACT_table1.sql"
    )
    TemplateParams.fromSchema(schema, scriptOutputFolder) shouldBe expectedTemplateParams
  }

  it should "generate the correct TemplateParams for an other Schema" in {
    val schema: Schema = Schema(
      name = "table1",
      pattern = Pattern.compile("output_file.*.csv"),
      List(Attribute(name = "col1"), Attribute(name = "col2")),
      metadata = Option(Metadata(write = Some(WriteMode.OVERWRITE), separator = Some("|"))),
      merge = Some(MergeOptions(List("col1", "col2"), None, timestamp = Some("updateCol"))),
      comment = None,
      presql = None,
      postsql = None
    )

    val expectedTemplateParams = TemplateParams(
      tableToExport = "table1",
      columnsToExport = List("col1", "col2"),
      fullExport = true,
      dsvDelimiter = "|",
      deltaColumn = None,
      exportOutputFileBase = "output_file",
      scriptOutputFile = scriptOutputFolder / "EXTRACT_table1.sql"
    )
    TemplateParams.fromSchema(schema, scriptOutputFolder) shouldBe expectedTemplateParams
  }
} 
Example 13
Source File: ConsoleConfigTest.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console

import better.files.File
import org.scalatest.{Matchers, WordSpec}

class ConsoleConfigTest extends WordSpec with Matchers {
  "An InstallConfig" should {
    "set the rootPath to the current working directory by default" in {
      val config = new InstallConfig(environment = Map.empty)
      config.rootPath shouldBe File(".")
    }

    "set the rootPath to SHIFTLEFT_OCULAR_INSTALL_DIR if it is defined" in {
      val config = new InstallConfig(environment = Map("SHIFTLEFT_OCULAR_INSTALL_DIR" -> "/tmp"))
      config.rootPath shouldBe File("/tmp")
    }
  }
} 
Example 14
Source File: ScriptManagerTest.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.scripting

import better.files.File
import cats.effect.IO
import org.scalatest.{Inside, Matchers, WordSpec}

import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.console.scripting.ScriptManager.{ScriptCollections, ScriptDescription, ScriptDescriptions}

import java.nio.file.{FileSystemNotFoundException, NoSuchFileException, Path}

import scala.io.Source
import scala.util.Try

class ScriptManagerTest extends WordSpec with Matchers with Inside {

  private object TestScriptExecutor extends AmmoniteExecutor {
    override protected def predef: String = ""
    override def runScript(scriptPath: Path, parameters: Map[String, String], cpg: Cpg): IO[Any] = IO.fromTry(
      Try {
        val source = Source.fromFile(scriptPath.toFile)
        val result = source.getLines.mkString(System.lineSeparator())
        source.close()
        result
      }
    )
  }

  private object TestScriptManager extends ScriptManager(TestScriptExecutor)

  protected val DEFAULT_CPG_NAME: String = {
    if (File(".").name == "console") {
      (File("..") / "resources" / "testcode" / "cpgs" / "method" / "cpg.bin.zip").pathAsString
    } else {
      (File("resources") / "testcode" / "cpgs" / "method" / "cpg.bin.zip").pathAsString
    }
  }

  def withScriptManager(f: ScriptManager => Unit): Unit = {
    f(TestScriptManager)
  }

  "listing scripts" should {
    "be correct" in withScriptManager { scriptManager =>
      val scripts = scriptManager.scripts()
      val expected = List(
        ScriptCollections("general",
                          ScriptDescriptions(
                            "A collection of general purpose scripts.",
                            List(ScriptDescription("list-funcs.sc", "Lists all functions."))
                          )),
        ScriptCollections("java",
                          ScriptDescriptions(
                            "A collection of java-specific scripts.",
                            List(ScriptDescription("list-sl-ns.sc", "Lists all shiftleft namespaces."))
                          )),
        ScriptCollections("general/general_plus",
                          ScriptDescriptions(
                            "Even more general purpose scripts.",
                            List.empty
                          ))
      )

      scripts should contain theSameElementsAs expected
    }
  }

  "running scripts" should {
    "be correct when explicitly specifying a CPG" in withScriptManager { scriptManager =>
      val expected =
        """|@main def main() = {
           |  cpg.method.name.l
           |}""".stripMargin

      scriptManager.runScript("general/list-funcs.sc", Map.empty, Cpg.emptyCpg) shouldBe expected
    }

    "be correct when specifying a CPG filename" in withScriptManager { scriptManager =>
      val expected =
        """|@main def main() = {
           |  cpg.method.name.l
           |}""".stripMargin

      scriptManager.runScript("general/list-funcs.sc", Map.empty, DEFAULT_CPG_NAME) shouldBe expected
    }

    "throw an exception if the specified CPG can not be found" in withScriptManager { scriptManager =>
      intercept[FileSystemNotFoundException] {
        scriptManager.runScript("general/list-funcs.sc", Map.empty, "cake.bin.zip")
      }
    }

    "throw an exception if the specified script can not be found" in withScriptManager { scriptManager =>
      intercept[NoSuchFileException] {
        scriptManager.runScript("list-funcs.sc", Map.empty, Cpg.emptyCpg)
      }
    }
  }

} 
Example 15
Source File: Project.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.workspacehandling

import java.nio.file.Path

import better.files.File
import better.files.Dsl._
import io.shiftleft.codepropertygraph.Cpg
import io.shiftleft.semanticcpg.Overlays

object Project {
  val workCpgFileName = "cpg.bin.tmp"
  val persistentCpgFileName = "cpg.bin"
}

case class ProjectFile(inputPath: String, name: String)


  def close: Project = {
    cpg.foreach { c =>
      c.close()
      System.err.println("Turning working copy into new persistent CPG")
      val workingCopy = path.resolve(workCpgFileName)
      val persistent = path.resolve(persistentCpgFileName)
      cp(workingCopy, persistent)
    }
    cpg = None
    this
  }

} 
Example 16
Source File: WorkspaceLoader.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.workspacehandling

import java.nio.file.Path

import better.files.Dsl.mkdirs
import better.files.File
import org.json4s.DefaultFormats
import org.json4s.native.Serialization.{read => jsonRead}

import scala.collection.mutable.ListBuffer
import scala.util.{Failure, Success, Try}


  def load(path: String): Workspace[ProjectType] = {
    val dirFile = File(path)
    val dirPath = dirFile.path.toAbsolutePath

    if (!dirFile.exists) {
      println(s"creating workspace directory: ${dirFile.path.toString}")
      mkdirs(dirFile)
    }
    new Workspace(ListBuffer.from(loadProjectsFromFs(dirPath)))
  }

  private def loadProjectsFromFs(cpgsPath: Path): LazyList[ProjectType] = {
    cpgsPath.toFile.listFiles
      .filter(_.isDirectory)
      .to(LazyList)
      .flatMap(f => loadProject(f.toPath))
  }

  def loadProject(path: Path): Option[ProjectType] = {
    Try {
      val projectFile = readProjectFile(path)
      createProject(projectFile, path)
    } match {
      case Success(v) => Some(v)
      case Failure(e) =>
        System.err.println(s"Error loading project at $path - skipping: ")
        System.err.println(e)
        None
    }
  }

  def createProject(projectFile: ProjectFile, path: Path): ProjectType

  private val PROJECTFILE_NAME = "project.json"
  implicit val formats: DefaultFormats.type = DefaultFormats

  private def readProjectFile(projectDirName: Path): ProjectFile = {
    // TODO see `writeProjectFile`
    val content = File(projectDirName.resolve(PROJECTFILE_NAME)).contentAsString
    val map = jsonRead[Map[String, String]](content)
    ProjectFile(map("inputPath"), map("name"))
  }

} 
Example 17
Source File: ConsoleFixture.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.testing

import java.nio.file.Path
import java.util.concurrent.LinkedBlockingQueue

import better.files.Dsl.mkdir
import better.files.File
import io.shiftleft.console.cpgcreation.{CpgGenerator, LanguageFrontend}
import io.shiftleft.console.{Console, ConsoleConfig, DefaultAmmoniteExecutor, InstallConfig}
import io.shiftleft.console.workspacehandling.{Project, ProjectFile, WorkspaceLoader}
import io.shiftleft.fuzzyc2cpg.FuzzyC2Cpg
import io.shiftleft.proto.cpg.Cpg.CpgStruct

object ConsoleFixture {
  def apply[T <: Console[Project]](constructor: String => T = { x =>
    new TestConsole(x)
  })(fun: (T, File) => Unit): Unit = {
    File.usingTemporaryDirectory("console") { workspaceDir =>
      File.usingTemporaryDirectory("console") { codeDir =>
        mkdir(codeDir / "dir1")
        mkdir(codeDir / "dir2")
        (codeDir / "dir1" / "foo.c")
          .write("int main(int argc, char **argv) { char *ptr = 0x1 + argv; return argc; }")
        (codeDir / "dir2" / "bar.c").write("int bar(int x) { return x; }")
        val console = constructor(workspaceDir.toString)
        fun(console, codeDir)
      }
    }
  }

}

object TestWorkspaceLoader extends WorkspaceLoader[Project] {
  override def createProject(projectFile: ProjectFile, path: Path): Project = Project(projectFile, path)
}

class TestConsole(workspaceDir: String) extends Console[Project](DefaultAmmoniteExecutor, TestWorkspaceLoader) {
  override def config = new ConsoleConfig(
    install = new InstallConfig(Map("SHIFTLEFT_OCULAR_INSTALL_DIR" -> workspaceDir))
  )

  override val cpgGenerator = new TestCpgGenerator(config)

}

class TestCpgGenerator(config: ConsoleConfig) extends CpgGenerator(config) {
  override def createFrontendByPath(
      inputPath: String,
  ): Option[LanguageFrontend] = {
    Some(new FuzzyCTestingFrontend)
  }

  override def createFrontendByLanguage(language: String): Option[LanguageFrontend] = {
    Some(new FuzzyCTestingFrontend)
  }

  private class FuzzyCTestingFrontend extends LanguageFrontend {

    override def generate(inputPath: String, outputPath: String, namespaces: List[String]): Option[String] = {
      val queue = new LinkedBlockingQueue[CpgStruct.Builder]()
      val factory =
        new io.shiftleft.fuzzyc2cpg.output.overflowdb.OutputModuleFactory(outputPath, queue)
      val fuzzyc = new FuzzyC2Cpg(factory)
      File(inputPath).list.foreach(println(_))
      fuzzyc.runAndOutput(Set(inputPath), Set(".c"))
      Some(outputPath)
    }

    def isAvailable: Boolean = true

  }

} 
Example 18
Source File: LanguageFrontend.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.cpgcreation

import better.files.File

import scala.sys.process._


  def generate(inputPath: String, outputPath: String = "cpg.bin.zip", namespaces: List[String] = List()): Option[String]

  protected def runShellCommand(program: String, arguments: Seq[String]): Option[String] = {
    if (!File(program).exists) {
      System.err.println("Support for this language is only available in ShiftLeft Ocular with an appropriate license")
      return None
    }
    val cmd = Seq[String](program) ++ arguments
    val exitValue = cmd.run.exitValue()
    if (exitValue == 0) {
      Some(cmd.toString)
    } else {
      System.err.println(s"Error running shell command: $cmd")
      None
    }
  }

} 
Example 19
Source File: CpgGenerator.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.console.cpgcreation

import java.nio.file.Path

import better.files.Dsl._
import better.files.File
import io.shiftleft.codepropertygraph.cpgloading.{CpgLoader, CpgLoaderConfig}
import io.shiftleft.console.ConsoleConfig
import overflowdb.OdbConfig
import io.shiftleft.console.LanguageHelper.{cpgGeneratorForLanguage, languageIsKnown}

import scala.util.Try

class CpgGenerator(config: ConsoleConfig) {

  
  def createFrontendByLanguage(language: String): Option[LanguageFrontend] = {
    Some(language)
      .filter(languageIsKnown)
      .flatMap(
        lang =>
          cpgGeneratorForLanguage(
            lang,
            config.frontend,
            config.install.rootPath.path
        ))
  }

  def runLanguageFrontend(frontend: LanguageFrontend,
                          inputPath: String,
                          outputPath: String,
                          namespaces: List[String] = List()): Option[Path] = {
    val outputFileOpt: Option[File] =
      frontend.generate(inputPath, outputPath, namespaces).map(File(_))
    outputFileOpt.map { outFile =>
      val parentPath = outFile.parent.path.toAbsolutePath
      if (isZipFile(outFile)) {
        report("Creating database from bin.zip")
        val srcFilename = outFile.path.toAbsolutePath.toString
        val dstFilename = parentPath.resolve("cpg.bin").toAbsolutePath.toString
        // MemoryHelper.hintForInsufficientMemory(srcFilename).map(report)
        convertProtoCpgToOverflowDb(srcFilename, dstFilename)
      } else {
        report("moving cpg.bin.zip to cpg.bin because it is already a database file")
        val srcPath = parentPath.resolve("cpg.bin.zip")
        if (srcPath.toFile.exists()) {
          mv(srcPath, parentPath.resolve("cpg.bin"))
        }
      }
      parentPath
    }
  }

  def convertProtoCpgToOverflowDb(srcFilename: String, dstFilename: String): Unit = {
    val odbConfig = OdbConfig.withDefaults.withStorageLocation(dstFilename)
    val config = CpgLoaderConfig.withDefaults.doNotCreateIndexesOnLoad.withOverflowConfig(odbConfig)
    CpgLoader.load(srcFilename, config).close
    File(srcFilename).delete()
  }

  def isZipFile(file: File): Boolean = {
    val bytes = file.bytes
    Try {
      bytes.next() == 'P' && bytes.next() == 'K'
    }.getOrElse(false)
  }

  private def report(str: String): Unit = System.err.println(str)

} 
Example 20
Source File: CodeDumper.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.semanticcpg.codedumper

import better.files.File
import io.shiftleft.codepropertygraph.generated.{Languages, nodes}
import io.shiftleft.semanticcpg.language._
import io.shiftleft.semanticcpg.language.NodeSteps
import io.shiftleft.codepropertygraph.Cpg
import overflowdb.OdbGraph
import io.shiftleft.utils.{Source, SourceHighlighter}
import org.apache.logging.log4j.LogManager

import scala.util.Try

object CodeDumper {

  private val logger = LogManager.getLogger(CodeDumper)
  val arrow: CharSequence = "
  def code(filename: String, startLine: Integer, endLine: Integer, lineToHighlight: Option[Integer] = None): String = {
    val lines = Try(File(filename).lines.toList).getOrElse {
      logger.warn("error reading from: " + filename);
      List()
    }
    lines
      .slice(startLine - 1, endLine)
      .zipWithIndex
      .map {
        case (line, lineNo) =>
          if (lineToHighlight.isDefined && lineNo == lineToHighlight.get - startLine) {
            line + " " + arrow
          } else {
            line
          }
      }
      .mkString("\n")
  }

} 
Example 21
Source File: Shared.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.semanticcpg.language.dotextension

import better.files.File

import scala.sys.process.Process
import scala.util.{Failure, Success, Try}

trait ImageViewer {
  def view(pathStr: String): Try[String]
}

object Shared {

  def plotAndDisplay(dotStrings: List[String], viewer: ImageViewer): Unit = {
    dotStrings.foreach { dotString =>
      File.usingTemporaryFile("semanticcpg") { dotFile =>
        File.usingTemporaryFile("semanticcpg") { svgFile =>
          dotFile.write(dotString)
          createSvgFile(dotFile, svgFile).toOption.foreach(_ => viewer.view(svgFile.path.toAbsolutePath.toString))
        }
      }
    }
  }

  private def createSvgFile(in: File, out: File): Try[String] = {
    Try {
      Process(Seq("dot", "-Tsvg", in.path.toAbsolutePath.toString, "-o", out.path.toAbsolutePath.toString)).!!
    } match {
      case Success(v) => Success(v)
      case Failure(exc) =>
        System.err.println("Executing `dot` failed: is `graphviz` installed?")
        System.err.println(exc)
        Failure(exc)
    }
  }

} 
Example 22
Source File: LayerCreator.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.semanticcpg.layers

import better.files.File
import io.shiftleft.SerializedCpg
import io.shiftleft.codepropertygraph.Cpg
import org.apache.logging.log4j.LogManager
import io.shiftleft.semanticcpg.Overlays

abstract class LayerCreator {

  private val logger = LogManager.getLogger(this.getClass)

  val overlayName: String
  val description: String
  val dependsOn: List[String] = List()

  def run(context: LayerCreatorContext, serializeInverse: Boolean = false): Unit = {
    val appliedOverlays = Overlays.appliedOverlays(context.cpg).toSet
    if (!dependsOn.toSet.subsetOf(appliedOverlays)) {
      logger.warn(
        s"${this.getClass.getName} depends on $dependsOn but CPG only has $appliedOverlays - skipping creation")
    } else if (appliedOverlays.contains(overlayName)) {
      logger.warn(s"The overlay $overlayName already exists - skipping creation")
    } else {
      create(context, serializeInverse)
      Overlays.appendOverlayName(context.cpg, overlayName)
    }
  }

  protected def initSerializedCpg(outputDir: Option[String], passName: String, index: Int): SerializedCpg = {
    outputDir match {
      case Some(dir) => new SerializedCpg((File(dir) / s"${index}_$passName").path.toAbsolutePath.toString)
      case None      => new SerializedCpg()
    }
  }

  def create(context: LayerCreatorContext, serializeInverse: Boolean = false): Unit

  
  def probe(cpg: Cpg): Boolean

}

class LayerCreatorContext(val cpg: Cpg, val outputDir: Option[String] = None) {}
class LayerCreatorOptions() 
Example 23
Source File: Mutator.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.mutants

import better.files.File
import grizzled.slf4j.Logging
import stryker4s.model.{MutatedFile, MutationsInSource, SourceTransformations}
import stryker4s.mutants.applymutants.{MatchBuilder, StatementTransformer}
import stryker4s.mutants.findmutants.MutantFinder

import scala.meta.Tree

class Mutator(mutantFinder: MutantFinder, transformer: StatementTransformer, matchBuilder: MatchBuilder)
    extends Logging {
  def mutate(files: Iterable[File]): Iterable[MutatedFile] = {
    val mutatedFiles = files
      .map { file =>
        val mutationsInSource = findMutants(file)
        val transformed = transformStatements(mutationsInSource)
        val builtTree = buildMatches(transformed)

        MutatedFile(file, builtTree, mutationsInSource.mutants, mutationsInSource.excluded)
      }
      .filterNot(mutatedFile => mutatedFile.mutants.isEmpty && mutatedFile.excludedMutants == 0)

    logMutationResult(mutatedFiles, files.size)

    mutatedFiles
  }

  
  private def buildMatches(transformedMutantsInSource: SourceTransformations): Tree =
    matchBuilder.buildNewSource(transformedMutantsInSource)

  private def logMutationResult(mutatedFiles: Iterable[MutatedFile], totalAmountOfFiles: Int): Unit = {
    val includedMutants = mutatedFiles.flatMap(_.mutants).size
    val excludedMutants = mutatedFiles.map(_.excludedMutants).sum
    val totalMutants = includedMutants + excludedMutants

    info(s"Found ${mutatedFiles.size} of $totalAmountOfFiles file(s) to be mutated.")
    info(s"$totalMutants Mutant(s) generated.${if (excludedMutants > 0)
      s" Of which $excludedMutants Mutant(s) are excluded."
    else ""}")

    if (totalAmountOfFiles == 0) {
      warn(s"No files marked to be mutated. ${dryRunText("mutate")}")
    } else if (includedMutants == 0 && excludedMutants > 0) {
      warn(s"All found mutations are excluded. ${dryRunText("excluded-mutations")}")
    } else if (totalMutants == 0) {
      info("Files to be mutated are found, but no mutations were found in those files.")
      info("If this is not intended, please check your configuration and try again.")
    }

    def dryRunText(configProperty: String): String =
      s"""Stryker4s will perform a dry-run without actually mutating anything.
         |You can configure the `$configProperty` property in your configuration""".stripMargin
  }
} 
Example 24
Source File: Config.scala    From full-scala-stack   with Apache License 2.0 5 votes vote down vote up
package api

import better.files.File
import com.typesafe.config.ConfigFactory


trait Config {
  val configKey = "full-scala-stack"
  val config: com.typesafe.config.Config = {
    val confFileName =
      System.getProperty("application.conf", "./src/main/resources/application.conf")
    val confFile = File(confFileName)
    val config = ConfigFactory
      .parseFile(confFile.toJava)
      .withFallback(ConfigFactory.load())
    config
  }
} 
Example 25
Source File: IssueActor.scala    From BacklogMigration-Redmine   with MIT License 5 votes vote down vote up
package com.nulabinc.backlog.r2b.exporter.actor

import java.util.concurrent.CountDownLatch

import akka.actor.Actor
import better.files.File
import com.nulabinc.backlog.migration.common.convert.Convert
import com.nulabinc.backlog.migration.common.domain.{BacklogComment, BacklogIssue, BacklogTextFormattingRule}
import com.nulabinc.backlog.migration.common.utils.{DateUtil, IOUtil, Logging}
import com.nulabinc.backlog.r2b.exporter.convert.{IssueWrites, JournalWrites}
import com.nulabinc.backlog.r2b.exporter.core.ExportContext
import com.nulabinc.backlog.r2b.exporter.service.{ChangeLogReducer, CommentReducer, IssueInitializer}
import com.taskadapter.redmineapi.Include
import com.taskadapter.redmineapi.bean.{Attachment, _}
import spray.json._

import scala.jdk.CollectionConverters._
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._


private[exporter] class IssueActor(exportContext: ExportContext, backlogTextFormattingRule: BacklogTextFormattingRule) extends Actor with Logging {

  import com.nulabinc.backlog.migration.common.formatters.BacklogJsonProtocol._
  import IssueActor.ConsoleF

  private implicit val issueWrites: IssueWrites = exportContext.issueWrites
  private implicit val journalWrites: JournalWrites = exportContext.journalWrites


  override def preRestart(reason: Throwable, message: Option[Any]): Unit = {
    logger.debug(s"preRestart: reason: $reason, message: $message")
    for { value <- message } yield {
      context.system.scheduler.scheduleOnce(10.seconds, self, value)
    }
  }

  def receive: Receive = {
    case IssueActor.Do(issueId: Int, completion: CountDownLatch, allCount: Int, console: ConsoleF)=>
      logger.debug(s"[START ISSUE]$issueId thread numbers:${java.lang.Thread.activeCount()}")

      val issue                        = exportContext.issueService.issueOfId(issueId, Include.attachments, Include.journals)
      val journals                     = issue.getJournals.asScala.toSeq.sortWith((c1, c2) => c1.getCreatedOn.before(c2.getCreatedOn))
      val attachments: Seq[Attachment] = issue.getAttachments.asScala.toSeq

      exportIssue(issue, journals, attachments)
      exportComments(issue, journals, attachments)

      completion.countDown()
      console((allCount - completion.getCount).toInt, allCount)
  }

  private[this] def exportIssue(issue: Issue, journals: Seq[Journal], attachments: Seq[Attachment]): File = {
    val issueCreated     = DateUtil.tryIsoParse(Option(issue.getCreatedOn).map(DateUtil.isoFormat))
    val issueDirPath     = exportContext.backlogPaths.issueDirectoryPath("issue", issue.getId.intValue(), issueCreated, 0)
    val issueInitializer = new IssueInitializer(exportContext, issueDirPath, journals, attachments, backlogTextFormattingRule)
    val backlogIssue     = issueInitializer.initialize(issue)

    IOUtil.output(exportContext.backlogPaths.issueJson(issueDirPath), backlogIssue.toJson.prettyPrint)
  }

  private[this] def exportComments(issue: Issue, journals: Seq[Journal], attachments: Seq[Attachment]): Unit = {
    val backlogIssue    = Convert.toBacklog(issue)
    val backlogComments = journals.map(Convert.toBacklog(_))
    backlogComments.zipWithIndex.foreach {
      case (comment, index) =>
        exportComment(comment, backlogIssue, backlogComments, attachments, index)
    }
  }

  private[this] def exportComment(comment: BacklogComment,
                                  issue: BacklogIssue,
                                  comments: Seq[BacklogComment],
                                  attachments: Seq[Attachment],
                                  index: Int) : File = {
    val commentCreated   = DateUtil.tryIsoParse(comment.optCreated)
    val issueDirPath     = exportContext.backlogPaths.issueDirectoryPath("comment", issue.id, commentCreated, index)
    val changeLogReducer = new ChangeLogReducer(exportContext, issueDirPath, issue, comments, attachments)
    val commentReducer   = new CommentReducer(issue.id, changeLogReducer)
    val reduced          = commentReducer.reduce(comment)

    IOUtil.output(exportContext.backlogPaths.issueJson(issueDirPath), reduced.toJson.prettyPrint)
  }

}

private[exporter] object IssueActor {

  type ConsoleF = (Int, Int) => Unit

  case class Do(issueId: Int, completion: CountDownLatch, allCount: Int, console: ConsoleF)

} 
Example 26
Source File: UserMappingFile.scala    From BacklogMigration-Redmine   with MIT License 5 votes vote down vote up
package com.nulabinc.backlog.r2b.mapping.file

import better.files.File
import com.nulabinc.backlog.migration.common.conf.{BacklogApiConfiguration, BacklogConfiguration}
import com.nulabinc.backlog.migration.common.domain.BacklogUser
import com.nulabinc.backlog.migration.common.modules.{ServiceInjector => BacklogInjector}
import com.nulabinc.backlog.migration.common.service.{UserService => BacklogUserService}
import com.nulabinc.backlog.migration.common.utils.{IOUtil, StringUtil}
import com.nulabinc.backlog.r2b.mapping.core.MappingDirectory
import com.nulabinc.backlog.r2b.mapping.domain.MappingJsonProtocol._
import com.nulabinc.backlog.r2b.mapping.domain.{Mapping, MappingsWrapper}
import com.nulabinc.backlog.r2b.redmine.conf.RedmineApiConfiguration
import com.nulabinc.backlog.r2b.redmine.modules.{ServiceInjector => RedmineInjector}
import com.nulabinc.backlog.r2b.redmine.service.{UserService => RedmineUserService}
import com.osinka.i18n.Messages
import com.taskadapter.redmineapi.bean.{User => RedmineUser}
import spray.json.JsonParser


class UserMappingFile(redmineApiConfig: RedmineApiConfiguration, backlogApiConfig: BacklogApiConfiguration, users: Seq[RedmineUser])
    extends MappingFile
    with BacklogConfiguration {

  private[this] val redmineItems = getRedmineItems()
  private[this] val backlogItems = getBacklogItems()

  private[this] def getRedmineItems(): Seq[MappingItem] = {
    val injector    = RedmineInjector.createInjector(redmineApiConfig)
    val userService = injector.getInstance(classOf[RedmineUserService])

    def resolve(user: RedmineUser): Option[RedmineUser] = {
      (Option(user.getLogin), Option(user.getFullName)) match {
        case (Some(_), Some(_)) => Some(user)
        case _                  => userService.optUserOfId(user.getId)
      }
    }

    def condition(user: RedmineUser): Boolean = {
      StringUtil.notEmpty(user.getLogin).nonEmpty
    }

    def createItem(user: RedmineUser): MappingItem = {
      MappingItem(user.getLogin, user.getFullName)
    }

    val redmineUsers = users.flatMap(resolve).filter(condition)
    redmineUsers.map(createItem)
  }

  private[this] def getBacklogItems(): Seq[MappingItem] = {
    def createItem(user: BacklogUser): MappingItem = {
      if (backlogApiConfig.url.contains(NaiSpaceDomain)) {
        MappingItem(user.optMailAddress.getOrElse(""), user.name)
      } else {
        MappingItem(user.optUserId.getOrElse(""), user.name)
      }
    }
    val backlogUsers = allUsers()
    backlogUsers.map(createItem)
  }

  private[this] def allUsers(): Seq[BacklogUser] = {
    val injector    = BacklogInjector.createInjector(backlogApiConfig)
    val userService = injector.getInstance(classOf[BacklogUserService])
    userService.allUsers()
  }

  private[this] def convertForNAI(backlogUsers: Seq[BacklogUser])(mapping: Mapping) = {
    if (backlogApiConfig.url.contains(NaiSpaceDomain)) {
      val targetBacklogUser = backlogUsers
        .find(backlogUser => backlogUser.optMailAddress.getOrElse("") == mapping.backlog)
        .getOrElse(throw new NoSuchElementException(s"User ${mapping.backlog} not found"))
      mapping.copy(backlog = targetBacklogUser.optUserId.getOrElse(s"UserId ${mapping.backlog} not found"))
    } else mapping
  }

  override def tryUnmarshal(): Seq[Mapping] = {
    val path    = File(filePath).path.toAbsolutePath
    val json    = IOUtil.input(path).getOrElse("")
    val convert = convertForNAI(allUsers()) _
    JsonParser(json).convertTo[MappingsWrapper].mappings.map(convert)
  }

  override def matchItem(redmine: MappingItem): String =
    backlogs.map(_.name).find(_ == redmine.name).getOrElse("")

  override def redmines: Seq[MappingItem] = redmineItems

  override def backlogs: Seq[MappingItem] = backlogItems

  override def filePath: String = MappingDirectory.USER_MAPPING_FILE

  override def itemName: String = Messages("common.users")

  override def description: String = {
    Messages("cli.mapping.configurable", itemName, backlogs.map(_.name).mkString(","))
  }

  override def isDisplayDetail: Boolean = true

} 
Example 27
Source File: DatasetSplitter.scala    From scala-deeplearn-examples   with Apache License 2.0 5 votes vote down vote up
package io.brunk

import better.files.File

import scala.util.Random.shuffle


object DatasetSplitter {
  val datasetSplitNames = Seq("train", "validation", "test")

  def main(args: Array[String]): Unit = {
    val inputDir = File(args(0))
    val outputDir = File(args(1))
    val splitSizes = args.drop(2).map(_.toFloat).toSeq

    val imgClassDirs = inputDir.list.filter(_.isDirectory).toVector.sortBy(_.name)

    // in case of different numbers of samples per class, use the smallest one
    val numSamplesPerClass = imgClassDirs.map(_.glob("*.jpg").size).min
    println(s"Number of samples per class (balanced): $numSamplesPerClass")

    val samplesPerClass =  {
      imgClassDirs.flatMap { imgClassDir =>
        shuffle(imgClassDir.children.toVector)
          .take(numSamplesPerClass)       // balance samples to have the same number for each class
          .map((imgClassDir.name, _))
      }.groupBy(_._1).mapValues(_.map(_._2))
    }

    val numSamples = samplesPerClass.map(_._2.size).sum
    println(s"Number of samples (balanced): $numSamples")
    val splitSizesAbsolute = splitSizes.map(_ / 100.0).map(_ * numSamplesPerClass).map(_.toInt)
    println(s"Number of samples per split: ${datasetSplitNames.zip(splitSizesAbsolute).mkString(" ")}")
    val splitIndices = splitSizesAbsolute
      .map(_ -1)
      .scanLeft(-1 to -1)((prev, current) => prev.last + 1 to (prev.last + current + 1)).tail // TODO cleaner solution
    println(splitIndices)

    val datasetNamesWithIndices = datasetSplitNames.zip(splitIndices)

    val datasetIndices = (for {
      (name, indices) <- datasetNamesWithIndices
      index <- indices
    } yield (index, name))
      .sortBy(_._1)
      .map(_._2)

    // create directories
    for {
      dataset <- datasetSplitNames
      imgClassDir <- imgClassDirs
      imgClass = imgClassDir.name
    } {
      (outputDir/dataset/imgClass).createDirectories()
    }
    // write into train, validation and test folders
    for {
      (imgClass, samples) <- samplesPerClass
      (filename, dataset) <- samples.zip(datasetIndices)
    } {
      filename.copyTo(outputDir/dataset/imgClass/filename.name)
    }

  }
} 
Example 28
Source File: TestProcessRunner.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.testutil.stubs

import better.files.File
import stryker4s.run.process.{Command, ProcessRunner}

import scala.util.{Success, Try}

object TestProcessRunner {
  def apply(testRunExitCode: Try[Int]*): TestProcessRunner = new TestProcessRunner(true, testRunExitCode: _*)
  def failInitialTestRun(): TestProcessRunner = new TestProcessRunner(false)
}

class TestProcessRunner(initialTestRunSuccess: Boolean, testRunExitCode: Try[Int]*) extends ProcessRunner {
  val timesCalled: Iterator[Int] = Iterator.from(0)

  
  override def apply(command: Command, workingDir: File, envVar: (String, String)): Try[Int] = {
    if (envVar._2.equals("None")) {
      Success(if (initialTestRunSuccess) 0 else 1)
    } else {
      timesCalled.next()
      testRunExitCode(envVar._2.toInt)
    }
  }
} 
Example 29
Source File: ConfigTest.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.config

import better.files.File
import stryker4s.testutil.Stryker4sSuite

class ConfigTest extends Stryker4sSuite {
  describe("toHoconString") {
    it("should print toString with default values") {
      val sut = Config.default

      val result = Config.toHoconString(sut)

      val expected =
        s"""base-dir="${File.currentWorkingDirectory.pathAsString.replace("\\", "\\\\")}"
           |dashboard {
           |    base-url="https://dashboard.stryker-mutator.io"
           |    report-type=full
           |}
           |excluded-mutations=[]
           |mutate=[
           |    "**/main/scalaBar.scala"
           |]
           |reporters=[
           |    html
           |]
           |test-filter=[]
           |thresholds {
           |    break=0
           |    high=80
           |    low=60
           |}
           |""".stripMargin
      result.toString should equal(expected.toString)
    }
  }
} 
Example 30
Source File: MutantRunResultMapperTest.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.report.mapper
import java.nio.file.Path

import better.files.File
import mutationtesting._
import org.scalatest.Inside
import stryker4s.config.{Config, Thresholds => ConfigThresholds}
import stryker4s.extension.FileExtensions._
import stryker4s.extension.ImplicitMutationConversion._
import stryker4s.extension.mutationtype._
import stryker4s.model.{Killed, Mutant, Survived}
import stryker4s.scalatest.FileUtil
import stryker4s.testutil.Stryker4sSuite

import scala.meta.{Lit, Term}

class MutantRunResultMapperTest extends Stryker4sSuite with Inside {
  describe("mapper") {
    it("should map 4 files to valid MutationTestReport") {
      val sut = new MutantRunResultMapper {}
      implicit val config: Config = Config(thresholds = ConfigThresholds(high = 60, low = 40))

      val path = FileUtil.getResource("scalaFiles/ExampleClass.scala").relativePath
      val mutantRunResult = Killed(
        toMutant(0, EqualTo, NotEqualTo, path),
        path
      )
      val mutantRunResult2 = Survived(
        toMutant(1, Lit.String("Hugo"), EmptyString, path),
        path
      )
      val path3 = FileUtil.getResource("scalaFiles/simpleFile.scala").relativePath
      val mutantRunResult3 = Killed(
        toMutant(0, GreaterThan, LesserThan, path3),
        path3
      )

      val mutationRunResults = List(mutantRunResult, mutantRunResult2, mutantRunResult3)

      val result = sut.toReport(mutationRunResults)
      inside(result) {
        case MutationTestReport(_, _, thresholds, files) =>
          thresholds should equal(Thresholds(high = 60, low = 40))
          files should have size 2
          val firstResult = files.find(_._1.endsWith("scalaFiles/ExampleClass.scala")).value
          files.find(_._1.endsWith("scalaFiles/simpleFile.scala")).value
          inside(firstResult._2) {
            case MutationTestResult(source, mutants, language) =>
              language should equal("scala")
              mutants should (
                contain.only(
                  MutantResult(
                    "0",
                    "EqualityOperator",
                    "!=",
                    Location(Position(4, 27), Position(4, 29)),
                    MutantStatus.Killed
                  ),
                  MutantResult(
                    "1",
                    "StringLiteral",
                    "\"\"",
                    Location(Position(6, 31), Position(6, 37)),
                    MutantStatus.Survived
                  )
                )
              )
              source should equal(FileUtil.getResource("scalaFiles/ExampleClass.scala").contentAsString)
          }
      }
    }
  }

  
  private def toMutant(id: Int, original: Term, category: SubstitutionMutation[_ <: Term], file: Path) = {
    import stryker4s.extension.TreeExtensions.FindExtension

    import scala.meta._
    val parsed = File(file).contentAsString.parse[Source]
    val foundOrig = parsed.get.find(original).value
    Mutant(id, foundOrig, category.tree, category)
  }
} 
Example 31
Source File: ProcessRunner.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.run.process

import better.files.File
import grizzled.slf4j.Logging

import scala.concurrent.duration.{Duration, MINUTES}
import scala.sys.process.{Process, ProcessLogger}
import scala.util.Try
import cats.effect.IO

trait ProcessRunner extends Logging {
  def apply(command: Command, workingDir: File): Try[Seq[String]] = {
    Try {
      Process(s"${command.command} ${command.args}", workingDir.toJava)
        .!!<(ProcessLogger(debug(_)))
        .linesIterator
        .toSeq
    }
  }

  def apply(command: Command, workingDir: File, envVar: (String, String)): Try[Int] = {
    val mutantProcess = Process(s"${command.command} ${command.args}", workingDir.toJava, envVar)
      .run(ProcessLogger(debug(_)))

    val exitCodeFuture = IO(mutantProcess.exitValue())
    // TODO: Maybe don't use unsafeRunTimed
    // TODO: Use timeout decided by initial test-run duration
    Try(exitCodeFuture.unsafeRunTimed(Duration(2, MINUTES)).get)
  }
}

object ProcessRunner {
  private def isWindows: Boolean = sys.props("os.name").toLowerCase.contains("windows")

  def apply(): ProcessRunner = {
    if (isWindows) new WindowsProcessRunner
    else new UnixProcessRunner
  }
} 
Example 32
Source File: MutantRunner.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.run

import java.nio.file.Path

import better.files.File
import grizzled.slf4j.Logging
import mutationtesting.{Metrics, MetricsResult}
import stryker4s.config.Config
import stryker4s.extension.FileExtensions._
import stryker4s.model._
import stryker4s.mutants.findmutants.SourceCollector
import stryker4s.report.Reporter
import stryker4s.report.mapper.MutantRunResultMapper
import stryker4s.report.FinishedRunReport
import scala.concurrent.duration._
import stryker4s.extension.exception.InitialTestRunFailedException

abstract class MutantRunner(sourceCollector: SourceCollector, reporter: Reporter)(implicit
    config: Config
) extends MutantRunResultMapper
    with Logging {
  type Context <: TestRunnerContext

  def apply(mutatedFiles: Iterable[MutatedFile]): MetricsResult = {
    val context = prepareEnv(mutatedFiles)

    initialTestRun(context)

    val runResults = runMutants(mutatedFiles, context)

    val report = toReport(runResults)
    val metrics = Metrics.calculateMetrics(report)

    // Timeout of 15 seconds is a little longer to make sure http requests etc finish
    // TODO: Don't use unsafeRun
    reporter.reportRunFinished(FinishedRunReport(report, metrics)).unsafeRunTimed(15.seconds)
    metrics
  }

  private def prepareEnv(mutatedFiles: Iterable[MutatedFile]): Context = {
    val files = sourceCollector.filesToCopy
    val tmpDir: File = {
      val targetFolder = config.baseDir / "target"
      targetFolder.createDirectoryIfNotExists()

      File.newTemporaryDirectory("stryker4s-", Some(targetFolder))
    }

    debug("Using temp directory: " + tmpDir)

    files.foreach(copyFile(_, tmpDir))

    // Overwrite files to mutated files
    mutatedFiles.foreach(writeMutatedFile(_, tmpDir))
    initializeTestContext(tmpDir)
  }

  private def copyFile(file: File, tmpDir: File): Unit = {
    val filePath = tmpDir / file.relativePath.toString

    filePath.createIfNotExists(file.isDirectory, createParents = true)

    val _ = file.copyTo(filePath, overwrite = true)
  }

  private def writeMutatedFile(mutatedFile: MutatedFile, tmpDir: File): File = {
    val filePath = mutatedFile.fileOrigin.inSubDir(tmpDir)
    filePath.overwrite(mutatedFile.tree.syntax)
  }

  private def runMutants(mutatedFiles: Iterable[MutatedFile], context: Context): Iterable[MutantRunResult] =
    for {
      mutatedFile <- mutatedFiles
      subPath = mutatedFile.fileOrigin.relativePath
      mutant <- mutatedFile.mutants
    } yield {
      val totalMutants = mutatedFiles.flatMap(_.mutants).size
      // TODO: Don't use unsafeRun
      reporter.reportMutationStart(mutant).unsafeRunTimed(5.seconds)
      val result = runMutant(mutant, context)(subPath)
      reporter.reportMutationComplete(result, totalMutants).unsafeRunTimed(5.seconds)
      result
    }

  def runMutant(mutant: Mutant, context: Context): Path => MutantRunResult

  def initialTestRun(context: Context): Unit = {
    info("Starting initial test run...")
    if (!runInitialTest(context)) {
      throw InitialTestRunFailedException(
        "Initial test run failed. Please make sure your tests pass before running Stryker4s."
      )
    }
    info("Initial test run succeeded! Testing mutants...")
  }

  def runInitialTest(context: Context): Boolean

  def initializeTestContext(tmpDir: File): Context
} 
Example 33
Source File: ConfigWriterImplicits.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.config.implicits

import java.nio.file.Path

import better.files.File
import com.typesafe.config.ConfigRenderOptions
import pureconfig.ConfigWriter
import stryker4s.config.{DashboardReportType, ExcludedMutations, ReporterType}
import pureconfig.generic.semiauto._

object ConfigWriterImplicits {
  implicit private[config] val fileWriter: ConfigWriter[File] =
    ConfigWriter[Path] contramap (_.path)

  implicit private[config] val exclusionsWriter: ConfigWriter[ExcludedMutations] =
    ConfigWriter[List[String]] contramap (_.exclusions.toList)

  implicit private[config] val reportersWriter: ConfigWriter[ReporterType] =
    deriveEnumerationWriter[ReporterType]

  implicit private[config] val dashboardReportTypeWriter: ConfigWriter[DashboardReportType] =
    deriveEnumerationWriter[DashboardReportType]

  private[config] val options: ConfigRenderOptions = ConfigRenderOptions
    .defaults()
    .setOriginComments(false)
    .setJson(false)
} 
Example 34
Source File: SourceHighlighter.scala    From codepropertygraph   with Apache License 2.0 5 votes vote down vote up
package io.shiftleft.utils

import better.files.File
import io.shiftleft.codepropertygraph.generated.Languages
import org.apache.logging.log4j.LogManager
import scala.sys.process.Process


case class Source(code: String, language: String)

object SourceHighlighter {
  private val logger = LogManager.getLogger(this)

  def highlight(source: Source): Option[String] = {
    val langFlag = source.language match {
      case Languages.C => "-sC"
      case other       => throw new RuntimeException(s"Attempting to call highlighter on unsupported language: $other")
    }

    val tmpSrcFile = File.newTemporaryFile("dump")
    tmpSrcFile.writeText(source.code)
    try {
      val highlightedCode = Process(Seq("source-highlight-esc.sh", tmpSrcFile.path.toString, langFlag)).!!
      Some(highlightedCode)
    } catch {
      case exception: Exception =>
        logger.info("syntax highlighting not working. Is `source-highlight` installed?")
        logger.info(exception)
        Some(source.code)
    } finally {
      tmpSrcFile.delete()
    }
  }

} 
Example 35
Source File: MutantFinder.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.mutants.findmutants

import better.files.File
import grizzled.slf4j.Logging
import stryker4s.config.Config
import stryker4s.extension.FileExtensions._
import stryker4s.model.{Mutant, MutationsInSource}

import scala.meta.Source
import scala.meta.parsers.{Parsed, XtensionParseInputLike}

class MutantFinder(matcher: MutantMatcher)(implicit config: Config) extends Logging {
  def mutantsInFile(filePath: File): MutationsInSource = {
    val parsedSource = parseFile(filePath)
    val (included, excluded) = findMutants(parsedSource)
    MutationsInSource(parsedSource, included, excluded)
  }

  def findMutants(source: Source): (Seq[Mutant], Int) = {
    val (included, excluded) = source.collect(matcher.allMatchers).flatten.partition(_.isDefined)
    (included.flatten, excluded.size)
  }

  def parseFile(file: File): Source =
    file.toJava.parse[Source] match {
      case Parsed.Success(source) =>
        source
      case Parsed.Error(_, msg, ex) =>
        error(s"Error while parsing file '${file.relativePath}', $msg")
        throw ex
    }
} 
Example 36
Source File: ProcessMutantRunner.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.command.runner

import java.nio.file.Path

import better.files.File
import stryker4s.config.Config
import stryker4s.model._
import stryker4s.mutants.findmutants.SourceCollector
import stryker4s.report.Reporter
import stryker4s.run.MutantRunner
import stryker4s.run.process.{Command, ProcessRunner}

import scala.concurrent.TimeoutException
import scala.util.{Failure, Success}

class ProcessMutantRunner(
    command: Command,
    processRunner: ProcessRunner,
    sourceCollector: SourceCollector,
    reporter: Reporter
)(implicit config: Config)
    extends MutantRunner(sourceCollector, reporter) {
  type Context = CommandRunnerContext

  override def runMutant(mutant: Mutant, context: Context): Path => MutantRunResult = {
    val id = mutant.id
    processRunner(command, context.tmpDir, ("ACTIVE_MUTATION", id.toString)) match {
      case Success(0)                         => Survived(mutant, _)
      case Success(exitCode) if exitCode != 0 => Killed(mutant, _)
      case Failure(_: TimeoutException)       => TimedOut(mutant, _)
      case _                                  => Error(mutant, _)
    }
  }

  override def runInitialTest(context: Context): Boolean = {
    processRunner(command, context.tmpDir, ("ACTIVE_MUTATION", "None")) match {
      case Success(0)                         => true
      case Success(exitCode) if exitCode != 0 => false
      case Failure(_: TimeoutException)       => false
    }
  }

  override def initializeTestContext(tmpDir: File): Context = CommandRunnerContext(tmpDir)

} 
Example 37
Source File: SbtMutantRunner.scala    From stryker4s   with Apache License 2.0 5 votes vote down vote up
package stryker4s.sbt.runner

import java.io.{PrintStream, File => JFile}
import java.nio.file.Path

import better.files.{File, _}
import sbt.Keys._
import sbt._
import sbt.internal.LogManager
import stryker4s.config.{Config, TestFilter}
import stryker4s.extension.FileExtensions._
import stryker4s.extension.exception.InitialTestRunFailedException
import stryker4s.model._
import stryker4s.mutants.findmutants.SourceCollector
import stryker4s.report.Reporter
import stryker4s.run.MutantRunner
import stryker4s.sbt.Stryker4sMain.autoImport.stryker
import sbt.Tests.Output

class SbtMutantRunner(state: State, sourceCollector: SourceCollector, reporter: Reporter)(implicit config: Config)
    extends MutantRunner(sourceCollector, reporter) {
  type Context = SbtRunnerContext

  
  private def runTests[T](state: State, onError: => T, onSuccess: => T, onFailed: => T): T =
    Project.runTask(executeTests in Test, state) match {
      case Some((_, Value(Output(TestResult.Passed, _, _)))) => onSuccess
      case Some((_, Value(Output(TestResult.Failed, _, _)))) => onFailed
      case _                                                 => onError
    }

  private def mutationSetting(mutation: Int): Def.Setting[_] =
    javaOptions in Test += s"-DACTIVE_MUTATION=${String.valueOf(mutation)}"

  private def tmpDirFor(conf: Configuration, tmpDir: File): Def.Initialize[JFile] =
    (scalaSource in conf)(_.toScala)(source => (source inSubDir tmpDir).toJava)
} 
Example 38
Source File: SharedSparkSession.scala    From lighthouse   with Apache License 2.0 5 votes vote down vote up
package be.dataminded.lighthouse.testing

import better.files.File
import org.apache.spark.sql.SparkSession

trait SharedSparkSession {

  private object AutoImport {
    lazy val tmp: File = File.newTemporaryDirectory().deleteOnExit()

    lazy val localMetastorePath: String  = (tmp / "metastore").pathAsString
    lazy val localWarehousePath: String  = (tmp / "warehouse").pathAsString
    lazy val checkPointDirectory: String = (tmp / "checkpoint").pathAsString
  }

  import AutoImport._

  lazy val spark: SparkSession = SparkSession
    .builder()
    .master("local[*]")
    .appName("LocalSparkTesting")
    .config("javax.jdo.option.ConnectionURL", s"jdbc:derby:;databaseName=$localMetastorePath;create=true")
    .config("datanucleus.rdbms.datastoreAdapterClassName", "org.datanucleus.store.rdbms.adapter.DerbyAdapter")
    .config("spark.sql.streaming.checkpointLocation", checkPointDirectory)
    .config("spark.sql.warehouse.dir", localWarehousePath)
    .config("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    .config("spark.sql.avro.compression.codec", "snappy")
    .config("spark.sql.parquet.compression.codec", "snappy")
    .config("spark.ui.enabled", "false")
    .config("spark.sql.sources.partitionOverwriteMode", "dynamic")
    .enableHiveSupport()
    .getOrCreate()
} 
Example 39
Source File: SchemaProvider.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.schema

import akka.NotUsed
import akka.stream.scaladsl.Source
import better.files.File
import io.circe.Json
import sangria.execution.{Executor, Middleware}
import sangria.execution.deferred.DeferredResolver
import sangria.schema.Schema

import scala.concurrent.{Await, Future}

trait SchemaProvider[Ctx, Val] {
  def schemaInfo: Future[Option[SchemaInfo[Ctx, Val]]]
  def schemaChanges: Option[Source[Boolean, NotUsed]]
}

case class SchemaInfo[Ctx, Val](
  schema: Schema[Ctx, Val],
  ctx: Ctx,
  value: Val,
  middleware: List[Middleware[Ctx]],
  deferredResolver: DeferredResolver[Ctx] = DeferredResolver.empty,
  schemaRendered: String,
  schemaIntrospection: Json,
  files: Vector[File]) 
Example 40
Source File: ReloadableSchemaProvider.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.schema

import java.util.concurrent.atomic.AtomicReference

import akka.actor.ActorSystem
import akka.stream.{Materializer, OverflowStrategy}
import akka.stream.scaladsl.{BroadcastHub, Keep, RunnableGraph, Source}
import better.files.File
import sangria.gateway.AppConfig
import sangria.gateway.file.FileMonitorActor
import sangria.gateway.http.client.HttpClient
import sangria.gateway.schema.materializer.{GatewayContext, GatewayMaterializer}
import sangria.gateway.util.Logging

import scala.concurrent.{ExecutionContext, Future}
import scala.util.{Failure, Success}

// TODO: on a timer reload all external schemas and check for changes
class ReloadableSchemaProvider(config: AppConfig, client: HttpClient, mat: GatewayMaterializer)(implicit system: ActorSystem, ec: ExecutionContext, amat: Materializer) extends SchemaProvider[GatewayContext, Any] with Logging {
  val loader = new SchemaLoader(config, client, mat)
  val schemaRef = new AtomicReference[Option[SchemaInfo[GatewayContext, Any]]](None)

  system.actorOf(FileMonitorActor.props(config.watch.allFiles, config.watch.threshold, config.watch.allGlobs, reloadSchema))

  private val producer = Source.actorRef[Boolean](100, OverflowStrategy.dropTail)
  private val runnableGraph = producer.toMat(BroadcastHub.sink(bufferSize = 256))(Keep.both)
  private val (changesPublisher, changesSource) = runnableGraph.run()

  val schemaChanges = Some(changesSource)

  def schemaInfo =
    schemaRef.get() match {
      case v @ Some(_) ⇒ Future.successful(v)
      case None ⇒ reloadSchema
    }

  def reloadSchema(files: Vector[File]): Unit = {
    logger.info(s"Schema files are changed: ${files mkString ", "}. Reloading schema")

    reloadSchema
  }

  def reloadSchema: Future[Option[SchemaInfo[GatewayContext, Any]]] =
    loader.loadSchema.andThen {
      case Success(Some(newSchema)) ⇒
        schemaRef.get() match {
          case Some(currentSchema) ⇒
            val changes = newSchema.schema.compare(currentSchema.schema)
            val renderedChanges =
              if (changes.nonEmpty)
                " with following changes:\n" + changes.map(c ⇒ "  * " + c.description + (if (c.breakingChange) " (breaking)" else "")).mkString("\n")
              else
                " without any changes."

            changesPublisher ! true
            logger.info(s"Schema successfully reloaded$renderedChanges")
          case None ⇒
            logger.info(s"Schema successfully loaded from files:\n${newSchema.files.map(f ⇒ "  * " + f).mkString("\n")}")
        }

        schemaRef.set(Some(newSchema))
      case Failure(error) ⇒
        logger.error("Failed to load the schema", error)
    }
} 
Example 41
Source File: SchemaLoader.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.schema

import better.files.File
import sangria.ast.Document
import sangria.execution.Executor
import sangria.execution.deferred.DeferredResolver
import sangria.gateway.AppConfig
import sangria.gateway.file.FileUtil
import sangria.gateway.http.client.HttpClient
import sangria.gateway.schema.materializer.{GatewayContext, GatewayMaterializer}
import sangria.gateway.util.Logging
import sangria.parser.QueryParser
import sangria.schema.Schema
import sangria.marshalling.circe._

import scala.concurrent.{ExecutionContext, Future}
import scala.util.control.NonFatal
import scala.util.{Failure, Success}

class SchemaLoader(config: AppConfig, client: HttpClient, mat: GatewayMaterializer)(implicit ec: ExecutionContext) extends Logging {
  def loadSchema: Future[Option[SchemaInfo[GatewayContext, Any]]] = {
    val files = FileUtil.loadFiles(config.watch.allFiles, config.watch.allGlobs)

    if (files.nonEmpty) {
      val parsed =
        files.map {
          case (path, content) ⇒ path → QueryParser.parse(content)
        }

      val failed = parsed.collect {case (path, Failure(e)) ⇒ path → e}

      if (failed.nonEmpty) {
        failed.foreach { case (path, error) ⇒
          logger.error(s"Can't parse file '$path':\n${error.getMessage}")
        }

        Future.successful(None)
      } else {
        val successful = parsed.collect {case (path, Success(doc)) ⇒ path → doc}
        val document = Document.merge(successful.map(_._2))

        try {
          val info =
            for {
              ctx ← GatewayContext.loadContext(config, client, document)
              schema = Schema.buildFromAst(document, mat.schemaBuilder(ctx).validateSchemaWithException(document))
              intro ← executeIntrospection(schema, ctx)
            } yield Some(SchemaInfo(
              schema,
              ctx,
              (),
              Nil,
              DeferredResolver.empty,
              schema.renderPretty,
              intro,
              files.map(_._1)))

          info.recover(handleError(files))
        } catch {
          case e if handleError(files).isDefinedAt(e) ⇒
            Future.successful(handleError(files)(e))
        }
      }
    } else {
      logger.error("No schema files found!")
      Future.successful(None)
    }
  }

  private def handleError(files: Vector[(File, String)]): PartialFunction[Throwable, Option[SchemaInfo[GatewayContext, Any]]] = {
    case NonFatal(e) ⇒
      logger.error(s"Can't create the schema from files: ${files.map(_._1).mkString(", ")}. " + e.getMessage)
      None
  }

  private def executeIntrospection(schema: Schema[GatewayContext, Any], ctx: GatewayContext) =
    Executor.execute(schema, sangria.introspection.introspectionQuery(schemaDescription = false, directiveRepeatableFlag = false), ctx)
} 
Example 42
Source File: AppConfig.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway

import better.files.File
import com.typesafe.config.Config
import net.ceedubs.ficus.Ficus._
import net.ceedubs.ficus.readers.ArbitraryTypeReader._

import scala.concurrent.duration.FiniteDuration

case class WatchConfig(
  enabled: Boolean,
  paths: Seq[String],
  pathsStr: Option[String],
  threshold: FiniteDuration,
  glob: Seq[String],
  globStr: Option[String]
) {
  lazy val allPaths = pathsStr.map(_.split("\\s*,\\s*").toSeq) getOrElse paths
  lazy val allFiles = allPaths.map(File(_))
  lazy val allGlobs = globStr.map(_.split("\\s*,\\s*").toSeq) getOrElse glob
}

case class LimitConfig(
  complexity: Double,
  maxDepth: Int,
  allowIntrospection: Boolean)

case class SlowLogConfig(
  enabled: Boolean,
  threshold: FiniteDuration,
  extension: Boolean,
  apolloTracing: Boolean)

case class AppConfig(
  port: Int,
  bindHost: String,
  graphiql: Boolean,
  playground: Boolean,
  slowLog: SlowLogConfig,
  watch: WatchConfig,
  limit: LimitConfig,
  includeDirectives: Option[Seq[String]],
  includeDirectivesStr: Option[String],
  excludeDirectives: Option[Seq[String]],
  excludeDirectivesStr: Option[String]
) {
  lazy val allIncludeDirectives = includeDirectivesStr.map(_.split("\\s*,\\s*").toSeq) orElse includeDirectives
  lazy val allExcludeDirectives = excludeDirectivesStr.map(_.split("\\s*,\\s*").toSeq) orElse excludeDirectives

  def isEnabled(directivesName: String) =
    !allExcludeDirectives.exists(_.contains(directivesName)) && (
      allIncludeDirectives.isEmpty ||
      allIncludeDirectives.exists(_.contains(directivesName)))
}

object AppConfig {
  def load(config: Config): AppConfig = config.as[AppConfig]
} 
Example 43
Source File: FileWatcher.scala    From graphql-gateway   with Apache License 2.0 5 votes vote down vote up
package sangria.gateway.file

import akka.actor._
import better.files.{Disposable, File, newMultiMap, repeat}
import better.files._

import scala.collection.mutable


class FileWatcher(file: File, maxDepth: Int) extends Actor {
  import FileWatcher._

  def this(file: File, recursive: Boolean = true) = this(file, if (recursive) Int.MaxValue else 0)

  protected[this] val callbacks = newMultiMap[Event, Callback]

  protected[this] val monitor: File.Monitor = new FileMonitor(file, maxDepth) {
    override def onEvent(event: Event, file: File, count: Int) = self ! Message.NewEvent(event, file, count)
    override def onException(exception: Throwable) = self ! Status.Failure(exception)
  }

  override def preStart() = monitor.start()(executionContext = context.dispatcher)

  override def receive = {
    case Message.NewEvent(event, target, count) if callbacks.contains(event) => callbacks(event).foreach(f => repeat(count)(f(event -> target)))
    case Message.RegisterCallback(events, callback) => events.foreach(event => callbacks.addBinding(event, callback))
    case Message.RemoveCallback(event, callback) => callbacks.removeBinding(event, callback)
  }

  override def postStop() = monitor.stop()
}

object FileWatcher {
  import java.nio.file.{Path, WatchEvent}

  type Event = WatchEvent.Kind[Path]
  type Callback = PartialFunction[(Event, File), Unit]

  sealed trait Message
  object Message {
    case class NewEvent(event: Event, file: File, count: Int) extends Message
    case class RegisterCallback(events: Traversable[Event], callback: Callback) extends Message
    case class RemoveCallback(event: Event, callback: Callback) extends Message
  }

  implicit val disposeActorSystem: Disposable[ActorSystem] =
    Disposable(_.terminate())

  implicit class FileWatcherOps(file: File) {
    def watcherProps(recursive: Boolean): Props =
      Props(new FileWatcher(file, recursive))

    def newWatcher(recursive: Boolean = true)(implicit ctx: ActorRefFactory): ActorRef =
      ctx.actorOf(watcherProps(recursive))
  }

  def when(events: Event*)(callback: Callback): Message =
    Message.RegisterCallback(events, callback)

  def on(event: Event)(callback: File => Unit): Message =
    when(event) { case (`event`, file) => callback(file) }

  def stop(event: Event, callback: Callback): Message =
    Message.RemoveCallback(event, callback)

  private def newMultiMap[A, B]: mutable.MultiMap[A, B] = new mutable.HashMap[A, mutable.Set[B]] with mutable.MultiMap[A, B]
  @inline private def repeat[U](n: Int)(f: => U): Unit = (1 to n).foreach(_ ⇒ f)
} 
Example 44
Source File: ExtractScriptGenSpec.scala    From comet-data-pipeline   with Apache License 2.0 5 votes vote down vote up
package com.ebiznext.comet.database.extractor

import better.files.File
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class ExtractScriptGenSpec extends AnyFlatSpec with Matchers {

  val scriptOutputFolder: File = File("/tmp")

  "templatize" should "generate an export script from a TemplateSettings" in {
    val templateParams: TemplateParams = TemplateParams(
      tableToExport = "table1",
      columnsToExport = List("col1", "col2"),
      fullExport = false,
      dsvDelimiter = ",",
      deltaColumn = Some("updateCol"),
      exportOutputFileBase = "output_file",
      scriptOutputFile = scriptOutputFolder / "EXTRACT_table1.sql"
    )

    val templatePayload: String = ScriptGen.templatize(
      File(
        getClass.getResource("/sample/database/EXTRACT_TABLE.sql.mustache").getPath
      ),
      templateParams
    )

    templatePayload shouldBe File(
      getClass.getResource("/sample/database/expected_script_payload.txt").getPath
    ).lines.mkString("\n")
  }

} 
Example 45
Source File: MetricsToolExecutor.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.cli.analysis

import java.nio.file.Path

import better.files.File
import com.codacy.analysis.core
import com.codacy.analysis.core.model.FileMetrics

import scala.util.{Failure, Success}

object MetricsToolExecutor {

  import com.codacy.analysis.cli.analysis.AnalyseExecutor._

  def reduceMetricsToolResultsByFile(metricsResults: Seq[MetricsToolExecutorResult]): Seq[MetricsToolExecutorResult] = {
    val (successfulMetricsResults, failedMetricsResults) =
      metricsResults.partition(_.analysisResults.isSuccess)

    successfulMetricsResults
      .groupBy(_.language)
      .values
      .flatMap {
        _.foldLeft(Option.empty[MetricsToolExecutorResult]) {
          case (
                Some(metricsExecutorResAcc @ MetricsToolExecutorResult(_, _, Success(fileMetricsAcc))),
                metricsExecutorRes @ MetricsToolExecutorResult(_, _, Success(fileMetrics))) =>
            val allFiles = metricsExecutorResAcc.files ++ metricsExecutorRes.files
            val reducedFileMetrics = reduceFileMetricsByFile(fileMetrics ++ fileMetricsAcc)
            Some(metricsExecutorResAcc.copy(files = allFiles, analysisResults = Success(reducedFileMetrics)))
          case (_, o) => Some(o)
        }
      }(collection.breakOut) ++ failedMetricsResults
  }

  private def reduceFileMetricsByFile(fileMetrics: Set[FileMetrics]): Set[FileMetrics] = {
    fileMetrics
      .groupBy(_.filename)
      .flatMap {
        case (filePath, fMetrics) =>
          fMetrics.reduceOption { (fMetricsAccumulator, fMetricsElement) =>
            FileMetrics(
              filePath,
              fMetricsAccumulator.complexity.orElse(fMetricsElement.complexity),
              fMetricsAccumulator.loc.orElse(fMetricsElement.loc),
              fMetricsAccumulator.cloc.orElse(fMetricsElement.cloc),
              fMetricsAccumulator.nrMethods.orElse(fMetricsElement.nrMethods),
              fMetricsAccumulator.nrClasses.orElse(fMetricsElement.nrClasses),
              if (fMetricsAccumulator.lineComplexities.nonEmpty) {
                fMetricsAccumulator.lineComplexities
              } else {
                fMetricsElement.lineComplexities
              })
          }
      }(collection.breakOut)
  }

  def calculateMissingFileMetrics(
    directory: File,
    metricsResults: Seq[AnalyseExecutor.MetricsToolExecutorResult]): Seq[MetricsToolExecutorResult] = {

    val fileMetricsByFilePath: Map[Path, FileMetrics] = metricsResults.flatMap { result =>
      result.analysisResults.map(_.map(fileMetrics => (fileMetrics.filename, fileMetrics))).getOrElse(Set.empty)
    }(collection.breakOut)

    metricsResults.foldLeft(Seq.empty[MetricsToolExecutorResult]) {
      case (metricsAccumulator, res @ AnalyseExecutor.MetricsToolExecutorResult(_, _, Success(_))) =>
        metricsAccumulator :+ countMissingLoc(directory, fileMetricsByFilePath, res)
      case (metricsAccumulator, res @ AnalyseExecutor.MetricsToolExecutorResult(lang, files, Failure(_)))
          if !metricsResults.exists(r => r.language == lang && r.files == files && r.analysisResults.isSuccess) =>
        metricsAccumulator :+ res :+ countMissingLoc(directory, fileMetricsByFilePath, res)
      case (metricsAccumulator, res) =>
        metricsAccumulator :+ res
    }
  }

  private def countMissingLoc(directory: File,
                              fileMetricsByFilePath: Map[Path, FileMetrics],
                              metricsRes: AnalyseExecutor.MetricsToolExecutorResult): MetricsToolExecutorResult = {
    val fileMetrics = metricsRes.files.map { file =>
      fileMetricsByFilePath.get(file) match {
        case None =>
          FileMetrics(
            filename = file,
            nrClasses = None,
            nrMethods = None,
            loc = countLoc(directory, file),
            cloc = None,
            complexity = None,
            lineComplexities = Set.empty)
        case Some(metrics) if metrics.loc.isEmpty => metrics.copy(loc = countLoc(directory, file))
        case Some(metrics)                        => metrics
      }
    }
    metricsRes.copy(analysisResults = Success(fileMetrics))
  }

  private def countLoc(directory: File, file: Path): Option[Int] = {
    val fileAbsolutePath = (directory / file.toString).path.toAbsolutePath.toString
    core.utils.FileHelper.countLoc(fileAbsolutePath)
  }
} 
Example 46
Source File: FallbackFileCollector.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.files

import better.files.File
import cats.MonadError

class FallbackFileCollector[T[_]](fileCollectorCompanions: List[FileCollectorCompanion[T]])(implicit
  monadError: MonadError[T, Throwable])
    extends FileCollector[T] {

  private val fileCollectors: List[FileCollector[T]] = fileCollectorCompanions.map(_.apply())

  override def list(directory: File): T[FilesTarget] = {
    list(fileCollectors, directory)
  }

  private def list(fileCollectorList: List[FileCollector[T]], directory: File): T[FilesTarget] = {
    fileCollectorList match {
      case fileCollector :: tail =>
        monadError.recoverWith(fileCollector.list(directory)) {
          case _ =>
            logger.info(s"Failed to list files with ${fileCollector.getClass.getName}")
            list(tail, directory)
        }
      case Nil =>
        val errorMessage =
          s"All FileCollectors failed to list files: ${fileCollectorCompanions.map(_.name).mkString(",")}"
        logger.error(errorMessage)

        monadError.raiseError(new Exception(errorMessage))
    }
  }
}

class FallbackFileCollectorCompanion[T[_]](fileCollectorCompanions: List[FileCollectorCompanion[T]])(implicit
  monadError: MonadError[T, Throwable])
    extends FileCollectorCompanion[T] {

  val name: String = s"fallback:${fileCollectorCompanions.map(_.name).mkString(",")}"

  override def apply(): FileCollector[T] = new FallbackFileCollector(fileCollectorCompanions)

} 
Example 47
Source File: DuplicationTool.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.tools

import java.nio.file.Path

import better.files.File
import com.codacy.analysis.core.model.DuplicationClone
import com.codacy.plugins.api.duplication.DuplicationTool.CodacyConfiguration
import com.codacy.plugins.api.languages.Language
import com.codacy.plugins.api
import com.codacy.plugins.duplication.traits
import com.codacy.plugins.runners.{BinaryDockerRunner, DockerRunner}
import com.codacy.plugins.utils.PluginHelper
import org.log4s.getLogger

import scala.concurrent.duration._
import scala.util.Try

class DuplicationTool(private val duplicationTool: traits.DuplicationTool, val languageToRun: Language) extends ITool {

  override def name: String = "duplication"
  override def supportedLanguages: Set[Language] = duplicationTool.languages.to[Set]

  def run(directory: File,
          files: Set[Path],
          timeout: Option[Duration] = Option.empty[Duration]): Try[Set[DuplicationClone]] = {
    val dockerRunner = new BinaryDockerRunner[api.duplication.DuplicationClone](duplicationTool)
    val runner = new traits.DuplicationRunner(duplicationTool, dockerRunner)

    for {
      duplicationClones <- runner.run(
        directory.toJava,
        CodacyConfiguration(Option(languageToRun), Option.empty),
        timeout.getOrElse(DockerRunner.defaultRunTimeout),
        None)
      clones = filterDuplicationClones(duplicationClones, files)
    } yield {
      clones.map(clone => DuplicationClone(clone.cloneLines, clone.nrTokens, clone.nrLines, clone.files.to[Set]))(
        collection.breakOut): Set[DuplicationClone]
    }
  }

  private def filterDuplicationClones(duplicationClones: List[api.duplication.DuplicationClone],
                                      files: Set[Path],
                                      minCloneLines: Int = 5): List[api.duplication.DuplicationClone] = {
    // The duplication files should be more than 1. If it is one, then it means
    // that the other clone was in an ignored file. This is based on the assumption
    // that the duplication results will contain more than one entry for files
    // with duplicated clones with themselves.
    duplicationClones.collect {
      case clone if clone.nrLines >= minCloneLines =>
        val commitFileNames = files.map(_.toString)
        val filteredFiles = filterUnignoredFiles(clone.files, commitFileNames)
        (clone.copy(files = filteredFiles), filteredFiles.length)
    }.collect { case (clone, nrCloneFiles) if nrCloneFiles > 1 => clone }
  }

  private def filterUnignoredFiles(duplicated: Seq[api.duplication.DuplicationCloneFile],
                                   expectedFiles: Set[String]): Seq[api.duplication.DuplicationCloneFile] = {
    duplicated.collect {
      case cloneFile if expectedFiles.contains(cloneFile.filePath) =>
        cloneFile
    }
  }
}

object DuplicationToolCollector {

  private val logger: org.log4s.Logger = getLogger

  private val availableTools: List[traits.DuplicationTool] = PluginHelper.dockerDuplicationPlugins

  def fromLanguages(languages: Set[Language]): Set[DuplicationTool] = {
    languages.flatMap { lang =>
      val collectedTools = availableTools.collect {
        case tool if tool.languages.contains(lang) =>
          new DuplicationTool(tool, lang)
      }
      if (collectedTools.isEmpty) {
        logger.info(s"No duplication tools found for language ${lang.name}")
      }
      collectedTools
    }
  }

} 
Example 48
Source File: MetricsTool.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.tools

import java.nio.file.Paths

import better.files.File
import com.codacy.analysis.core.model.FileMetrics
import com.codacy.plugins.api
import com.codacy.plugins.api.Source
import com.codacy.plugins.api.languages.Language
import com.codacy.plugins.api.metrics.MetricsTool.CodacyConfiguration
import com.codacy.plugins.metrics.traits
import com.codacy.plugins.metrics.traits.{MetricsRequest, MetricsRunner}
import com.codacy.plugins.runners.{BinaryDockerRunner, DockerRunner}
import com.codacy.plugins.utils.PluginHelper
import org.log4s.getLogger

import scala.concurrent.duration.Duration
import scala.util.Try

class MetricsTool(private val metricsTool: traits.MetricsTool, val languageToRun: Language) extends ITool {
  override def name: String = "metrics"

  override def supportedLanguages: Set[Language] = metricsTool.languages.to[Set]

  def run(directory: File,
          files: Option[Set[Source.File]],
          timeout: Option[Duration] = Option.empty[Duration]): Try[List[FileMetrics]] = {
    val request = MetricsRequest(directory.pathAsString)

    val dockerRunner = new BinaryDockerRunner[api.metrics.FileMetrics](metricsTool)
    val runner = new MetricsRunner(metricsTool, dockerRunner)

    val configuration = CodacyConfiguration(files, Some(languageToRun), None)

    val toolFileMetrics =
      runner.run(request, configuration, timeout.getOrElse(DockerRunner.defaultRunTimeout), None)

    toolFileMetrics.map {
      _.collect {
        case fileMetrics if unignoredFile(fileMetrics, files) =>
          FileMetrics(
            filename = Paths.get(fileMetrics.filename),
            complexity = fileMetrics.complexity,
            loc = fileMetrics.loc,
            cloc = fileMetrics.cloc,
            nrMethods = fileMetrics.nrMethods,
            nrClasses = fileMetrics.nrClasses,
            lineComplexities = fileMetrics.lineComplexities)
      }
    }
  }

  def unignoredFile(metrics: api.metrics.FileMetrics, files: Option[Set[Source.File]]): Boolean = {
    files.forall(_.exists(_.path == metrics.filename))
  }
}

object MetricsToolCollector {

  private val logger: org.log4s.Logger = getLogger

  private val availableTools = PluginHelper.dockerMetricsPlugins

  def fromLanguages(languages: Set[Language]): Set[MetricsTool] = {
    languages.flatMap { lang =>
      val collectedTools = availableTools.collect {
        case tool if tool.languages.contains(lang) =>
          new MetricsTool(tool, lang)
      }
      if (collectedTools.isEmpty) {
        logger.info(s"No metrics tools found for language ${lang.name}")
      }
      collectedTools
    }
  }

} 
Example 49
Source File: Analyser.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.analysis

import java.nio.file.Path

import better.files.File
import com.codacy.analysis.core.model.{Configuration, DuplicationClone, FileMetrics, ToolResult}
import com.codacy.analysis.core.tools.{DuplicationTool, MetricsTool, Tool}
import org.log4s.{Logger, getLogger}

import scala.concurrent.duration.Duration
import scala.util.Try

trait AnalyserCompanion[T[_]] {
  def name: String
  def apply(): Analyser[T]
}

trait Analyser[T[_]] {

  def analyse(tool: Tool,
              directory: File,
              files: Set[Path],
              config: Configuration,
              timeout: Option[Duration] = Option.empty[Duration]): T[Set[ToolResult]]

  def metrics(metricsTool: MetricsTool,
              directory: File,
              files: Option[Set[Path]],
              timeout: Option[Duration] = Option.empty[Duration]): T[Set[FileMetrics]]

  def duplication(duplicationTool: DuplicationTool,
                  directory: File,
                  files: Set[Path],
                  timeout: Option[Duration] = Option.empty[Duration]): T[Set[DuplicationClone]]

}

object Analyser {

  private val logger: Logger = getLogger

  val defaultAnalyser: AnalyserCompanion[Try] = CodacyPluginsAnalyser

  val allAnalysers: Set[AnalyserCompanion[Try]] = Set(defaultAnalyser)

  def apply(name: String): Analyser[Try] = {
    val builder = allAnalysers.find(_.name.equalsIgnoreCase(name)).getOrElse {
      logger.warn(s"Could not find analyser for name $name. Using ${defaultAnalyser.name} as fallback.")
      defaultAnalyser
    }

    builder()
  }

  sealed trait Error {
    val message: String
  }

  object Error {

    final case class ToolExecutionFailure(toolType: String, toolName: String) extends Error {
      override val message: String = s"Failed $toolType for $toolName"
    }

    final case class ToolNeedsNetwork(toolName: String) extends Error {
      override val message: String = s"The tool $toolName needs network access to execute."
    }

    final case class NonExistingToolInput(toolName: String, availableTools: Set[String]) extends Error {

      override val message: String =
        s"""The selected tool "$toolName" is not supported or does not exist.
                                        |The tool should be one of (${availableTools.mkString(", ")})""".stripMargin
    }

    case object NoActiveToolInConfiguration extends Error {
      override val message: String = "No active tool found on the remote configuration"
    }

    case object NoToolsFoundForFiles extends Error {
      override val message: String = "No tools found for files provided"
    }

  }
} 
Example 50
Source File: CodacyPluginsAnalyser.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.analysis

import java.nio.file.Path

import better.files.File
import com.codacy.analysis.core.model._
import com.codacy.analysis.core.tools.{DuplicationTool, MetricsTool, Tool}
import com.codacy.plugins.api.Source
import org.log4s.{Logger, getLogger}

import scala.concurrent.duration._
import scala.util.{Failure, Success, Try}

class CodacyPluginsAnalyser extends Analyser[Try] {

  private val logger: Logger = getLogger

  override def analyse(tool: Tool,
                       directory: File,
                       files: Set[Path],
                       config: Configuration,
                       timeout: Option[Duration] = Option.empty[Duration]): Try[Set[ToolResult]] = {
    val result = tool.run(directory, files, config, timeout)

    result match {
      case Success(res) =>
        logger.info(s"Completed analysis for ${tool.name} with ${res.size} results")
      case Failure(e) =>
        logger.error(e)(Analyser.Error.ToolExecutionFailure("analysis", tool.name).message)
    }

    result
  }

  override def metrics(metricsTool: MetricsTool,
                       directory: File,
                       files: Option[Set[Path]],
                       timeout: Option[Duration] = Option.empty[Duration]): Try[Set[FileMetrics]] = {

    val srcFiles = files.map(_.map(filePath => Source.File(filePath.toString)))

    val result = metricsTool.run(directory, srcFiles, timeout)

    result match {
      case Success(res) =>
        logger.info(s"Completed metrics for ${metricsTool.name} with ${res.size} results")
      case Failure(e) =>
        logger.error(e)(Analyser.Error.ToolExecutionFailure("metrics", metricsTool.name).message)
    }

    result.map(_.to[Set])
  }

  override def duplication(duplicationTool: DuplicationTool,
                           directory: File,
                           files: Set[Path],
                           timeout: Option[Duration] = Option.empty[Duration]): Try[Set[DuplicationClone]] = {

    val result = duplicationTool.run(directory, files, timeout)

    result match {
      case Success(res) =>
        logger.info(s"Completed duplication for ${duplicationTool.name} with ${res.size} results")
      case Failure(e) =>
        logger.error(e)(Analyser.Error.ToolExecutionFailure("duplication", duplicationTool.name).message)
    }

    result.map(_.to[Set])
  }

}

object CodacyPluginsAnalyser extends AnalyserCompanion[Try] {

  val name: String = "codacy-plugins"

  override def apply(): Analyser[Try] = new CodacyPluginsAnalyser()

  object errors {

    def missingTool(tool: String): Analyser.Error =
      Analyser.Error.NonExistingToolInput(tool, Tool.allToolShortNames)
  }

} 
Example 51
Source File: CodacyConfigurationFile.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.configuration

import better.files.File
import cats.syntax.show._
import com.codacy.analysis.core.files.Glob
import com.codacy.plugins.api.languages.{Language, Languages}
import io.circe.generic.auto._
import io.circe.yaml.parser
import io.circe.{Decoder, Json, _}
import play.api.libs.json.JsValue

import scala.util.{Properties, Try}

final case class LanguageConfiguration(extensions: Option[Set[String]])

final case class EngineConfiguration(excludePaths: Option[Set[Glob]],
                                     baseSubDir: Option[String],
                                     extraValues: Option[Map[String, JsValue]])

final case class CodacyConfigurationFile(engines: Option[Map[String, EngineConfiguration]],
                                         excludePaths: Option[Set[Glob]],
                                         languages: Option[Map[Language, LanguageConfiguration]]) {

  lazy val languageCustomExtensions: Map[Language, Set[String]] =
    languages.fold(Map.empty[Language, Set[String]])(_.map {
      case (lang, config) => (lang, config.extensions.getOrElse(Set.empty[String]))
    })
}

class CodacyConfigurationFileLoader {

  val filenames: Set[String] = Set(".codacy.yaml", ".codacy.yml")

  def load(directory: File): Either[String, CodacyConfigurationFile] = {
    search(directory).flatMap(configDir => parse(configDir.contentAsString))
  }

  def search(root: File): Either[String, File] = {
    filenames
      .map(root / _)
      .find(f => f.exists && f.isRegularFile)
      .fold[Either[String, File]](
        Left(s"Could not find Codacy configuration file. Make sure you have a file named like one of ${filenames
          .mkString(", ")}."))(Right(_))
  }

  def parse(yamlString: String): Either[String, CodacyConfigurationFile] = {
    for {
      json <- parser.parse(yamlString).left.map(_.show)
      cursor = HCursor.fromJson(json)
      configurationEither = Decoder[CodacyConfigurationFile].decodeAccumulating(cursor).toEither
      configuration <- configurationEither.left.map(_.toList.map(_.show).mkString(Properties.lineSeparator))
    } yield configuration
  }

}

object CodacyConfigurationFile {

  implicit val globDecoder: Decoder[Glob] = (c: HCursor) => c.as[String].map(Glob)

  implicit val languageKeyDecoder: KeyDecoder[Language] = (languageStr: String) => Languages.fromName(languageStr)

  implicit val decodeEngineConfiguration: Decoder[EngineConfiguration] =
    new Decoder[EngineConfiguration] {
      val engineConfigurationKeys = Set("enabled", "exclude_paths", "base_sub_dir")

      def apply(c: HCursor): Decoder.Result[EngineConfiguration] = {
        val extraKeys =
          c.keys.fold(List.empty[String])(_.to[List]).filter(key => !engineConfigurationKeys.contains(key))
        for {
          excludePaths <- c.downField("exclude_paths").as[Option[Set[Glob]]]
          baseSubDir <- c.downField("base_sub_dir").as[Option[String]]
        } yield {
          val extraToolConfigurations: Map[String, JsValue] = extraKeys.flatMap { extraKey =>
            c.downField(extraKey)
              .as[Json]
              .fold[Option[JsValue]](
                { _ =>
                  Option.empty
                },
                { json =>
                  Try(play.api.libs.json.Json.parse(json.noSpaces)).toOption
                })
              .map(value => (extraKey, value))
          }(collection.breakOut)

          EngineConfiguration(excludePaths, baseSubDir, Option(extraToolConfigurations).filter(_.nonEmpty))
        }
      }
    }

  implicit val decodeCodacyConfigurationFile: Decoder[CodacyConfigurationFile] =
    Decoder.forProduct3("engines", "exclude_paths", "languages")(CodacyConfigurationFile.apply)

} 
Example 52
Source File: FileHelper.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.utils

import java.nio.file.Path

import better.files.File
import org.log4s
import org.log4s.getLogger

import scala.util.Try

object FileHelper {

  private val logger: log4s.Logger = getLogger

  def relativePath(filename: String): Path = File.currentWorkingDirectory.relativize(File(filename))

  def countLoc(filename: String): Option[Int] = {
    Try(File(filename).lineIterator).fold(
      { t =>
        logger.error(t)(s"Failed to read file $filename")
        Option.empty[Int]
      },
      { lines =>
        Some(lines.foldLeft(0) {
          case (counter, line) if line.trim.length >= 3 => counter + 1
          case (counter, _)                             => counter
        })
      })
  }
} 
Example 53
Source File: Git.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.git

import better.files.File
import org.eclipse.jgit.internal.storage.file.FileRepository
import org.eclipse.jgit.storage.file.FileRepositoryBuilder
import org.log4s.{Logger, getLogger}

import scala.util.Try

object Git {

  private val logger: Logger = getLogger

  def repository(directory: File): Try[Repository] = {
    Try((directory / ".git").toJava).filter(d => new FileRepository(d.getPath).getObjectDatabase.exists()).flatMap {
      gitDir =>
        Try {
          val builder = new FileRepositoryBuilder

          val repository = builder.setGitDir(gitDir).readEnvironment.findGitDir.build

          new Repository(repository)
        }
    }
  }

  def currentCommitUuid(directory: File): Option[Commit.Uuid] = {
    Git
      .repository(directory)
      .flatMap(_.latestCommit)
      .fold(
        { e =>
          logger.warn(e)(e.getMessage)
          None
        },
        commit => Some(commit.commitUuid))
  }

} 
Example 54
Source File: ValidateConfigurationCommandSpec.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.cli.command

import better.files.{File, Resource}
import com.codacy.analysis.cli.analysis.ExitStatus.ExitCodes
import org.specs2.control.NoLanguageFeatures
import org.specs2.matcher.FileMatchers
import org.specs2.mutable.Specification

class ValidateConfigurationCommandSpec extends Specification with NoLanguageFeatures with FileMatchers {

  "ValidateConfigurationExecutor" should {
    "find configuration file" in {
      File
        .temporaryDirectory()
        .map { directory =>
          val resource = Resource.getAsString("com/codacy/analysis/core/configuration/codacy.yaml")
          (directory / ".codacy.yaml").write(resource)

          val command =
            ValidateConfigurationCommand(ValidateConfiguration(CommonOptions(), Option(directory)))

          command.run() mustEqual ExitCodes.success
        }
        .get
    }

    "fail" in {
      File
        .temporaryDirectory()
        .map { directory =>
          val command =
            ValidateConfigurationCommand(ValidateConfiguration(CommonOptions(), Option(directory)))

          command.run() mustEqual ExitCodes.invalidConfigurationFile
        }
        .get
    }
  }

} 
Example 55
Source File: ValidateConfigurationCommand.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.cli.command

import better.files.File
import com.codacy.analysis.cli.analysis.ExitStatus
import com.codacy.analysis.cli.analysis.ExitStatus.ExitCodes
import com.codacy.analysis.core.configuration.CodacyConfigurationFileLoader

object ValidateConfigurationCommand {

  def apply(validateConfiguration: ValidateConfiguration): ValidateConfigurationCommand = {
    new ValidateConfigurationCommand(validateConfiguration, new CodacyConfigurationFileLoader())
  }
}

class ValidateConfigurationCommand(validateConfiguration: ValidateConfiguration,
                                   configurationLoader: CodacyConfigurationFileLoader) {

  def run(): ExitStatus.ExitCode = {
    val directory = validateConfiguration.directory.getOrElse(File.currentWorkingDirectory)

    (for {
      file <- configurationLoader.search(directory)
      cfgFile <- configurationLoader.parse(file.contentAsString)
    } yield (file, cfgFile)) match {
      case Left(e) =>
        Console.err.println(e)
        ExitCodes.invalidConfigurationFile

      case Right((file, cfgFile)) =>
        Console.out.println(s"Successfully loaded the Codacy configuration file in ${file.pathAsString}")
        pprint.pprintln(cfgFile)
        ExitCodes.success
    }

  }

} 
Example 56
Source File: GitSpec.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.git

import better.files.File
import org.specs2.control.NoLanguageFeatures
import org.specs2.mutable.Specification
import com.codacy.analysis.core.utils.TestUtils._

import scala.sys.process.Process

class GitSpec extends Specification with NoLanguageFeatures {

  "Git" should {
    "create a repository" in {
      (for {
        temporaryDirectory <- File.temporaryDirectory()
      } yield {
        Process(Seq("git", "init"), temporaryDirectory.toJava).!

        Git.repository(temporaryDirectory) must beSuccessfulTry
      }).get
    }

    "get the current commit uuid" in {
      withTemporaryGitRepo(directory => {
        val expectedUuid = Process(Seq("git", "rev-parse", "HEAD"), directory.toJava).!!.trim
        Git.currentCommitUuid(directory) must beLike {
          case Some(commit) => commit.value must beEqualTo(expectedUuid)
        }
      })
    }

    "fail to create a repository" in {
      (for {
        temporaryDirectory <- File.temporaryDirectory()
      } yield {
        Git.repository(temporaryDirectory) must beFailedTry
      }).get
    }
  }

} 
Example 57
Source File: Environment.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.cli.configuration

import java.net.URL

import better.files.File
import com.codacy.analysis.core.utils.Implicits._
import org.log4s.{Logger, getLogger}

import scala.util.{Failure, Try}

class Environment(variables: Map[String, String]) {

  private val logger: Logger = getLogger

  def codeDirectoryEnvironmentVariable(): Option[String] = {
    validate("Project directory", "environment variable", "CODACY_CODE")(variables.get("CODACY_CODE"))
  }

  def projectTokenArgument(projectTokenFromArguments: Option[String]): Option[String] = {
    validate("Project token", "argument", "--project-token")(projectTokenFromArguments)
  }

  def projectTokenEnvironmentVariable(): Option[String] = {
    validate("Project token", "environment variable", "CODACY_PROJECT_TOKEN")(variables.get("CODACY_PROJECT_TOKEN"))
  }

  def apiTokenArgument(apiTokenFromArguments: Option[String]): Option[String] = {
    validate("API token", "argument", "--api-token")(apiTokenFromArguments)
  }

  def apiTokenEnvironmentVariable(): Option[String] = {
    validate("API token", "environment variable", "CODACY_API_TOKEN")(variables.get("CODACY_API_TOKEN"))
  }

  def apiBaseUrlArgument(codacyApiBaseURLFromArguments: Option[String]): Option[String] = {
    val apiURL =
      validate("API base URL", "argument", "--codacy-api-base-url")(codacyApiBaseURLFromArguments)
    validateApiBaseUrl(apiURL)
  }

  def apiBaseUrlEnvironmentVariable(): Option[String] = {
    val apiURL =
      validate("API base URL", "environment variable", "CODACY_API_BASE_URL")(variables.get("CODACY_API_BASE_URL"))
    validateApiBaseUrl(apiURL)
  }

  def baseProjectDirectory(directory: Option[File]): File =
    directory.fold(codeDirectoryEnvironmentVariable().map(File(_)).getOrElse(File.currentWorkingDirectory))(dir =>
      if (dir.isDirectory) dir else dir.parent)

  private def validateApiBaseUrl(apiURL: Option[String]): Option[String] = {
    apiURL.flatMap { url =>
      Try(new URL(url)) match {
        case Failure(_) =>
          val error = s"Invalid API base URL: $url"

          val help = if (!url.startsWith("http")) {
            " * Maybe you forgot the http:// or https:// ?"
          }

          logger.warn(s"$error\n$help")
          Option.empty[String]

        case _ =>
          logger.info(s"Using API base URL $url")
          Option(url)
      }
    }
  }

  private def validate(name: String, paramType: String, param: String)(value: Option[String]): Option[String] = {
    value.ifEmpty(logger.info(s"$name not passed through $paramType `$param`")).flatMap {
      case t if t.trim.nonEmpty =>
        logger.info(s"$name found in $paramType `$param`")
        Option(t.trim)
      case _ =>
        logger.warn(s"$name passed through $paramType `$param` is empty")
        Option.empty[String]
    }
  }
} 
Example 58
Source File: EnrichToKafkaSimulator.scala    From trucking-iot   with Apache License 2.0 5 votes vote down vote up
package com.orendainx.trucking.simulator.simulators

import akka.actor.{Actor, ActorSystem, Inbox, Props}
import better.files.File
import com.orendainx.trucking.commons.models._
import com.orendainx.trucking.enrichment.WeatherAPI
import com.orendainx.trucking.simulator.coordinators.AutomaticCoordinator
import com.orendainx.trucking.simulator.depots.NoSharingDepot
import com.orendainx.trucking.simulator.flows.SharedFlowManager
import com.orendainx.trucking.simulator.generators.TruckAndTrafficGenerator
import com.orendainx.trucking.simulator.services.DriverFactory
import com.orendainx.trucking.simulator.transmitters.{ActorTransmitter, DataTransmitter, KafkaTransmitter}
import com.typesafe.config.{Config, ConfigFactory}

import scala.concurrent.Await
import scala.concurrent.duration._


  private class EnrichmentActor extends Actor {
    def receive = {
      case td: TruckData =>
        kafkaTruckTransmitter ! DataTransmitter.Transmit(
          EnrichedTruckData(td,
            WeatherAPI.default.getFog(td.eventType),
            WeatherAPI.default.getRain(td.eventType),
            WeatherAPI.default.getWind(td.eventType))
        )
      case td: TrafficData =>
        kafkaTrafficTransmitter ! DataTransmitter.Transmit(td)
    }
  }
} 
Example 59
Source File: DockerImagesWriterTest.scala    From exodus   with MIT License 5 votes vote down vote up
package com.wix.bazel.migrator

import java.nio.file.{Files, Path}

import better.files.File
import com.github.marschall.memoryfilesystem.MemoryFileSystemBuilder
import com.wix.bazel.migrator.overrides.{InternalTargetOverride, InternalTargetsOverrides}
import org.specs2.matcher.{Matcher, Scope}
import org.specs2.mutable.SpecificationWithJUnit

class DockerImagesWriterTest extends SpecificationWithJUnit {
  abstract class ctx extends Scope{

    def containExactlyOnce(substr: String): Matcher[String] = {
      {a:String => a.indexOf(substr) must not be_== -1} and {a:String => a.indexOf(substr) must beEqualTo(a.lastIndexOf(substr))}
    }

    val rootfs: Path = MemoryFileSystemBuilder.newLinux().build().getPath("repo-root")
    val overrideWithDockerImages = InternalTargetOverride("some-label", dockerImagesDeps = Option(List("mysql:5.7", "docker-repo.wixpress.com/com.wixpress.whatever/whatever:1.234.5")))
    def overrides: Set[InternalTargetOverride]
    def writer = new DockerImagesWriter(rootfs, InternalTargetsOverrides(overrides))
  }

  "DockerImagesWriter" should {
    "create docker_images.bzl in third_party/docker_images" in new ctx {
      def overrides: Set[InternalTargetOverride] = Set.empty
      writer.write()
      Files.exists(rootfs.resolve("third_party/docker_images/docker_images.bzl")) should beTrue
    }

    "create BUILD.bazel file in third_party/docker_images" in new ctx {
      def overrides: Set[InternalTargetOverride] = Set.empty
      writer.write()
      Files.exists(rootfs.resolve("third_party/docker_images/BUILD.bazel")) should beTrue
    }

    "fill default values in container_pull for short-form image" in new ctx {
      def overrides: Set[InternalTargetOverride] = Set(overrideWithDockerImages)
      writer.write()
      val expected: String =
        s"""|  container_pull(
            |    name = "mysql_5.7",
            |    registry = "index.docker.io",
            |    repository = "library/mysql",
            |    tag = "5.7"
            |  )""".stripMargin
      File(rootfs.resolve("third_party/docker_images/docker_images.bzl")).contentAsString must contain(expected)
    }

    "write values as-is in container_pull for full form image" in new ctx {
      def overrides: Set[InternalTargetOverride] = Set(overrideWithDockerImages)
      writer.write()
      val expected: String =
        s"""|  container_pull(
            |    name = "com.wixpress.whatever_whatever_1.234.5",
            |    registry = "docker-repo.wixpress.com",
            |    repository = "com.wixpress.whatever/whatever",
            |    tag = "1.234.5"
            |  )""".stripMargin
      File(rootfs.resolve("third_party/docker_images/docker_images.bzl")).contentAsString must contain(expected)
    }

    "write container_image in BUILD file" in new ctx {
      def overrides: Set[InternalTargetOverride] = Set(overrideWithDockerImages)
      writer.write()
      val expected: String =
        s"""container_image(name="com.wixpress.whatever_whatever_1.234.5", base="@com.wixpress.whatever_whatever_1.234.5//image")""".stripMargin

      File(rootfs.resolve("third_party/docker_images/BUILD.bazel")).contentAsString must contain(expected)
    }

    "deduplicate images in BUILD file" in new ctx {
      def overrides = Set(overrideWithDockerImages, overrideWithDockerImages.copy(label = "duplicate"))
      writer.write()
      private val fileContent: String = File(rootfs.resolve("third_party/docker_images/BUILD.bazel")).contentAsString
      fileContent must containExactlyOnce("container_image(name=\"mysql_5.7\",")
    }

    "deduplicate images in docker_images.bzl file" in new ctx {

      def overrides = Set(overrideWithDockerImages, overrideWithDockerImages.copy(label = "duplicate"))
      writer.write()
      private val fileContent: String = File(rootfs.resolve("third_party/docker_images/docker_images.bzl")).contentAsString
      fileContent must containExactlyOnce("name = \"mysql_5.7\",")
    }
  }
} 
Example 60
Source File: GitRepository.scala    From exodus   with MIT License 5 votes vote down vote up
package com.wixpress.build.git

import better.files.File
import org.eclipse.jgit.api.Git

case class GitRepository(path: File, git: Git) {
  def pathAsString: String = path.pathAsString
}

object GitRepository {
  def newRemote: GitRepository = {
    val remoteRepoDir = newDisposableDir("remote-dir")
    GitRepository(remoteRepoDir, Git.init()
      .setDirectory(remoteRepoDir.toJava)
      .setBare(true)
      .call())
  }

  def newLocal: GitRepository = {
    val localRepoDir = newDisposableDir("local-dir")
    GitRepository(localRepoDir, Git.init()
      .setDirectory(localRepoDir.toJava)
      .call())
  }

  def newLocalCloneOf(remoteRepo: GitRepository): GitRepository = {
    val localCloneDir = newDisposableDir("clone")
    GitRepository(localCloneDir, Git.cloneRepository()
      .setURI(remoteRepo.path.pathAsString)
      .setDirectory(localCloneDir.path.toFile)
      .call())
  }

  private def newDisposableDir(prefix: String): File = {
    val tmpDir = File.newTemporaryDirectory(prefix)
    tmpDir.toJava.deleteOnExit()
    tmpDir
  }
} 
Example 61
Source File: FakeLocalBazelWorkspace.scala    From exodus   with MIT License 5 votes vote down vote up
package com.wixpress.build.bazel

import scala.collection.mutable
import ThirdPartyPaths._
import better.files.File

class FakeLocalBazelWorkspace(sourceFiles: mutable.Map[String, String] = mutable.Map.empty, val localWorkspaceName: String = "") extends BazelLocalWorkspace {

  // since FakeLocalBazelWorkspace is already stateful - I allowed another state.
  // on next revision of SynchronizerAcceptanceTest - we will introduce stateless FakeWorkspace
  private var overrides = ThirdPartyOverrides.empty

  def setThirdPartyOverrides(overrides: ThirdPartyOverrides): Unit = {
    this.overrides = overrides
  }

  override def thirdPartyReposFileContent(): String =
    sourceFiles.getOrElse(thirdPartyReposFilePath, "")

  override def overwriteThirdPartyReposFile(skylarkFileContent: String): Unit =
    sourceFiles.put(thirdPartyReposFilePath, skylarkFileContent)

  override def overwriteThirdPartyImportTargetsFile(thirdPartyGroup: String, thirdPartyReposContent: String): Unit = {
    val fileKey = s"$thirdPartyImportFilesPathRoot/$thirdPartyGroup.bzl"
    thirdPartyReposContent match {
      case "" => sourceFiles.remove(fileKey)
      case _ => sourceFiles.put(fileKey, thirdPartyReposContent)
    }
  }

  override def buildFileContent(packageName: String): Option[String] =
    sourceFiles.get(packageName + "/BUILD.bazel")

  override def thirdPartyImportTargetsFileContent(thirdPartyGroup: String): Option[String] =
    sourceFiles.get(s"$thirdPartyImportFilesPathRoot/$thirdPartyGroup.bzl")

  override def allThirdPartyImportTargetsFilesContent(): Set[String] =
    sourceFiles.filter(f => f._1.contains(thirdPartyImportFilesPathRoot + "/")).values.toSet

  override def allThirdPartyImportTargetsFiles(): Map[File, String] =
    sourceFiles.filter(f => f._1.contains(thirdPartyImportFilesPathRoot + "/")).map(pair => (File(pair._1), pair._2)).toMap

  override def overwriteBuildFile(packageName: String, content: String): Unit =
    sourceFiles.put(packageName + "/BUILD.bazel", content)

  override def thirdPartyOverrides(): ThirdPartyOverrides = overrides
}

object FakeLocalBazelWorkspace {
  val thirdPartyReposFilePath: String =  "third_party.bzl"
  val thirdPartyImportFilesPathRoot: String = "third_party"
} 
Example 62
Source File: FileSystemBazelLocalWorkspace.scala    From exodus   with MIT License 5 votes vote down vote up
package com.wixpress.build.bazel

import java.io.FileNotFoundException

import better.files.File
import ThirdPartyPaths._

class FileSystemBazelLocalWorkspace(root: File) extends BazelLocalWorkspace {

  val localWorkspaceName: String = {
    val workspaceFileContent = contentIfExistsOf(root / "WORKSPACE")
    val validWorkspaceWith = """(?s).*workspace\s*\(\s*name\s*=\s*"([^"]+)"\s*\).*""".r

    workspaceFileContent match {
      case Some(validWorkspaceWith(name)) => name
      case _ =>   ""
    }
  }

  private val ThirdPartyOverridesPath = "bazel_migration/third_party_targets.overrides"

  validate()

  override def overwriteBuildFile(packageName: String, content: String): Unit = {
    val buildFilePath = root / packageName / "BUILD.bazel"
    buildFilePath.createIfNotExists(createParents = true)
    buildFilePath.overwrite(content)
  }

  override def overwriteThirdPartyReposFile(thirdPartyReposContent: String): Unit =
    (root / thirdPartyReposFilePath).overwrite(thirdPartyReposContent)

  override def overwriteThirdPartyImportTargetsFile(thirdPartyGroup: String, content: String): Unit = {
    val targetsFile = root / s"$thirdPartyImportFilesPathRoot/$thirdPartyGroup.bzl"
    content match {
      case "" => if (targetsFile.exists) targetsFile.delete()
      case _ => {
        targetsFile.createIfNotExists(createParents = true)
        targetsFile.overwrite(content)
      }
    }
  }

  override def thirdPartyReposFileContent(): String = contentIfExistsOf(root / thirdPartyReposFilePath).getOrElse("")

  override def buildFileContent(packageName: String): Option[String] = contentIfExistsOf(root / packageName / "BUILD.bazel")

  override def thirdPartyImportTargetsFileContent(thirdPartyGroup: String): Option[String] = contentIfExistsOf(root / thirdPartyImportFilesPathRoot / s"$thirdPartyGroup.bzl")

  override def allThirdPartyImportTargetsFilesContent(): Set[String] = {
    allThirdPartyImportTargetsFiles().values.toSet
  }

  override def allThirdPartyImportTargetsFiles(): Map[File, String] = {
    val thirdPartyLocation = root / thirdPartyImportFilesPathRoot
    thirdPartyLocation.createIfNotExists(asDirectory = true, createParents = true)
    val files = thirdPartyLocation.glob("**/*.bzl")
    val withNoCustomVersions = files.filterNot(f => f.path.startsWith(thirdPartyLocation + "/custom/"))
    withNoCustomVersions.map(f => f -> contentIfExistsOf(f).get) toMap
  }

  override def thirdPartyOverrides(): ThirdPartyOverrides = {
    contentIfExistsOf(root / ThirdPartyOverridesPath)
      .map(ThirdPartyOverridesReader.from)
      .getOrElse(ThirdPartyOverrides.empty)
  }

  private def contentIfExistsOf(filePath: File) =
    if (filePath.exists) Some(filePath.contentAsString) else None


  private def validate(): Unit = {
    if (!root.exists)
      throw new FileNotFoundException(root.pathAsString)
  }

} 
Example 63
Source File: HDFSMiniCluster.scala    From daf   with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
package it.teamdigitale.miniclusters

import better.files.File
import org.apache.logging.log4j.LogManager
import org.apache.hadoop.hdfs.HdfsConfiguration
import org.apache.hadoop.test.PathUtils
import org.apache.hadoop.fs.FileSystem
import org.apache.hadoop.hdfs.{HdfsConfiguration, MiniDFSCluster}
import better.files._

import scala.util.{Failure, Try}

class HDFSMiniCluster extends AutoCloseable {
  val alogger = LogManager.getLogger(this.getClass)

  var hdfsCluster: Try[MiniDFSCluster] = Failure[MiniDFSCluster](new Exception)
  var fileSystem: Try[FileSystem] = Failure[FileSystem](new Exception)

  val (testDataPath, confPath) = {
    val testDataPath = s"${PathUtils.getTestDir(classOf[HDFSMiniCluster]).getCanonicalPath}/MiniCluster"
    val confPath = s"$testDataPath/conf"
    (
      testDataPath.toFile.createIfNotExists(asDirectory = true, createParents = false),
      confPath.toFile.createIfNotExists(asDirectory = true, createParents = false)
    )
  }


  def start(): Unit = {

    alogger.info("Starting HDFS mini cluster")
    val conf = new HdfsConfiguration()
    conf.setBoolean("dfs.permissions", true)
    System.clearProperty(MiniDFSCluster.PROP_TEST_BUILD_DATA)

    conf.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, testDataPath.pathAsString)
    //FileUtil.fullyDelete(testDataPath.toJava)

    conf.set(s"hadoop.proxyuser.${System.getProperties.get("user.name")}.groups", "*")
    conf.set(s"hadoop.proxyuser.${System.getProperties.get("user.name")}.hosts", "*")

    val builder = new MiniDFSCluster.Builder(conf)
    hdfsCluster = Try(builder.build())
    fileSystem = hdfsCluster.map(_.getFileSystem)
    fileSystem.foreach(fs => {
      val confFile: File = confPath / "hdfs-site.xml"
      for {os <- confFile.newOutputStream.autoClosed} fs.getConf.writeXml(os)
    })

  }


  override def close() = {
    alogger.info("Stopping HDFS mini cluster")
    hdfsCluster.foreach(_.shutdown(true))
    val _ = testDataPath.parent.parent.delete(true)
  }
} 
Example 64
Source File: HDFSBase.scala    From daf   with BSD 3-Clause "New" or "Revised" License 5 votes vote down vote up
package daf.util

import better.files.{ File, _ }
import daf.util.DataFrameClasses.{ Address, Person }
import org.apache.hadoop.fs.FileSystem
import org.apache.hadoop.hdfs.{ HdfsConfiguration, MiniDFSCluster }
import org.apache.hadoop.test.PathUtils
import org.apache.spark.sql.{ SaveMode, SparkSession }
import org.scalatest.{ BeforeAndAfterAll, FlatSpec, Matchers }
import org.slf4j.LoggerFactory

import scala.util.{ Failure, Random, Try }

abstract class HDFSBase extends FlatSpec with Matchers with BeforeAndAfterAll {

  var miniCluster: Try[MiniDFSCluster] = Failure[MiniDFSCluster](new Exception)

  var fileSystem: Try[FileSystem] = Failure[FileSystem](new Exception)

  val sparkSession: SparkSession = SparkSession.builder().master("local").getOrCreate()

  val alogger = LoggerFactory.getLogger(this.getClass)

  val (testDataPath, confPath) = {
    val testDataPath = s"${PathUtils.getTestDir(this.getClass).getCanonicalPath}/MiniCluster"
    val confPath = s"$testDataPath/conf"
    (
      testDataPath.toFile.createIfNotExists(asDirectory = true, createParents = false),
      confPath.toFile.createIfNotExists(asDirectory = true, createParents = false)
    )
  }

  def pathAvro = "opendata/test.avro"
  def pathParquet = "opendata/test.parquet"
  def pathCsv = "opendata/test.csv"

  def getSparkSession = sparkSession

  override def beforeAll(): Unit = {

    val conf = new HdfsConfiguration()
    conf.setBoolean("dfs.permissions", true)
    System.clearProperty(MiniDFSCluster.PROP_TEST_BUILD_DATA)

    conf.set(MiniDFSCluster.HDFS_MINIDFS_BASEDIR, testDataPath.pathAsString)
    //FileUtil.fullyDelete(testDataPath.toJava)

    conf.set(s"hadoop.proxyuser.${System.getProperties.get("user.name")}.groups", "*")
    conf.set(s"hadoop.proxyuser.${System.getProperties.get("user.name")}.hosts", "*")

    val builder = new MiniDFSCluster.Builder(conf)
    miniCluster = Try(builder.build())
    fileSystem = miniCluster.map(_.getFileSystem)
    fileSystem.foreach(fs => {
      val confFile: File = confPath / "hdfs-site.xml"
      for { os <- confFile.newOutputStream.autoClosed } fs.getConf.writeXml(os)
    })

    writeDf()
  }

  override def afterAll(): Unit = {
    miniCluster.foreach(_.shutdown(true))
    val _ = testDataPath.parent.parent.delete(true)
    sparkSession.stop()
  }

  
  private def writeDf(): Unit = {
    import sparkSession.implicits._

    alogger.info(s"TestDataPath ${testDataPath.toJava.getAbsolutePath}")
    alogger.info(s"ConfPath ${confPath.toJava.getAbsolutePath}")
    val persons = (1 to 10).map(i => Person(s"Andy$i", Random.nextInt(85), Address("Via Ciccio Cappuccio")))
    val caseClassDS = persons.toDS()
    caseClassDS.write.format("parquet").mode(SaveMode.Overwrite).save(pathParquet)
    caseClassDS.write.format("com.databricks.spark.avro").mode(SaveMode.Overwrite).save(pathAvro)
    //writing directly the Person dataframe generates an exception
    caseClassDS.toDF.select("name", "age").write.format("csv").mode(SaveMode.Overwrite).option("header", "true").save(pathCsv)
  }
}

object DataFrameClasses {

  final case class Address(street: String)

  final case class Person(name: String, age: Int, address: Address)
} 
Example 65
Source File: NetworkBuilder.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.core.config

import java.net.InetSocketAddress
import java.nio.file.{Path, Paths}

import better.files.File
import cats.effect.IO
import cats.implicits._
import io.circe.syntax._
import jbok.common.config.Config
import jbok.core.keystore.KeyStorePlatform
import jbok.core.models.Address
import jbok.core.peer.PeerUri
import jbok.crypto.signature.KeyPair
import monocle.macros.syntax.lens._

import sys.process.{ProcessLogger, stringSeqToProcess}
import scala.concurrent.duration._

final case class NetworkBuilder(
    base: FullConfig,
    configs: List[FullConfig] = Nil,
) {
  val home = System.getProperty("user.home")
  val root = Paths.get(home).resolve(".jbok")

  def withBlockPeriod(n: Int): NetworkBuilder =
    copy(base = base.lens(_.mining.period).set(n.millis))

  def createCert(ip: String, cn: String, caDir: Path, certDir: Path): IO[String] = IO {
    val path = File(".")
    val projectDir = path.path.toAbsolutePath
    val processLogger = new ProcessLogger {
      override def out(s: => String): Unit = println(s)
      override def err(s: => String): Unit = println(s)
      override def buffer[T](f: => T): T = f
    }

    Seq("bash", "-c", s"${projectDir.resolve("bin/create-cert.sh")} ${ip} ${cn} ${projectDir.resolve("bin").toAbsolutePath} ${caDir.toAbsolutePath} ${certDir.toAbsolutePath}")
      .lineStream_!(processLogger)
      .mkString("\n")
  }

  def addNode(keyPair: KeyPair, coinbase: Address, rootPath: Path, host: String): NetworkBuilder = {
    val config = base
      .lens(_.rootPath).set(rootPath.toAbsolutePath.toString)
      .lens(_.peer.host).set(host)
      .lens(_.service.local).set(host)
      .lens(_.service.enableMetrics).set(true)
//      .lens(_.service.secure).set(true)
      .lens(_.mining.enabled).set(true)
      .lens(_.mining.address).set(Address(keyPair))
      .lens(_.mining.coinbase).set(coinbase)
//      .lens(_.ssl.enabled).set(true)
      .lens(_.ssl.trustStorePath).set(rootPath.resolve("cert/cacert.jks").toAbsolutePath.toString)
      .lens(_.ssl.keyStorePath).set(rootPath.resolve("cert/server.jks").toAbsolutePath.toString)
      .lens(_.persist.driver).set("rocksdb")
      .lens(_.persist.path).set(s"${rootPath.resolve("data").toAbsolutePath}")
      .lens(_.log.logDir).set(s"${rootPath.resolve("logs").toAbsolutePath}")
      .lens(_.keystore.dir).set(s"${rootPath.resolve("keystore").toAbsolutePath}")
      .lens(_.db.driver).set("org.sqlite.JDBC")
      .lens(_.db.url).set(s"jdbc:sqlite:${rootPath.resolve(s"service.db")}")

    val keystore = new KeyStorePlatform[IO](config.keystore)
    keystore.importPrivateKey(keyPair.secret.bytes, "changeit").unsafeRunSync()

    createCert(host, host, root.resolve("ca"), rootPath.resolve("cert")).unsafeRunSync()
    copy(configs = config :: configs)
  }

  def build: List[FullConfig] = {
    val reversed = configs.reverse
    val seeds = reversed.map(_.peer).map { peer =>
      PeerUri.fromTcpAddr(new InetSocketAddress(peer.host, peer.port)).uri
    }

    reversed.zipWithIndex.map { case (config, i) => config.lens(_.peer.seeds).set(seeds.take(i) ++ seeds.drop(i + 1)) }
  }

  def dump: IO[Unit] =
    build.traverse_(config => Config[IO].dump(config.asJson, Paths.get(config.rootPath).resolve(s"config.yaml")))
} 
Example 66
Source File: FileUtilSpec.scala    From iotchain   with MIT License 5 votes vote down vote up
package jbok.common

import better.files.File
import cats.effect.IO
import jbok.common.FileUtil.FileLockErr

class FileUtilSpec extends CommonSpec {
  "FileUtil" should {
    "release lock whatever use" in {
      val file = File.newTemporaryFile()
      val p = FileUtil[IO]
        .lock(file.path)
        .use { _ =>
          IO.raiseError(new Exception("boom"))
        }
        .attempt
      p.unsafeRunSync()
      file.exists shouldBe false
    }

    "raise FileLockErr if already locked" in {
      val file = File.newTemporaryFile()
      val p = FileUtil[IO]
        .lock(file.path)
        .use { _ =>
          FileUtil[IO]
            .lock(file.path)
            .use { _ =>
              IO.unit
            }
            .attempt
            .map(x => x.left.get shouldBe FileLockErr(file.path))
        }
        .attempt
      p.unsafeRunSync().isRight shouldBe true
      file.exists shouldBe false
    }

    "lock with content" in {
      val file = File.newTemporaryFile()
      val p = FileUtil[IO]
        .lock(file.path, "oho")
        .use { _ =>
          IO(println(file.lines.head)).flatMap(_ => IO.raiseError(new Exception("boom")))
        }
        .attempt
      p.unsafeRunSync()
      file.exists shouldBe false
    }
  }
} 
Example 67
Source File: MavenAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.buildtool.maven

import better.files.File
import cats.Monad
import cats.implicits._
import org.scalasteward.core.application.Config
import org.scalasteward.core.buildtool.BuildToolAlg
import org.scalasteward.core.data._
import org.scalasteward.core.io.{FileAlg, ProcessAlg, WorkspaceAlg}
import org.scalasteward.core.scalafix.Migration
import org.scalasteward.core.util.Nel
import org.scalasteward.core.vcs.data.Repo

trait MavenAlg[F[_]] extends BuildToolAlg[F]

object MavenAlg {
  def create[F[_]](implicit
      config: Config,
      fileAlg: FileAlg[F],
      processAlg: ProcessAlg[F],
      workspaceAlg: WorkspaceAlg[F],
      F: Monad[F]
  ): MavenAlg[F] =
    new MavenAlg[F] {
      override def containsBuild(repo: Repo): F[Boolean] =
        workspaceAlg.repoDir(repo).flatMap(repoDir => fileAlg.isRegularFile(repoDir / "pom.xml"))

      override def getDependencies(repo: Repo): F[List[Scope.Dependencies]] =
        for {
          repoDir <- workspaceAlg.repoDir(repo)
          dependenciesRaw <- exec(mvnCmd(command.listDependencies), repoDir)
          repositoriesRaw <- exec(mvnCmd(command.listRepositories), repoDir)
          dependencies = parser.parseDependencies(dependenciesRaw).distinct
          resolvers = parser.parseResolvers(repositoriesRaw).distinct
        } yield List(Scope(dependencies, resolvers))

      override def runMigrations(repo: Repo, migrations: Nel[Migration]): F[Unit] =
        F.unit

      def exec(command: Nel[String], repoDir: File): F[List[String]] =
        maybeIgnoreOptsFiles(repoDir)(processAlg.execSandboxed(command, repoDir))

      def mvnCmd(commands: String*): Nel[String] =
        Nel("mvn", "--batch-mode" :: commands.toList)

      def maybeIgnoreOptsFiles[A](dir: File)(fa: F[A]): F[A] =
        if (config.ignoreOptsFiles) ignoreOptsFiles(dir)(fa) else fa

      def ignoreOptsFiles[A](dir: File)(fa: F[A]): F[A] =
        fileAlg.removeTemporarily(dir / ".jvmopts")(fa)
    }
} 
Example 68
Source File: ProcessAlgTest.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.io

import better.files.File
import cats.effect.{Blocker, IO}
import java.util.concurrent.Executors
import org.scalasteward.core.TestInstances._
import org.scalasteward.core.io.ProcessAlgTest.ioProcessAlg
import org.scalasteward.core.mock.MockContext._
import org.scalasteward.core.mock.MockState
import org.scalasteward.core.util.Nel
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

class ProcessAlgTest extends AnyFunSuite with Matchers {
  test("exec echo") {
    ioProcessAlg
      .exec(Nel.of("echo", "-n", "hello"), File.currentWorkingDirectory)
      .unsafeRunSync() shouldBe List("hello")
  }

  test("exec false") {
    ioProcessAlg
      .exec(Nel.of("ls", "--foo"), File.currentWorkingDirectory)
      .attempt
      .map(_.isLeft)
      .unsafeRunSync()
  }

  test("respect the disableSandbox setting") {
    val cfg = config.copy(disableSandbox = true)
    val processAlg = new MockProcessAlg()(cfg)

    val state = processAlg
      .execSandboxed(Nel.of("echo", "hello"), File.temp)
      .runS(MockState.empty)
      .unsafeRunSync()

    state shouldBe MockState.empty.copy(
      commands = Vector(
        List("TEST_VAR=GREAT", "ANOTHER_TEST_VAR=ALSO_GREAT", File.temp.toString, "echo", "hello")
      )
    )
  }

  test("execSandboxed echo") {
    val state = processAlg
      .execSandboxed(Nel.of("echo", "hello"), File.temp)
      .runS(MockState.empty)
      .unsafeRunSync()

    state shouldBe MockState.empty.copy(
      commands = Vector(
        List(
          "TEST_VAR=GREAT",
          "ANOTHER_TEST_VAR=ALSO_GREAT",
          File.temp.toString,
          "firejail",
          s"--whitelist=${File.temp}",
          "echo",
          "hello"
        )
      )
    )
  }
}

object ProcessAlgTest {
  val blocker: Blocker = Blocker.liftExecutorService(Executors.newCachedThreadPool())
  implicit val ioProcessAlg: ProcessAlg[IO] = ProcessAlg.create[IO](blocker)
} 
Example 69
Source File: MockFileAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.io

import better.files.File
import cats.data.StateT
import cats.effect.IO
import fs2.Stream
import org.scalasteward.core.mock.{applyPure, MockEff, MockState}

class MockFileAlg extends FileAlg[MockEff] {
  override def createTemporarily[A](file: File, content: String)(fa: MockEff[A]): MockEff[A] =
    for {
      _ <- StateT.modify[IO, MockState](_.exec(List("create", file.pathAsString)))
      a <- fa
      _ <- StateT.modify[IO, MockState](_.exec(List("rm", file.pathAsString)))
    } yield a

  override def deleteForce(file: File): MockEff[Unit] =
    StateT.modify(_.exec(List("rm", "-rf", file.pathAsString)).rm(file))

  override def ensureExists(dir: File): MockEff[File] =
    applyPure(s => (s.exec(List("mkdir", "-p", dir.pathAsString)), dir))

  override def home: MockEff[File] =
    StateT.pure(File.root / "tmp" / "steward")

  override def isDirectory(file: File): MockEff[Boolean] =
    StateT.pure(false)

  override def isRegularFile(file: File): MockEff[Boolean] =
    for {
      _ <- StateT.modify[IO, MockState](_.exec(List("test", "-f", file.pathAsString)))
      s <- StateT.get[IO, MockState]
      exists = s.files.contains(file)
    } yield exists

  override def removeTemporarily[A](file: File)(fa: MockEff[A]): MockEff[A] =
    for {
      _ <- StateT.modify[IO, MockState](_.exec(List("rm", file.pathAsString)))
      a <- fa
      _ <- StateT.modify[IO, MockState](_.exec(List("restore", file.pathAsString)))
    } yield a

  override def readFile(file: File): MockEff[Option[String]] =
    applyPure(s => (s.exec(List("read", file.pathAsString)), s.files.get(file)))

  override def readResource(resource: String): MockEff[String] =
    for {
      _ <- StateT.modify[IO, MockState](_.exec(List("read", s"classpath:$resource")))
      content <- StateT.liftF(FileAlgTest.ioFileAlg.readResource(resource))
    } yield content

  override def walk(dir: File): Stream[MockEff, File] = {
    val dirAsString = dir.pathAsString
    val state: MockEff[List[File]] = StateT.inspect {
      _.files.keys.filter(_.pathAsString.startsWith(dirAsString)).toList
    }
    Stream.eval(state).flatMap(Stream.emits[MockEff, File])
  }

  override def writeFile(file: File, content: String): MockEff[Unit] =
    StateT.modify(_.exec(List("write", file.pathAsString)).add(file, content))
} 
Example 70
Source File: MigrationAlgTest.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.scalafix

import better.files.File
import org.scalasteward.core.data.{GroupId, Version}
import org.scalasteward.core.mock.MockContext._
import org.scalasteward.core.mock.{MockEff, MockState}
import org.scalasteward.core.util.Nel
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

class MigrationAlgTest extends AnyFunSuite with Matchers {
  val extraFile: File = config.workspace / "extra-migrations.conf"

  test("loadMigrations with extra file") {
    val content =
      """|migrations = [
         |  {
         |    groupId: "org.ice.cream",
         |    artifactIds: ["yumyum-.*"],
         |    newVersion: "1.0.0",
         |    rewriteRules: ["awesome rewrite rule"],
         |    doc: "https://scalacenter.github.io/scalafix/"
         |  }
         |]""".stripMargin
    val initialState = MockState.empty.add(extraFile, content)
    val migrations =
      MigrationAlg.loadMigrations[MockEff](Some(extraFile)).runA(initialState).unsafeRunSync

    migrations.size should be > 1
    (migrations should contain).oneElementOf(
      List(
        Migration(
          GroupId("org.ice.cream"),
          Nel.of("yumyum-.*"),
          Version("1.0.0"),
          Nel.of("awesome rewrite rule"),
          Some("https://scalacenter.github.io/scalafix/")
        )
      )
    )
  }

  test("loadMigrations with extra file and disableDefaults = true") {
    val content =
      """|disableDefaults = true
         |migrations = [
         |  {
         |    groupId: "org.ice.cream",
         |    artifactIds: ["yumyum-.*"],
         |    newVersion: "1.0.0",
         |    rewriteRules: ["awesome rewrite rule"]
         |  }
         |]""".stripMargin
    val initialState = MockState.empty.add(extraFile, content)
    val migrations =
      MigrationAlg.loadMigrations[MockEff](Some(extraFile)).runA(initialState).unsafeRunSync

    migrations shouldBe List(
      Migration(
        GroupId("org.ice.cream"),
        Nel.of("yumyum-.*"),
        Version("1.0.0"),
        Nel.of("awesome rewrite rule"),
        None
      )
    )
  }

  test("loadMigrations with extra file and disableDefaults = true only") {
    val initialState = MockState.empty.add(extraFile, "disableDefaults = true")
    val migrations =
      MigrationAlg.loadMigrations[MockEff](Some(extraFile)).runA(initialState).unsafeRunSync
    migrations.isEmpty shouldBe true
  }

  test("loadMigrations with malformed extra file") {
    val initialState = MockState.empty.add(extraFile, """{"key": "i'm not a valid Migration}""")
    val migrations =
      MigrationAlg.loadMigrations[MockEff](Some(extraFile)).runA(initialState).attempt.unsafeRunSync
    migrations.isLeft shouldBe true
  }

  test("loadMigrations without extra file") {
    val migrations =
      MigrationAlg.loadMigrations[MockEff](None).runA(MockState.empty).unsafeRunSync()
    migrations.size shouldBe 13
  }
} 
Example 71
Source File: MavenAlgTest.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.buildtool.maven

import better.files.File
import org.scalasteward.core.mock.MockContext._
import org.scalasteward.core.mock.MockState
import org.scalasteward.core.vcs.data.Repo
import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

class MavenAlgTest extends AnyFunSuite with Matchers {
  val var1 = "TEST_VAR=GREAT"
  val var2 = "ANOTHER_TEST_VAR=ALSO_GREAT"

  test("getDependencies") {
    val repo = Repo("namespace", "repo-name")
    val repoDir = config.workspace / repo.show
    val files: Map[File, String] = Map.empty

    val state =
      mavenAlg.getDependencies(repo).runS(MockState.empty.copy(files = files)).unsafeRunSync()

    state shouldBe MockState(
      files = files,
      logs = Vector.empty,
      commands = Vector(
        List(
          var1,
          var2,
          repoDir.toString,
          "firejail",
          s"--whitelist=$repoDir",
          "mvn",
          "--batch-mode",
          command.listDependencies
        ),
        List(
          var1,
          var2,
          repoDir.toString,
          "firejail",
          s"--whitelist=$repoDir",
          "mvn",
          "--batch-mode",
          command.listRepositories
        )
      )
    )
  }
} 
Example 72
Source File: MockContext.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.mock

import better.files.File
import cats.Parallel
import cats.effect.Sync
import org.http4s.Uri
import org.scalasteward.core.TestInstances.ioContextShift
import org.scalasteward.core.application.Cli.EnvVar
import org.scalasteward.core.application.{Config, SupportedVCS}
import org.scalasteward.core.buildtool.BuildToolDispatcher
import org.scalasteward.core.buildtool.maven.MavenAlg
import org.scalasteward.core.buildtool.mill.MillAlg
import org.scalasteward.core.buildtool.sbt.SbtAlg
import org.scalasteward.core.coursier.{CoursierAlg, VersionsCache}
import org.scalasteward.core.edit.EditAlg
import org.scalasteward.core.git.{Author, GitAlg}
import org.scalasteward.core.io.{MockFileAlg, MockProcessAlg, MockWorkspaceAlg}
import org.scalasteward.core.nurture.PullRequestRepository
import org.scalasteward.core.persistence.JsonKeyValueStore
import org.scalasteward.core.repocache.RepoCacheRepository
import org.scalasteward.core.repoconfig.RepoConfigAlg
import org.scalasteward.core.scalafix.MigrationAlg
import org.scalasteward.core.scalafmt.ScalafmtAlg
import org.scalasteward.core.update.{FilterAlg, GroupMigrations, PruningAlg, UpdateAlg}
import org.scalasteward.core.util.uri._
import org.scalasteward.core.util.{BracketThrowable, DateTimeAlg}
import org.scalasteward.core.vcs.VCSRepoAlg
import org.scalasteward.core.vcs.data.AuthenticatedUser

import scala.concurrent.duration._

object MockContext {
  implicit val config: Config = Config(
    workspace = File.temp / "ws",
    reposFile = File.temp / "repos.md",
    defaultRepoConfigFile = Some(File.temp / "default.scala-steward.conf"),
    gitAuthor = Author("Bot Doe", "[email protected]"),
    vcsType = SupportedVCS.GitHub,
    vcsApiHost = Uri(),
    vcsLogin = "bot-doe",
    gitAskPass = File.temp / "askpass.sh",
    signCommits = false,
    whitelistedDirectories = Nil,
    readOnlyDirectories = Nil,
    disableSandbox = false,
    doNotFork = false,
    ignoreOptsFiles = false,
    envVars = List(
      EnvVar("TEST_VAR", "GREAT"),
      EnvVar("ANOTHER_TEST_VAR", "ALSO_GREAT")
    ),
    processTimeout = 10.minutes,
    scalafixMigrations = None,
    groupMigrations = None,
    cacheTtl = 1.hour,
    cacheMissDelay = 0.milliseconds,
    bitbucketServerUseDefaultReviewers = false
  )

  implicit val mockEffBracketThrowable: BracketThrowable[MockEff] = Sync[MockEff]
  implicit val mockEffParallel: Parallel[MockEff] = Parallel.identity

  implicit val fileAlg: MockFileAlg = new MockFileAlg
  implicit val mockLogger: MockLogger = new MockLogger
  implicit val processAlg: MockProcessAlg = new MockProcessAlg
  implicit val workspaceAlg: MockWorkspaceAlg = new MockWorkspaceAlg

  implicit val coursierAlg: CoursierAlg[MockEff] = CoursierAlg.create
  implicit val dateTimeAlg: DateTimeAlg[MockEff] = DateTimeAlg.create
  implicit val gitAlg: GitAlg[MockEff] = GitAlg.create
  implicit val user: AuthenticatedUser = AuthenticatedUser("scala-steward", "token")
  implicit val vcsRepoAlg: VCSRepoAlg[MockEff] = VCSRepoAlg.create(config, gitAlg)
  implicit val scalafmtAlg: ScalafmtAlg[MockEff] = ScalafmtAlg.create
  implicit val migrationAlg: MigrationAlg =
    MigrationAlg.create[MockEff](config.scalafixMigrations).runA(MockState.empty).unsafeRunSync()
  implicit val cacheRepository: RepoCacheRepository[MockEff] =
    new RepoCacheRepository[MockEff](new JsonKeyValueStore("repo_cache", "1"))
  implicit val filterAlg: FilterAlg[MockEff] = new FilterAlg[MockEff]
  implicit val versionsCache: VersionsCache[MockEff] =
    new VersionsCache[MockEff](config.cacheTtl, new JsonKeyValueStore("versions", "1"))
  implicit val groupMigrations: GroupMigrations =
    GroupMigrations.create[MockEff].runA(MockState.empty).unsafeRunSync()
  implicit val updateAlg: UpdateAlg[MockEff] = new UpdateAlg[MockEff]
  implicit val mavenAlg: MavenAlg[MockEff] = MavenAlg.create
  implicit val sbtAlg: SbtAlg[MockEff] = SbtAlg.create
  implicit val millAlg: MillAlg[MockEff] = MillAlg.create
  implicit val buildToolDispatcher: BuildToolDispatcher[MockEff] = BuildToolDispatcher.create
  implicit val editAlg: EditAlg[MockEff] = new EditAlg[MockEff]
  implicit val repoConfigAlg: RepoConfigAlg[MockEff] = new RepoConfigAlg[MockEff]
  implicit val pullRequestRepository: PullRequestRepository[MockEff] =
    new PullRequestRepository[MockEff](new JsonKeyValueStore("pull_requests", "1"))
  implicit val pruningAlg: PruningAlg[MockEff] = new PruningAlg[MockEff]
} 
Example 73
Source File: MockState.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.mock

import better.files.File

final case class MockState(
    commands: Vector[List[String]],
    logs: Vector[(Option[Throwable], String)],
    files: Map[File, String]
) {
  def add(file: File, content: String): MockState =
    copy(files = files + (file -> content))

  def addFiles(newFiles: Map[File, String]): MockState =
    copy(files = files ++ newFiles)

  def rm(file: File): MockState =
    copy(files = files - file)

  def exec(cmd: List[String], env: (String, String)*): MockState =
    copy(commands = commands :+ (env.map { case (k, v) => s"$k=$v" }.toList ++ cmd))

  def log(maybeThrowable: Option[Throwable], msg: String): MockState =
    copy(logs = logs :+ ((maybeThrowable, msg)))
}

object MockState {
  def empty: MockState =
    MockState(commands = Vector.empty, logs = Vector.empty, files = Map.empty)
} 
Example 74
Source File: package.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core

import better.files.File
import cats.implicits._
import org.scalasteward.core.data.{GroupId, Update}

package object io {
  def isSourceFile(update: Update, fileExtensions: Set[String])(file: File): Boolean = {
    val notInGitDir = !file.pathAsString.contains(".git/")
    notInGitDir && isSpecificOrGenericSourceFile(update, fileExtensions)(file)
  }

  private def isSpecificOrGenericSourceFile(update: Update, fileExtensions: Set[String])(
      file: File
  ): Boolean =
    () match {
      case _ if isSbtUpdate(update)          => file.name === "build.properties"
      case _ if isScalafmtCoreUpdate(update) => file.name === ".scalafmt.conf"
      case _                                 => isGenericSourceFile(file, fileExtensions)
    }

  private def isGenericSourceFile(file: File, fileExtensions: Set[String]): Boolean =
    fileExtensions.exists(file.name.endsWith)

  private def isSbtUpdate(update: Update): Boolean =
    update.groupId === GroupId("org.scala-sbt") &&
      update.artifactIds.exists(_.name === "sbt")

  private def isScalafmtCoreUpdate(update: Update): Boolean =
    update.groupId === GroupId("org.scalameta") &&
      update.artifactIds.exists(_.name === "scalafmt-core")
} 
Example 75
Source File: ProcessAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.io

import better.files.File
import cats.effect.{Blocker, Concurrent, ContextShift, Timer}
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.application.Cli.EnvVar
import org.scalasteward.core.application.Config
import org.scalasteward.core.util.Nel

trait ProcessAlg[F[_]] {
  def exec(command: Nel[String], cwd: File, extraEnv: (String, String)*): F[List[String]]

  def execSandboxed(command: Nel[String], cwd: File): F[List[String]]
}

object ProcessAlg {
  abstract class UsingFirejail[F[_]](config: Config) extends ProcessAlg[F] {
    override def execSandboxed(command: Nel[String], cwd: File): F[List[String]] = {
      val envVars = config.envVars.map(EnvVar.unapply(_).get)
      if (config.disableSandbox)
        exec(command, cwd, envVars: _*)
      else {
        val whitelisted = (cwd.pathAsString :: config.whitelistedDirectories)
          .map(dir => s"--whitelist=$dir")
        val readOnly = config.readOnlyDirectories
          .map(dir => s"--read-only=$dir")
        exec(Nel("firejail", whitelisted ++ readOnly) ::: command, cwd, envVars: _*)
      }
    }
  }

  def create[F[_]](blocker: Blocker)(implicit
      config: Config,
      contextShift: ContextShift[F],
      logger: Logger[F],
      timer: Timer[F],
      F: Concurrent[F]
  ): ProcessAlg[F] =
    new UsingFirejail[F](config) {
      override def exec(
          command: Nel[String],
          cwd: File,
          extraEnv: (String, String)*
      ): F[List[String]] =
        logger.debug(s"Execute ${command.mkString_(" ")}") >>
          process.slurp[F](
            command,
            Some(cwd.toJava),
            extraEnv.toMap,
            config.processTimeout,
            logger.trace(_),
            blocker
          )
    }
} 
Example 76
Source File: WorkspaceAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.io

import better.files.File
import cats.FlatMap
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.application.Config
import org.scalasteward.core.vcs.data.Repo

trait WorkspaceAlg[F[_]] {
  def cleanWorkspace: F[Unit]

  def rootDir: F[File]

  def repoDir(repo: Repo): F[File]
}

object WorkspaceAlg {
  def create[F[_]](implicit
      fileAlg: FileAlg[F],
      logger: Logger[F],
      config: Config,
      F: FlatMap[F]
  ): WorkspaceAlg[F] =
    new WorkspaceAlg[F] {
      private[this] val reposDir = config.workspace / "repos"

      override def cleanWorkspace: F[Unit] =
        for {
          _ <- logger.info(s"Clean workspace ${config.workspace}")
          _ <- fileAlg.deleteForce(reposDir)
          _ <- rootDir
        } yield ()

      override def rootDir: F[File] =
        fileAlg.ensureExists(config.workspace)

      override def repoDir(repo: Repo): F[File] =
        fileAlg.ensureExists(reposDir / repo.owner / repo.repo)
    }
} 
Example 77
Source File: MigrationAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.scalafix

import better.files.File
import cats.data.OptionT
import cats.effect.Sync
import cats.implicits._
import io.circe.config.parser.decode
import org.scalasteward.core.data.{Update, Version}
import org.scalasteward.core.io.FileAlg
import org.scalasteward.core.util.{ApplicativeThrowable, MonadThrowable}

trait MigrationAlg {
  def findMigrations(update: Update): List[Migration]
}

object MigrationAlg {
  def create[F[_]](extraMigrations: Option[File])(implicit
      fileAlg: FileAlg[F],
      F: Sync[F]
  ): F[MigrationAlg] =
    loadMigrations(extraMigrations).map { migrations =>
      new MigrationAlg {
        override def findMigrations(update: Update): List[Migration] =
          findMigrationsImpl(migrations, update)
      }
    }

  def loadMigrations[F[_]](
      extraMigrations: Option[File]
  )(implicit fileAlg: FileAlg[F], F: MonadThrowable[F]): F[List[Migration]] =
    for {
      default <-
        fileAlg
          .readResource("scalafix-migrations.conf")
          .flatMap(decodeMigrations[F](_, "default"))
      maybeExtra <- OptionT(extraMigrations.flatTraverse(fileAlg.readFile))
        .semiflatMap(decodeMigrations[F](_, "extra"))
        .value
      migrations = maybeExtra match {
        case Some(extra) if extra.disableDefaults => extra.migrations
        case Some(extra)                          => default.migrations ++ extra.migrations
        case None                                 => default.migrations
      }
    } yield migrations

  private def decodeMigrations[F[_]](content: String, tpe: String)(implicit
      F: ApplicativeThrowable[F]
  ): F[ScalafixMigrations] =
    F.fromEither(decode[ScalafixMigrations](content))
      .adaptErr(new Throwable(s"Failed to load $tpe Scalafix migrations", _))

  private def findMigrationsImpl(
      givenMigrations: List[Migration],
      update: Update
  ): List[Migration] =
    givenMigrations.filter { migration =>
      update.groupId === migration.groupId &&
      migration.artifactIds.exists(re =>
        update.artifactIds.exists(artifactId => re.r.findFirstIn(artifactId.name).isDefined)
      ) &&
      Version(update.currentVersion) < migration.newVersion &&
      Version(update.newerVersions.head) >= migration.newVersion
    }
} 
Example 78
Source File: JsonKeyValueStore.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.persistence

import better.files.File
import cats.Monad
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import io.circe.parser.decode
import io.circe.syntax._
import io.circe.{Decoder, Encoder, KeyEncoder}
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}

final class JsonKeyValueStore[F[_], K, V](
    name: String,
    schemaVersion: String,
    maybePrefix: Option[String] = None
)(implicit
    fileAlg: FileAlg[F],
    keyEncoder: KeyEncoder[K],
    logger: Logger[F],
    valueDecoder: Decoder[V],
    valueEncoder: Encoder[V],
    workspaceAlg: WorkspaceAlg[F],
    F: Monad[F]
) extends KeyValueStore[F, K, V] {
  override def get(key: K): F[Option[V]] =
    jsonFile(key).flatMap { file =>
      fileAlg.readFile(file).flatMap {
        case Some(content) =>
          decode[Option[V]](content) match {
            case Right(maybeValue) => F.pure(maybeValue)
            case Left(error) =>
              logger.error(error)(s"Failed to parse or decode JSON from $file").as(Option.empty[V])
          }
        case None => F.pure(Option.empty[V])
      }
    }

  override def put(key: K, value: V): F[Unit] =
    write(key, Some(value))

  override def modifyF(key: K)(f: Option[V] => F[Option[V]]): F[Option[V]] =
    get(key).flatMap(maybeValue => f(maybeValue).flatTap(write(key, _)))

  private def jsonFile(key: K): F[File] = {
    val keyPath = maybePrefix.fold("")(_ + "/") + keyEncoder(key)
    workspaceAlg.rootDir.map(_ / "store" / name / s"v$schemaVersion" / keyPath / s"$name.json")
  }

  private def write(key: K, value: Option[V]): F[Unit] =
    jsonFile(key).flatMap(fileAlg.writeFile(_, value.asJson.toString))
} 
Example 79
Source File: RepoConfigAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.repoconfig

import better.files.File
import cats.data.OptionT
import cats.implicits._
import io.chrisdavenport.log4cats.Logger
import io.circe.config.parser
import org.scalasteward.core.application.Config
import org.scalasteward.core.data.Update
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
import org.scalasteward.core.repoconfig.RepoConfigAlg._
import org.scalasteward.core.util.MonadThrowable
import org.scalasteward.core.vcs.data.Repo

final class RepoConfigAlg[F[_]](implicit
    config: Config,
    fileAlg: FileAlg[F],
    logger: Logger[F],
    workspaceAlg: WorkspaceAlg[F],
    F: MonadThrowable[F]
) {
  def readRepoConfigOrDefault(repo: Repo): F[RepoConfig] =
    readRepoConfig(repo).flatMap { config =>
      config.map(F.pure).getOrElse(defaultRepoConfig)
    }

  
  val defaultRepoConfig: F[RepoConfig] =
    OptionT
      .fromOption[F](config.defaultRepoConfigFile)
      .flatMap(readRepoConfigFromFile)
      .getOrElse(RepoConfig.empty)

  def readRepoConfig(repo: Repo): F[Option[RepoConfig]] =
    workspaceAlg
      .repoDir(repo)
      .flatMap(dir => readRepoConfigFromFile(dir / repoConfigBasename).value)

  private def readRepoConfigFromFile(configFile: File): OptionT[F, RepoConfig] =
    OptionT(fileAlg.readFile(configFile)).map(parseRepoConfig).flatMapF {
      case Right(repoConfig) => logger.info(s"Parsed $repoConfig").as(repoConfig.some)
      case Left(errorMsg)    => logger.info(errorMsg).as(none[RepoConfig])
    }
}

object RepoConfigAlg {
  val repoConfigBasename: String = ".scala-steward.conf"

  def parseRepoConfig(input: String): Either[String, RepoConfig] =
    parser.decode[RepoConfig](input).leftMap { error =>
      s"Failed to parse $repoConfigBasename: ${error.getMessage}"
    }

  def configToIgnoreFurtherUpdates(update: Update): String =
    update match {
      case s: Update.Single =>
        s"""updates.ignore = [ { groupId = "${s.groupId}", artifactId = "${s.artifactId.name}" } ]"""
      case g: Update.Group =>
        s"""updates.ignore = [ { groupId = "${g.groupId}" } ]"""
    }
} 
Example 80
Source File: StewardAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.application

import better.files.File
import cats.Monad
import cats.effect.ExitCode
import cats.implicits._
import fs2.Stream
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.buildtool.sbt.SbtAlg
import org.scalasteward.core.git.GitAlg
import org.scalasteward.core.io.{FileAlg, WorkspaceAlg}
import org.scalasteward.core.nurture.NurtureAlg
import org.scalasteward.core.repocache.RepoCacheAlg
import org.scalasteward.core.update.PruningAlg
import org.scalasteward.core.util
import org.scalasteward.core.util.DateTimeAlg
import org.scalasteward.core.util.logger.LoggerOps
import org.scalasteward.core.vcs.data.Repo

final class StewardAlg[F[_]](implicit
    config: Config,
    dateTimeAlg: DateTimeAlg[F],
    fileAlg: FileAlg[F],
    gitAlg: GitAlg[F],
    logger: Logger[F],
    nurtureAlg: NurtureAlg[F],
    pruningAlg: PruningAlg[F],
    repoCacheAlg: RepoCacheAlg[F],
    sbtAlg: SbtAlg[F],
    selfCheckAlg: SelfCheckAlg[F],
    streamCompiler: Stream.Compiler[F, F],
    workspaceAlg: WorkspaceAlg[F],
    F: Monad[F]
) {
  private def printBanner: F[Unit] = {
    val banner =
      """|  ____            _         ____  _                             _
         | / ___|  ___ __ _| | __ _  / ___|| |_ _____      ____ _ _ __ __| |
         | \___ \ / __/ _` | |/ _` | \___ \| __/ _ \ \ /\ / / _` | '__/ _` |
         |  ___) | (_| (_| | | (_| |  ___) | ||  __/\ V  V / (_| | | | (_| |
         | |____/ \___\__,_|_|\__,_| |____/ \__\___| \_/\_/ \__,_|_|  \__,_|""".stripMargin
    val msg = List(" ", banner, s" v${org.scalasteward.core.BuildInfo.version}", " ")
      .mkString(System.lineSeparator())
    logger.info(msg)
  }

  private def readRepos(reposFile: File): F[List[Repo]] =
    fileAlg.readFile(reposFile).map { maybeContent =>
      val regex = """-\s+(.+)/([^/]+)""".r
      val content = maybeContent.getOrElse("")
      content.linesIterator.collect {
        case regex(owner, repo) => Repo(owner.trim, repo.trim)
      }.toList
    }

  private def steward(repo: Repo): F[Either[Throwable, Unit]] = {
    val label = s"Steward ${repo.show}"
    logger.infoTotalTime(label) {
      for {
        _ <- logger.info(util.string.lineLeftRight(label))
        _ <- repoCacheAlg.checkCache(repo)
        (attentionNeeded, updates) <- pruningAlg.needsAttention(repo)
        result <- {
          if (attentionNeeded) nurtureAlg.nurture(repo, updates)
          else gitAlg.removeClone(repo).as(().asRight[Throwable])
        }
      } yield result
    }
  }

  def runF: F[ExitCode] =
    logger.infoTotalTime("run") {
      for {
        _ <- printBanner
        _ <- selfCheckAlg.checkAll
        exitCode <- sbtAlg.addGlobalPlugins {
          for {
            _ <- workspaceAlg.cleanWorkspace
            repos <- readRepos(config.reposFile)
            result <- Stream.emits(repos).evalMap(steward).compile.foldMonoid
          } yield result.fold(_ => ExitCode.Error, _ => ExitCode.Success)
        }
      } yield exitCode
    }
} 
Example 81
Source File: EditAlg.scala    From scala-steward   with Apache License 2.0 5 votes vote down vote up
package org.scalasteward.core.edit

import better.files.File
import cats.Traverse
import cats.implicits._
import fs2.Stream
import io.chrisdavenport.log4cats.Logger
import org.scalasteward.core.buildtool.BuildToolDispatcher
import org.scalasteward.core.data.Update
import org.scalasteward.core.io.{isSourceFile, FileAlg, WorkspaceAlg}
import org.scalasteward.core.scalafix.MigrationAlg
import org.scalasteward.core.util._
import org.scalasteward.core.vcs.data.Repo

final class EditAlg[F[_]](implicit
    buildToolDispatcher: BuildToolDispatcher[F],
    fileAlg: FileAlg[F],
    logger: Logger[F],
    migrationAlg: MigrationAlg,
    streamCompiler: Stream.Compiler[F, F],
    workspaceAlg: WorkspaceAlg[F],
    F: MonadThrowable[F]
) {
  def applyUpdate(repo: Repo, update: Update, fileExtensions: Set[String]): F[Unit] =
    for {
      _ <- applyScalafixMigrations(repo, update).handleErrorWith(e =>
        logger.warn(s"Could not apply ${update.show} : $e")
      )
      repoDir <- workspaceAlg.repoDir(repo)
      files <- fileAlg.findFilesContaining(
        repoDir,
        update.currentVersion,
        isSourceFile(update, fileExtensions)
      )
      noFilesFound = logger.warn("No files found that contain the current version")
      _ <- files.toNel.fold(noFilesFound)(applyUpdateTo(_, update))
    } yield ()

  def applyUpdateTo[G[_]: Traverse](files: G[File], update: Update): F[Unit] = {
    val actions = UpdateHeuristic.all.map { heuristic =>
      logger.info(s"Trying heuristic '${heuristic.name}'") >>
        fileAlg.editFiles(files, heuristic.replaceVersion(update))
    }
    bindUntilTrue(actions).void
  }

  def applyScalafixMigrations(repo: Repo, update: Update): F[Unit] =
    Nel.fromList(migrationAlg.findMigrations(update)).traverse_ { migrations =>
      logger.info(s"Applying migrations: $migrations") >>
        buildToolDispatcher.runMigrations(repo, migrations)
    }
} 
Example 82
Source File: FallbackFileCollectorSpec.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.files

import better.files.File
import cats.instances.try_.catsStdInstancesForTry
import org.specs2.control.NoLanguageFeatures
import org.specs2.mutable.Specification

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

class FallbackFileCollectorSpec extends Specification with NoLanguageFeatures {

  private val failingCompanion: FileCollectorCompanion[Try] = new FileCollectorCompanion[Try] {
    override def name: String = ""

    override def apply(): FileCollector[Try] =
      new FileCollector[Try] {

        override def list(directory: File): Try[FilesTarget] = {
          Failure(new Exception("because fail"))
        }
      }
  }

  private val successfulCompanion: FileCollectorCompanion[Try] = new FileCollectorCompanion[Try] {
    override def name: String = ""

    override def apply(): FileCollector[Try] =
      new FileCollector[Try] {

        override def list(directory: File): Try[FilesTarget] = {
          Success(FilesTarget(directory, Set.empty, Set.empty))
        }
      }
  }

  "FallbackFileCollectorSpec" should {
    "not fallback" in {
      new FallbackFileCollector(List(successfulCompanion, failingCompanion)).list(File("")) must beSuccessfulTry
    }

    "fallback" in {
      new FallbackFileCollector(List(failingCompanion, successfulCompanion)).list(File("")) must beSuccessfulTry
    }

    "fail when all fail" in {
      new FallbackFileCollector(List(failingCompanion, failingCompanion)).list(File("")) must beFailedTry
    }
  }
} 
Example 83
Source File: LanguagesHelperSpec.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.utils

import better.files.File
import com.codacy.analysis.core.files.FilesTarget
import com.codacy.plugins.api.languages.Languages
import org.specs2.control.NoLanguageFeatures
import org.specs2.mutable.Specification

class LanguagesHelperSpec extends Specification with NoLanguageFeatures {

  "LanguagesHelper" should {
    "detect the languages from a given set of files" in {

      val filesTarget =
        FilesTarget(File(""), Set(File("test.js").path, File("Test.java").path, File("SomeClazz.rb").path), Set.empty)

      val languages = LanguagesHelper.fromFileTarget(filesTarget, Map.empty)

      languages should containTheSameElementsAs(Seq(Languages.Java, Languages.Ruby, Languages.Javascript))
    }

    "detect the languages from a given set of files, considering custom extensions for some of them" in {
      val filesTarget = FilesTarget(
        File(""),
        Set(
          File("test.css").path,
          File("test.js-that_will_be_kotlin").path,
          File("Test-1.java-that_will_be_ruby").path,
          File("test-rb.resource").path),
        Set.empty)

      val languages = LanguagesHelper.fromFileTarget(
        filesTarget,
        Map(
          Languages.Ruby -> Set("-rb.resource", "-1.java-that_will_be_ruby"),
          Languages.Kotlin -> Set(".js-that_will_be_kotlin")))

      languages should containTheSameElementsAs(Seq(Languages.Kotlin, Languages.Ruby, Languages.CSS))
    }

    "return an empty set of languages for extensions that do not match any language" in {
      val filesTarget =
        FilesTarget(
          File(""),
          Set(File("test.exotericLanguage").path, File("test-rb.anotherLanguageThatNoOneUses").path),
          Set.empty)

      val languages = LanguagesHelper.fromFileTarget(filesTarget, Map.empty)

      languages should beEmpty
    }
  }
} 
Example 84
Source File: TestUtils.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.utils

import java.nio.file.attribute.PosixFilePermission
import java.nio.file.{Path, Paths}

import better.files.File
import com.codacy.plugins.api.results
import io.circe.Decoder
import org.specs2.concurrent.ExecutionEnv
import org.specs2.matcher.MatchResult

import scala.sys.process.Process

object TestUtils {

  implicit val categoryDecoder: Decoder[results.Pattern.Category.Value] =
    Decoder.decodeEnumeration(results.Pattern.Category)

  implicit val levelDecoder: Decoder[results.Result.Level.Value] =
    Decoder.decodeEnumeration(results.Result.Level)
  implicit val fileDecoder: Decoder[Path] = Decoder[String].map(Paths.get(_))
  implicit val executionEnv: ExecutionEnv = ExecutionEnv.fromGlobalExecutionContext

  def withClonedRepo[T](gitUrl: String, commitUUid: String)(block: (File, File) => MatchResult[T]): MatchResult[T] =
    (for {
      directory <- File.temporaryDirectory()
      file <- File.temporaryFile()
    } yield {
      directory
        .addPermission(PosixFilePermission.OWNER_READ)
        .addPermission(PosixFilePermission.GROUP_READ)
        .addPermission(PosixFilePermission.OTHERS_READ)
        .addPermission(PosixFilePermission.OWNER_EXECUTE)
        .addPermission(PosixFilePermission.GROUP_EXECUTE)
        .addPermission(PosixFilePermission.OTHERS_EXECUTE)
      Process(Seq("git", "clone", gitUrl, directory.pathAsString)).!
      Process(Seq("git", "reset", "--hard", commitUUid), directory.toJava).!
      block(file, directory)
    }).get()

  def withTemporaryGitRepo[T](fn: File => MatchResult[T]): MatchResult[T] = {
    (for {
      temporaryDirectory <- File.temporaryDirectory()
    } yield {
      Process(Seq("git", "init"), temporaryDirectory.toJava).!
      Process(Seq("git", "commit", "--allow-empty", "-m", "initial commit"), temporaryDirectory.toJava).!
      fn(temporaryDirectory)
    }).get

  }
} 
Example 85
Source File: CommitSpec.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.git

import better.files.File
import org.specs2.control.NoLanguageFeatures
import org.specs2.mutable.Specification
import com.codacy.analysis.core.utils.TestUtils._

import scala.sys.process.Process
import scala.util.Success

class CommitSpec extends Specification with NoLanguageFeatures {

  "Commit" should {
    "get all files" in {
      withTemporaryGitRepo { temporaryDirectory =>
        (for {
          tempFile1 <- File.temporaryFile(parent = Some(temporaryDirectory))
          tempFile2 <- File.temporaryFile(parent = Some(temporaryDirectory))
          tempFile3 <- File.temporaryFile(parent = Some(temporaryDirectory))
        } yield {

          def addFile(file: File) = {
            Process(Seq("git", "add", temporaryDirectory.relativize(file).toString), temporaryDirectory.toJava).!
          }
          addFile(tempFile1)
          addFile(tempFile2)
          addFile(tempFile3)
          Process(Seq("git", "commit", "-m", "tmp"), temporaryDirectory.toJava).!

          val expectedFiles =
            List(tempFile1, tempFile2, tempFile3).map(temporaryDirectory.relativize)
          Git.repository(temporaryDirectory).flatMap(_.latestCommit).flatMap(_.files) must beLike {
            case Success(fileSet) => fileSet must containTheSameElementsAs(expectedFiles)
          }
        }).get()
      }
    }
  }
} 
Example 86
Source File: RepositorySpec.scala    From codacy-analysis-cli   with GNU Affero General Public License v3.0 5 votes vote down vote up
package com.codacy.analysis.core.git

import better.files.File
import com.codacy.analysis.core.utils.TestUtils._
import org.specs2.control.NoLanguageFeatures
import org.specs2.mutable.Specification

import scala.sys.process.Process
import scala.util.Success

class RepositorySpec extends Specification with NoLanguageFeatures {

  "Repository" should {
    "get latest commit" in {

      "when it exists" in {
        (for {
          temporaryDirectory <- File.temporaryDirectory()
          temporaryFile <- File.temporaryFile(parent = Some(temporaryDirectory))
        } yield {
          Process(Seq("git", "init"), temporaryDirectory.toJava).!
          Process(Seq("git", "add", temporaryDirectory.relativize(temporaryFile).toString), temporaryDirectory.toJava).!
          Process(Seq("git", "commit", "-m", "tmp"), temporaryDirectory.toJava).!

          Git.repository(temporaryDirectory).flatMap(_.latestCommit) must beSuccessfulTry
        }).get
      }

      "when it doesn't exist" in {
        (for {
          temporaryDirectory <- File.temporaryDirectory()
        } yield {
          Process(Seq("git", "init"), temporaryDirectory.toJava).!

          Git.repository(temporaryDirectory).flatMap(_.latestCommit) must beFailedTry
        }).get
      }
    }

    "get all uncommitted changes" in {

      "changed files" in {
        withTemporaryGitRepo { directory =>
          val file = directory / "random_file.file"
          file.createFileIfNotExists(createParents = true)

          Process(Seq("git", "add", "."), directory.toJava).!
          Process(Seq("git", "commit", "-m", "added a new file!"), directory.toJava).!

          file.write("Random file contents")

          Git.repository(directory).flatMap(_.uncommitedFiles) must beLike {
            case Success(uncommited) =>
              uncommited must contain(exactly(relativePath(file, directory)))
          }
        }
      }

      "untracked files" in {
        "with an untracked folder that contains an untracked file" in {
          withTemporaryGitRepo { directory =>
            val deepFile = directory / "mainFolder" / "subFolder" / "deepFile.sc"
            deepFile.createFileIfNotExists(createParents = true)

            Git.repository(directory).flatMap(_.uncommitedFiles) must beLike {
              case Success(uncommited) =>
                uncommited must contain(exactly(relativePath(deepFile, directory)))
            }
          }
        }

        "with an untracked folder with no content" in {
          withTemporaryGitRepo { directory =>
            val noContentsFolder = directory / "mainFolder" / "noContents"
            noContentsFolder.createDirectoryIfNotExists(createParents = true)

            Git.repository(directory).flatMap(_.uncommitedFiles) must beLike {
              case Success(uncommited) =>
                uncommited must beEmpty
            }
          }
        }
      }
    }

  }

  private def relativePath(targetFile: File, directory: File): String = {
    targetFile.pathAsString.stripPrefix(s"${directory.pathAsString}/")
  }
} 
Example 87
Source File: Config.scala    From iotchain   with MIT License 4 votes vote down vote up
package jbok.common.config

import java.nio.file.Path

import better.files.File
import cats.effect.Sync
import cats.implicits._
import io.circe
import io.circe.{Decoder, Json}
import jbok.common.FileUtil
import jbok.common.log.Logger

trait Config[F[_]] {
  def read[A: Decoder](path: Path): F[A]

  def read[A: Decoder](text: String): F[A]

  def readResource[A: Decoder](name: String): F[A]

  def dump(json: Json, path: Path): F[Unit]
}

object Config {
  def apply[F[_]](implicit ev: Config[F]): Config[F] = ev

  implicit def instance[F[_]](implicit F: Sync[F]): Config[F] = new Config[F] {
    private val log = Logger[F]

    override def read[A: Decoder](path: Path): F[A] =
      log.i(s"reading config from path=${path}") >>
        (File(path).extension match {
          case Some(".json") =>
            FileUtil[F].read(path).flatMap(text => F.fromEither(circe.parser.decode[A](text)))
          case Some(".yml") | Some(".yaml") =>
            FileUtil[F].read(path).flatMap(text => F.fromEither(circe.yaml.parser.parse(text).flatMap(_.as[A])))
          case Some(ext) =>
            F.raiseError(new Exception(s"Unknown extension path=${path},ext=${ext}"))
          case None =>
            F.raiseError(new Exception(s"No extension path=${path}"))
        })

    override def read[A: Decoder](text: String): F[A] =
      log.i(s"parsing config from text") >>
        F.fromEither(circe.yaml.parser.parse(text).flatMap(_.as[A]))

    override def readResource[A: Decoder](name: String): F[A] =
      log.i(s"reading config from resource=${name}") >>
        FileUtil[F].readResource(name) >>= read[A]

    override def dump(json: Json, path: Path): F[Unit] =
      log.i(s"dumping config to path=${path}") >>
        (File(path).extension match {
          case Some(".json") =>
            FileUtil[F].dump(json.spaces2, path)
          case Some(".yml") | Some(".yaml") =>
            FileUtil[F].dump(circe.yaml.Printer.spaces2.copy(preserveOrder = true, indicatorIndent = 2).pretty(json), path)
          case Some(ext) =>
            F.raiseError(new Exception(s"Unknown extension path=${path},ext=${ext}"))
          case None =>
            F.raiseError(new Exception(s"No extension path=${path}"))
        })
  }
}