aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Christopher Vogt <oss.nsp@cvogt.org>2017-03-09 01:21:11 -0500
committerGitHub <noreply@github.com>2017-03-09 01:21:11 -0500
commit2e37c52f56e84f064a8bd265c6ed00a1e5f32b51 (patch)
treea6a67d4653a5010c401124b7de2978b1f540f23b
parent28d7497fc900a2b410c84da38ea104dcc638ef1e (diff)
parent919d7987fad82f59f998a29d79a82116049af1b9 (diff)
downloadcbt-2e37c52f56e84f064a8bd265c6ed00a1e5f32b51.tar.gz
cbt-2e37c52f56e84f064a8bd265c6ed00a1e5f32b51.tar.bz2
cbt-2e37c52f56e84f064a8bd265c6ed00a1e5f32b51.zip
Merge pull request #407 from cvogt/chris
Chris
-rw-r--r--libraries/proguard/Proguard.scala18
-rw-r--r--libraries/proguard/build/build.scala72
-rw-r--r--plugins/scalafmt/Scalafmt.scala145
-rw-r--r--plugins/scalafmt/build/build.scala2
-rw-r--r--plugins/sonatype-release/src/sonatype/SonatypeLib.scala17
-rw-r--r--stage2/Lib.scala27
-rw-r--r--stage2/plugins/GeneratedSections.scala52
7 files changed, 172 insertions, 161 deletions
diff --git a/libraries/proguard/Proguard.scala b/libraries/proguard/Proguard.scala
index e662e0d..7d57a77 100644
--- a/libraries/proguard/Proguard.scala
+++ b/libraries/proguard/Proguard.scala
@@ -22,15 +22,15 @@ object KeepOptionModifier {
object ProGuard {
val artifactId = "proguard-base"
- val groupId = "net.sf.proguard"
- val version = "5.3.2"
- val mainClass = "proguard.ProGuard"
- val `rt.jar` = Seq( new File( System.getProperty( "java.home" ), "lib/rt.jar" ) )
+ val groupId = "net.sf.proguard"
+ val version = "5.3.2"
+ val mainClass = "proguard.ProGuard"
+ val `rt.jar` = Seq( new File( System.getProperty( "java.home" ), "lib/rt.jar" ) )
}
case class ProGuard[T](
main: Seq[String] => Int,
- T: Seq[File] => T,
- log: String => Unit = _ => ()
+ T: Seq[File] => T,
+ log: String => Unit = _ => ()
) {
/**
@@ -160,9 +160,9 @@ case class ProGuard[T](
private object argsFor {
def apply[T: argsFor]( value: T ) = implicitly[argsFor[T]].apply( value )
implicit object SeqFile extends argsFor[Seq[File]]( v => Some( Seq( v.map( _.getPath ).mkString( ":" ) ) ) )
- implicit object File extends argsFor[File]( v => Some( Seq( v.getPath ) ) )
- implicit object String extends argsFor[String]( v => Some( Seq( v ) ) )
- implicit object Int extends argsFor[Int]( i => Some( Seq( i.toString ) ) )
+ implicit object File extends argsFor[File]( v => Some( Seq( v.getPath ) ) )
+ implicit object String extends argsFor[String]( v => Some( Seq( v ) ) )
+ implicit object Int extends argsFor[Int]( i => Some( Seq( i.toString ) ) )
implicit object Boolean
extends argsFor[Boolean]( {
case false => None
diff --git a/libraries/proguard/build/build.scala b/libraries/proguard/build/build.scala
index 9b55ec9..c781ce2 100644
--- a/libraries/proguard/build/build.scala
+++ b/libraries/proguard/build/build.scala
@@ -5,7 +5,27 @@ import java.net._
import java.io._
import scala.xml._
-class Build(val context: Context) extends Scalafmt with GeneratedSections{
+class Build(val context: Context) extends Scalafmt{
+ def description: String = "Type-safe scala wrapper to interfaces with ProGuard.main runner"
+ def inceptionYear = 2017
+
+ def generate = {
+ lib.transformFiles( sourceFiles, replaceSections( _, replacements ) )
+ compile
+ }
+
+ override def scalafmt = super.scalafmt.copy(
+ config = super.scalafmt.lib.cbtRecommendedConfig,
+ whiteSpaceInParenthesis = true
+ )
+
+ override def compile = {
+ // currently suffers from non-deterministic formatting. Try a few times to reproduce commit state.
+ val formatted = scalafmt.apply.map(_.string).mkString("\n")
+ if( formatted.nonEmpty ) System.err.println( "Formatted:\n" ++ formatted ++ "\n---------------" )
+ super.compile
+ }
+
def refcard = projectDirectory / "spec/refcard.html"
/** downloads html proguard parameter specification */
@@ -55,39 +75,6 @@ class Build(val context: Context) extends Scalafmt with GeneratedSections{
XmlNotDownloadingDTD.loadString( w.toString )
}
- override def scalafmtConfig = {
- import org.scalafmt.config._
- ScalafmtConfig.defaultWithAlign.copy(
- maxColumn = 110,
- continuationIndent = super.scalafmtConfig.continuationIndent.copy(
- defnSite = 2
- ),
- align = super.scalafmtConfig.align.copy(
- tokens = AlignToken.default ++ Set(
- AlignToken( ":", "Param" ),
- AlignToken( "=", "Param" )
- ) + AlignToken.caseArrow,
- arrowEnumeratorGenerator = true,
- mixedOwners = true
- ),
- binPack = super.scalafmtConfig.binPack.copy(
- parentConstructors = true
- ),
- spaces = super.scalafmtConfig.spaces.copy(
- inImportCurlyBraces = true
- ),
- lineEndings = LineEndings.unix,
- newlines = super.scalafmtConfig.newlines.copy(
- penalizeSingleSelectMultiArgList = false
- ),
- runner = super.scalafmtConfig.runner.copy(
- optimizer = super.scalafmtConfig.runner.optimizer.copy(
- forceConfigStyleOnOffset = -1
- )
- )
- )
- }
-
/** generates Scala code from parameter specification html */
def replacements = {
val tables = XML.loadFile(refcard) \\ "table"
@@ -143,21 +130,4 @@ class Build(val context: Context) extends Scalafmt with GeneratedSections{
"params" -> params
)
}
-
- override def generate{
- super.generate
- compile
- }
-
- private def whiteSpaceInParenthesis =
- Seq(
- "(\\(+)([^\\s\\)])".r.replaceAllIn(_:String, m => m.group(1).mkString(" ") ++ " " ++ m.group(2) ),
- "([^\\s\\(])(\\)+)".r.replaceAllIn(_:String, m => m.group(1) ++ " " ++ m.group(2).mkString(" ") )
- ).reduce(_ andThen _)
-
- override def compile = {
- scalafmt
- lib.transformFiles( sourceFiles, whiteSpaceInParenthesis )
- super.compile
- }
}
diff --git a/plugins/scalafmt/Scalafmt.scala b/plugins/scalafmt/Scalafmt.scala
index 5f4e054..9d42cbd 100644
--- a/plugins/scalafmt/Scalafmt.scala
+++ b/plugins/scalafmt/Scalafmt.scala
@@ -8,75 +8,106 @@ import java.io.File
import java.nio.file.Files._
import java.nio.file._
-/**
- * This plugin provides scalafmt support for cbt.
- *
- */
+/** This plugin provides scalafmt support for cbt. */
trait Scalafmt extends BaseBuild {
- /**
- * Reformat scala source code according to `scalafmtConfig` rules
- *
- * @return always returns `ExitCode.Success`
- */
- final def scalafmt: ExitCode = Scalafmt.format(sourceFiles, scalafmtConfig)
-
- /**
- * Scalafmt formatting config.
- *
- * Tries to get style in following order:
- * • project local .scalafmt.conf
- * • global ~/.scalafmt.conf
- * • default scalafmt config
- *
- * Override this task if you want to provide
- * scalafmt config programmatically on your own.
- */
- def scalafmtConfig: ScalafmtConfig =
- Scalafmt.getStyle(
- project = projectDirectory.toPath,
- home = Option(System.getProperty("user.home")) map (p => Paths.get(p))
+ /** Reformat scala source code according to `scalafmtConfig` rules */
+ def scalafmt = {
+ val scalafmtLib = new ScalafmtLib(lib)
+ scalafmtLib.format( sourceFiles ).config(
+ scalafmtLib.loadConfig(
+ projectDirectory.toPath
+ ) getOrElse ScalafmtConfig.default
)
+ }
}
-object Scalafmt {
+class ScalafmtLib(lib: Lib){ scalafmtLib =>
+ def userHome = Option( System.getProperty("user.home") ).map(Paths.get(_))
- def getStyle(project: Path, home: Option[Path]): ScalafmtConfig = {
- val local = getConfigPath(project)
- val global = home flatMap getConfigPath
- val customStyle = for {
- configPath <- local.orElse(global)
- style <- StyleCache.getStyleForFile(configPath.toString)
- } yield style
+ /** Tries to load config from .scalafmt.conf in given directory or fallback directory */
+ def loadConfig( directory: Path, fallback: Option[Path] = userHome ): Option[ScalafmtConfig] = {
+ def findIn( base: Path ): Option[Path] = {
+ Some( base.resolve(".scalafmt.conf").toAbsolutePath ).filter(isRegularFile(_))
+ }
- customStyle.getOrElse(ScalafmtConfig.default)
+ findIn( directory ).orElse( fallback flatMap findIn )
+ .flatMap ( file => StyleCache.getStyleForFile(file.toString) )
}
- def format(files: Seq[File], style: ScalafmtConfig): ExitCode = {
- val results = files.filter(_.string endsWith ".scala").map(_.toPath).map{ path =>
- val original = new String(readAllBytes(path))
- org.scalafmt.Scalafmt.format(original, style) match {
- case Formatted.Success(formatted) =>
- if (original != formatted) {
- val tmpPath = Paths.get(path.toString ++ ".scalafmt-tmp")
- write(tmpPath, formatted.getBytes)
- move(tmpPath, path, StandardCopyOption.REPLACE_EXISTING)
- Some(1)
- } else {
- Some(0)
+ case class format(files: Seq[File]){
+ /**
+ * @param whiteSpaceInParenthesis more of a hack to make up for missing support in Scalafmt. Does not respect alignment and maxColumn.
+ */
+ case class config(
+ config: ScalafmtConfig,
+ whiteSpaceInParenthesis: Boolean = false
+ ) extends (() => Seq[File]){
+ def lib = scalafmtLib
+ def apply = {
+ val (successes, errors) = scalafmtLib.lib.transformFilesOrError(
+ files,
+ org.scalafmt.Scalafmt.format(_, config) match {
+ case Formatted.Success(formatted) => Right(
+ if( whiteSpaceInParenthesis ){
+ scalafmtLib.whiteSpaceInParenthesis(formatted)
+ } else formatted
+ )
+ case Formatted.Failure( e ) => Left( e )
}
- case Formatted.Failure(e) =>
- System.err.println(s"Scalafmt failed for $path\nCause: $e\n")
- None
+ )
+ if(errors.nonEmpty)
+ throw new RuntimeException(
+ "Scalafmt failed to format some files:\n" ++ errors.map{
+ case (file, error) => file.string ++ ": " ++ error.getMessage
+ }.mkString("\n"),
+ errors.head._2
+ )
+ successes
}
}
- if(results.forall(_.nonEmpty)){
- System.err.println(s"Formatted ${results.flatten.sum} Scala sources")
- ExitCode.Success
- } else ExitCode.Failure
}
- private def getConfigPath(base: Path): Option[Path] = {
- Some( base.resolve(".scalafmt.conf").toFile )
- .collect{ case f if f.exists && f.isFile => f.toPath.toAbsolutePath }
+ private def whiteSpaceInParenthesis: String => String =
+ Seq(
+ "(\\(+)([^\\s\\)])".r.replaceAllIn(_:String, m => m.group(1).mkString(" ") ++ " " ++ m.group(2) ),
+ "([^\\s\\(])(\\)+)".r.replaceAllIn(_:String, m => m.group(1) ++ " " ++ m.group(2).mkString(" ") )
+ ).reduce(_ andThen _)
+
+ def cbtRecommendedConfig = {
+ import org.scalafmt.config._
+ val c = ScalafmtConfig.defaultWithAlign
+ c.copy(
+ maxColumn = 110,
+ continuationIndent = c.continuationIndent.copy(
+ defnSite = 2
+ ),
+ align = c.align.copy(
+ tokens = AlignToken.default ++ Set(
+ // formatting for these alignment tokens seems to be deterministic right now
+ // Maybe because of scala meta. Killing the class loader between runs seems not to help.
+ // Starting a new jvm each time does.
+ AlignToken( "=>", ".*" ),
+ AlignToken( ":", ".*" ),
+ AlignToken( "=", ".*" )
+ ) + AlignToken.caseArrow,
+ arrowEnumeratorGenerator = true,
+ mixedOwners = true
+ ),
+ binPack = c.binPack.copy(
+ parentConstructors = true
+ ),
+ spaces = c.spaces.copy(
+ inImportCurlyBraces = true
+ ),
+ lineEndings = LineEndings.unix,
+ newlines = c.newlines.copy(
+ penalizeSingleSelectMultiArgList = false
+ ),
+ runner = c.runner.copy(
+ optimizer = c.runner.optimizer.copy(
+ forceConfigStyleOnOffset = -1
+ )
+ )
+ )
}
}
diff --git a/plugins/scalafmt/build/build.scala b/plugins/scalafmt/build/build.scala
index b37d769..e592873 100644
--- a/plugins/scalafmt/build/build.scala
+++ b/plugins/scalafmt/build/build.scala
@@ -1,7 +1,7 @@
import cbt._
class Build(val context: Context) extends Plugin {
- private val ScalafmtVersion = "0.5.7"
+ private val ScalafmtVersion = "0.6.2"
override def dependencies =
super.dependencies ++
diff --git a/plugins/sonatype-release/src/sonatype/SonatypeLib.scala b/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
index 08f7ee1..4e5d613 100644
--- a/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
+++ b/plugins/sonatype-release/src/sonatype/SonatypeLib.scala
@@ -54,7 +54,7 @@ final case class SonatypeLib(
profileName: String,
serviceURI: String = SonatypeLib.serviceURI,
snapshotsURI: String = SonatypeLib.snapshotsURI,
- credentials: String = SonatypeLib.credentials
+ credentials: String = SonatypeLib.credentials // FIXME: maybe hide this from cli ?
)( implicit logger: Logger ){
private val lib: Lib = new Lib(logger)
private def log: String => Unit = logger.log("sonatype-release",_)
@@ -74,20 +74,21 @@ final case class SonatypeLib(
artifacts, new URL(deployURI ++ releaseFolder), Some(credentials)
)
- val urls = if (releaseFolder.endsWith("-SNAPSHOT")){
- publish(snapshotsURI)
+ if (releaseFolder.endsWith("-SNAPSHOT")){
+ val urls = publish(snapshotsURI)
+ System.err.println(lib.green("Successfully published snapshot on Sonatype!"))
+ urls
} else {
val profile = getStagingProfile
val repoId = createStagingRepo(profile)
val urls = publish(
serviceURI ++ "/staging/deployByRepositoryId/" ++ repoId.string
)
+ System.err.println(lib.green("Successfully uploaded jars to Sonatype!"))
finishRelease( getStagingRepoById(repoId), profile )
- urls
+ System.err.println(lib.green("Successfully released uploaded jars to Maven Central!"))
+ urls
}
-
- System.err.println(lib.green("Successfully published to Sonatype!"))
- urls
}
/*
@@ -101,6 +102,8 @@ final case class SonatypeLib(
private def release: ExitCode = {
val profile = getStagingProfile()
+ System.err.println("Releasing jars to Maven Central!")
+
getStagingRepos(profile).toList match {
case Nil =>
System.err.println(lib.red("No staging repositories found, you need to publish artifacts first."))
diff --git a/stage2/Lib.scala b/stage2/Lib.scala
index c95ee2a..db1ee6d 100644
--- a/stage2/Lib.scala
+++ b/stage2/Lib.scala
@@ -4,7 +4,7 @@ import java.io._
import java.net._
import java.lang.reflect.InvocationTargetException
import java.nio.file.{Path =>_,_}
-import java.nio.file.Files.{readAllBytes, deleteIfExists, delete}
+import java.nio.file.Files._
import java.security.MessageDigest
import java.util.jar._
import java.lang.reflect.Method
@@ -539,13 +539,26 @@ final class Lib(val logger: Logger) extends Stage1Lib(logger){
}
def transformFiles( files: Seq[File], transform: String => String ): Seq[File] = {
- files.flatMap{ file =>
+ transformFilesOrError( files, s => Right(transform(s)) )._1
+ }
+
+ def transformFilesOrError[T]( files: Seq[File], transform: String => Either[T,String] ): ( Seq[File], Seq[(File, T)] ) = {
+ val results = files.map{ file =>
val string = file.readAsString
- val replaced = transform( string )
- if( string != replaced ) {
- write( file, replaced )
- Some(file)
- } else None
+ transform( string ).left.map(
+ file -> _
+ ).right.map(
+ replaced =>
+ if( string != replaced ) {
+ val tmpFile = file ++ ".cbt-tmp"
+ assert( !tmpFile.exists )
+ write( tmpFile, replaced )
+ move( tmpFile.toPath, file.toPath, StandardCopyOption.REPLACE_EXISTING )
+ Some( file )
+ } else None
+ )
}
+
+ ( results.map(_.right.toOption).flatten.flatten, results.map(_.left.toOption).flatten )
}
}
diff --git a/stage2/plugins/GeneratedSections.scala b/stage2/plugins/GeneratedSections.scala
index dc065cf..aedcaff 100644
--- a/stage2/plugins/GeneratedSections.scala
+++ b/stage2/plugins/GeneratedSections.scala
@@ -1,33 +1,27 @@
package cbt
import java.nio.file.Files._
-trait GeneratedSections extends BaseBuild{
- def generatedSectionStartMarker( name: String ) = s"AUTO GENERATED SECTION BEGIN: $name "
- def generatedSectionEndMarker( name: String ) = s"AUTO GENERATED SECTION END: $name "
- assert(
- generatedSectionStartMarker("foo").endsWith(" "),
- "generatedSectionStartMarker needs to end with a space character"
- )
- assert(
- generatedSectionEndMarker("foo").endsWith(" "),
- "generatedSectionEndMarker needs to end with a space character"
- )
-
- def replacements: Seq[(String, String)]
-
- def generate = {
- def replaceSections(subject: String, sections: Seq[(String, String)]): String = {
- sections.headOption.map{
- case (name, replacement) =>
- replaceSections(
- s"(?s)(\n[^\n]*AUTO GENERATED SECTION BEGIN: $name [^\n]*\n).*(\n[^\n]*AUTO GENERATED SECTION END: $name [^\n]*\n)"
- .r.replaceAllIn( subject, m => m.group(1) ++ replacement ++ m.group(2) ),
- sections.tail
- )
- }.getOrElse(subject)
- }
-
- val updated = lib.transformFiles( sourceFiles, replaceSections( _, replacements ) )
-
- logger.log("generated-sections","Updated:" + updated.map(_ ++ "\n").mkString)
+object replaceSections{
+ def apply(
+ subject: String,
+ sections: Seq[(String, String)],
+ generatedSectionBeginMarker: String => String = name => s"AUTO GENERATED SECTION BEGIN: $name ",
+ generatedSectionEndMarker: String => String = name => s"AUTO GENERATED SECTION END: $name "
+ ): String = {
+ assert(
+ generatedSectionBeginMarker("foo").endsWith(" "),
+ "generatedSectionStartMarker needs to end with a space character"
+ )
+ assert(
+ generatedSectionEndMarker("foo").endsWith(" "),
+ "generatedSectionEndMarker needs to end with a space character"
+ )
+ sections.headOption.map{
+ case (name, replacement) =>
+ replaceSections(
+ s"(?s)(\n[^\n]*AUTO GENERATED SECTION BEGIN: $name [^\n]*\n).*(\n[^\n]*AUTO GENERATED SECTION END: $name [^\n]*\n)"
+ .r.replaceAllIn( subject, m => m.group(1) ++ replacement ++ m.group(2) ),
+ sections.tail
+ )
+ }.getOrElse(subject)
}
}