All Downloads are FREE. Search and download functionalities are using the official Maven repository.

.scala-fortify_2.13.15.1.1.4.source-code.FortifyComponent.scala Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2016-2024 Lightbend, Inc. All rights reserved.
 * No information contained herein may be reproduced or transmitted in any form
 * or by any means without the express written permission of Lightbend, Inc.
 */

package com.lightbend.tools.fortify.plugin

import java.io.{File, FileOutputStream, OutputStreamWriter, PrintWriter}
import java.nio.charset.StandardCharsets

import scala.tools.nsc
import nsc.plugins._

abstract class FortifyComponent extends PluginComponent with PluginOptions {

  override def description = "compiler phase for Scala -> Fortify NST"

  /** the following two members override abstract members in Transform */
  val phaseName: String = "compile-to-nst"

  /** Create a new phase which applies transformer */
  def newPhase(prev: nsc.Phase): StdPhase = new FortifyPhase(prev)

  val session = collection.mutable.Buffer[SessionWriter.Entry]()

  /** The phase defined by this transform */
  class FortifyPhase(prev: nsc.Phase) extends StdPhase(prev) {
    val translator = new Translator[global.type](global, showSourceInfo)
    override def apply(unit: global.CompilationUnit): Unit = {
      if (unit.source.file.file == null) // e.g. in REPL
        return
      if (Paths.isExcluded(excludes, unit.source.file.file))
        return
      val actualOutputDir = outputDir.getOrElse(new File("."))
      val outputPath =
        Paths.sourcePathToNstPath(unit.source.file.file, actualOutputDir)
      outputPath.getParentFile.mkdirs()
      val writer: java.io.PrintWriter =
        new scala.reflect.io.File(outputPath)(io.Codec.UTF8).printWriter()
      session +=
        SessionWriter.Entry(unit.source.file.file, outputPath, countLines(unit.source.file.file))
      val (originalPath, lineMapper) = {
        val twirl = new Twirl(unit.source.content.mkString)
        twirl.originalPath match {
          case Some(path) =>
            (path, twirl.mapLine _)
          case None =>
            (unit.source.file.path, identity[Int] _)
        }
      }
      try translator.apply(originalPath, unit.source, unit.body, lineMapper, writer)
      finally writer.close()
    }
    override def run(): Unit = {
      super.run()
      if (session.isEmpty) // e.g. in REPL
        return
      for (id <- buildId; dir <- outputDir)
        SessionWriter.synchronized {
          val sessionFile =
            new File(dir.getParent, s"$id.scasession.increment")
          // maybe a bit janky to reuse this flag for this, but we don't want this
          // noise when doing development work
          if (!suppressEntitlementCheck)
            println(s"scala-fortify: writing translated files to ${dir.getAbsolutePath}")
          val exists = sessionFile.exists
          val foStream = new FileOutputStream(sessionFile, true) // append = true
          val osWriter = new OutputStreamWriter(foStream, StandardCharsets.UTF_8)
          val writer = new PrintWriter(osWriter)
          // not sure if it's important to match the Java translator's behavior
          // of starting a new file with a blank line, but we might as well
          if (!exists)
            writer.println()
          try SessionWriter.write(
              writer,
              buildId.getOrElse(""),
              session.toSeq,
              global.settings.encoding.value)
          finally writer.close()
        }
    }
  }

  private def countLines(file: File): Int = {
    val source = io.Source.fromFile(file)(global.settings.encoding.value)
    try source.getLines().size
    finally source.close()
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy