From 04a7895b60a7f6d16e2beda5450b212e1fcaafc3 Mon Sep 17 00:00:00 2001 From: ChavXO Date: Fri, 5 Aug 2016 00:08:26 +0200 Subject: [PATCH 1/2] Changed implementation to only use nio. --- build/build.scala | 4 +- compatibility/BuildInterface.java | 5 +- compatibility/Context.java | 14 ++-- compatibility/Dependency.java | 7 +- nailgun_launcher/CBTUrlClassLoader.java | 6 +- nailgun_launcher/NailgunLauncher.java | 43 ++++++----- nailgun_launcher/Stage0Lib.java | 34 +++++---- stage1/CbtPaths.scala | 24 +++---- stage1/ClassPath.scala | 12 ++-- stage1/ContextImplementation.scala | 14 ++-- stage1/MavenRepository.scala | 5 +- stage1/Stage1.scala | 32 +++++---- stage1/Stage1Lib.scala | 50 +++++++------ stage1/cbt.scala | 15 ++-- stage1/resolver.scala | 41 +++++------ stage2/BasicBuild.scala | 43 +++++------ stage2/BuildBuild.scala | 21 +++--- stage2/BuildDependency.scala | 5 +- stage2/GitDependency.scala | 14 ++-- stage2/Lib.scala | 95 +++++++++++++------------ stage2/PackageJars.scala | 17 ++--- stage2/Publish.scala | 6 +- stage2/Scaffold.scala | 9 +-- stage2/Stage2.scala | 2 + stage2/ToolsTasks.scala | 7 +- 25 files changed, 289 insertions(+), 236 deletions(-) diff --git a/build/build.scala b/build/build.scala index 8770ef63..0dffc8c4 100644 --- a/build/build.scala +++ b/build/build.scala @@ -1,4 +1,6 @@ import cbt._ +import java.nio._ +import java.nio.file._ class Build(val context: Context) extends Publish{ // FIXME: somehow consolidate this with cbt's own boot-strapping from source. @@ -12,7 +14,7 @@ class Build(val context: Context) extends Publish{ } override def sources = Seq( "nailgun_launcher", "stage1", "stage2", "compatibility" - ).map(d => projectDirectory ++ ("/" + d)) + ).map(d => Path.get( projectDirectory.toString + ("/" + d) ) ) def groupId: String = "org.cvogt" diff --git a/compatibility/BuildInterface.java b/compatibility/BuildInterface.java index 636ded99..35f905fb 100644 --- a/compatibility/BuildInterface.java +++ b/compatibility/BuildInterface.java @@ -1,10 +1,11 @@ package cbt; -import java.io.*; +import java.nio.*; +import java.nio.file.*; public interface BuildInterface extends Dependency{ public abstract BuildInterface copy(Context context); // needed to configure builds public abstract String scalaVersion(); // needed to propagate scalaVersion to dependent builds public abstract String[] crossScalaVersionsArray(); // FIXME: this probably can't use Scala classes public abstract BuildInterface finalBuild(); // needed to propagage through build builds. Maybe we can get rid of this. - public abstract File[] triggerLoopFilesArray(); // needed for watching files across composed builds + public abstract Path[] triggerLoopFilesArray(); // needed for watching files across composed builds } diff --git a/compatibility/Context.java b/compatibility/Context.java index 921087fe..c7cf900b 100644 --- a/compatibility/Context.java +++ b/compatibility/Context.java @@ -1,11 +1,11 @@ package cbt; -import java.io.*; +import java.nio.file.*; import java.util.concurrent.ConcurrentHashMap; // TODO: try to reduce the number of members public abstract class Context{ - public abstract File projectDirectory(); - public abstract File cwd(); + public abstract Path projectDirectory(); + public abstract Path cwd(); public abstract String[] argsArray(); public abstract String[] enabledLoggersArray(); public abstract Long startCompat(); @@ -14,9 +14,9 @@ public abstract class Context{ public abstract String scalaVersionOrNull(); // needed to propagate scalaVersion to dependendee builds public abstract ConcurrentHashMap permanentKeys(); public abstract ConcurrentHashMap permanentClassLoaders(); - public abstract File cache(); - public abstract File cbtHome(); - public abstract File cbtRootHome(); - public abstract File compatibilityTarget(); + public abstract Path cache(); + public abstract Path cbtHome(); + public abstract Path cbtRootHome(); + public abstract Path compatibilityTarget(); public abstract BuildInterface parentBuildOrNull(); } diff --git a/compatibility/Dependency.java b/compatibility/Dependency.java index d491174d..4379173e 100644 --- a/compatibility/Dependency.java +++ b/compatibility/Dependency.java @@ -1,10 +1,11 @@ package cbt; -import java.io.*; +import java.nio.*; +import java.nio.file.*; public interface Dependency{ public abstract String show(); public abstract Boolean needsUpdateCompat(); public abstract Dependency[] dependenciesArray(); - public abstract File[] dependencyClasspathArray(); - public abstract File[] exportedClasspathArray(); + public abstract Path[] dependencyClasspathArray(); + public abstract Path[] exportedClasspathArray(); } diff --git a/nailgun_launcher/CBTUrlClassLoader.java b/nailgun_launcher/CBTUrlClassLoader.java index b799bc0b..23d67a43 100644 --- a/nailgun_launcher/CBTUrlClassLoader.java +++ b/nailgun_launcher/CBTUrlClassLoader.java @@ -1,5 +1,7 @@ package cbt; import java.io.*; +import java.nio.*; +import java.nio.file.*; import java.net.*; import java.util.*; import static cbt.Stage0Lib.*; @@ -43,8 +45,8 @@ public Class loadClass(String name, Boolean resolve) throws ClassNotFoundExcepti } void assertExist(URL[] urls){ for(URL url: urls){ - if(!new File(url.getPath()).exists()){ - throw new AssertionError("File does not exist when trying to create CbtURLClassLoader: "+url); + if(!Files.exists( Paths.get( url.getPath() ), LinkOption.NOFOLLOW_LINKS ) ){ + throw new AssertionError("File does not exist when trying to create CbtURLClassLoader: " + url); } } } diff --git a/nailgun_launcher/NailgunLauncher.java b/nailgun_launcher/NailgunLauncher.java index 159041f1..0c3f2e55 100644 --- a/nailgun_launcher/NailgunLauncher.java +++ b/nailgun_launcher/NailgunLauncher.java @@ -1,5 +1,7 @@ package cbt; import java.io.*; +import java.nio.file.*; +import java.nio.*; import java.lang.reflect.*; import java.net.*; import java.security.*; @@ -31,9 +33,9 @@ public static Object getBuild( Object context ) throws Exception{ BuildStage1Result res = buildStage1( (Boolean) get(context, "cbtHasChangedCompat"), (Long) get(context, "startCompat"), - ((File) get(context, "cache")).toString() + "/", - ((File) get(context, "cbtHome")).toString(), - ((File) get(context, "compatibilityTarget")).toString() + "/", + ((Path) get(context, "cache")).toString() + "/", + ((Path) get(context, "cbtHome")).toString(), + ((Path) get(context, "compatibilityTarget")).toString() + "/", new ClassLoaderCache2( (ConcurrentHashMap) get(context, "permanentKeys"), (ConcurrentHashMap) get(context, "permanentClassLoaders") @@ -73,13 +75,13 @@ public static void main( String[] args ) throws Exception { .loadClass("cbt.Stage1") .getMethod( "run", - String[].class, File.class, File.class, Boolean.class, - File.class, Long.class, ConcurrentHashMap.class, ConcurrentHashMap.class + String[].class, Path.class, Path.class, Boolean.class, + Path.class, Long.class, ConcurrentHashMap.class, ConcurrentHashMap.class ) .invoke( null, - (Object) args, new File(cache), new File(CBT_HOME), res.changed, - new File(compatibilityTarget), start, classLoaderCache.keys, classLoaderCache.values + (Object) args, Paths.get(cache), Paths.get(CBT_HOME), res.changed, + Paths.get(compatibilityTarget), start, classLoaderCache.keys, classLoaderCache.values ) ); } catch (Exception e) { @@ -104,7 +106,7 @@ public static BuildStage1Result buildStage1( String nailgunTarget = cbtHome + "/" + NAILGUN + TARGET; String stage1Sources = cbtHome + "/" + STAGE1; String stage1Target = stage1Sources + TARGET; - File compatibilitySources = new File(cbtHome + "/compatibility"); + Path compatibilitySources = Paths.get(cbtHome + "/compatibility"); String mavenCache = cache + "maven"; String mavenUrl = "https://repo1.maven.org/maven2"; @@ -115,12 +117,14 @@ public static BuildStage1Result buildStage1( if(!compatibilityTarget.startsWith(cbtHome)){ compatibilityClassLoader = classLoaderCache.get( compatibilityTarget ); } else { - List compatibilitySourceFiles = new ArrayList(); - for( File f: compatibilitySources.listFiles() ){ - if( f.isFile() && (f.toString().endsWith(".scala") || f.toString().endsWith(".java")) ){ - compatibilitySourceFiles.add(f); + List compatibilitySourceFiles = new ArrayList(); + try (DirectoryStream directoryStream = Files.newDirectoryStream(Paths.get(compatibilitySources.toString()))) { + for (Path f : directoryStream) { + if( ! Files.isDirectory(f, LinkOption.NOFOLLOW_LINKS) && f.toString().endsWith(".java") ){ + compatibilitySourceFiles.add(f); + } } - } + } catch (IOException ex) {ex.printStackTrace();} changed = compile(changed, start, "", compatibilityTarget, earlyDeps, compatibilitySourceFiles, defaultSecurityManager); if( classLoaderCache.contains( compatibilityTarget ) ){ @@ -141,12 +145,15 @@ public static BuildStage1Result buildStage1( append( append( nailgunClasspathArray, compatibilityTarget ), stage1Target ); String stage1Classpath = classpath( stage1ClasspathArray ); - List stage1SourceFiles = new ArrayList(); - for( File f: new File(stage1Sources).listFiles() ){ - if( f.isFile() && f.toString().endsWith(".scala") ){ - stage1SourceFiles.add(f); + List stage1SourceFiles = new ArrayList(); + try (DirectoryStream directoryStream = Files.newDirectoryStream(Paths.get(stage1Sources))) { + for (Path f : directoryStream) { + if( ! Files.isDirectory(f, LinkOption.NOFOLLOW_LINKS) && f.toString().endsWith(".scala") ){ + stage1SourceFiles.add(f); + } } - } + } catch (IOException ex) {ex.printStackTrace();} + changed = compile(changed, start, stage1Classpath, stage1Target, earlyDeps, stage1SourceFiles, defaultSecurityManager); ClassLoader stage1classLoader; diff --git a/nailgun_launcher/Stage0Lib.java b/nailgun_launcher/Stage0Lib.java index 5f8c5c72..a2ab331c 100644 --- a/nailgun_launcher/Stage0Lib.java +++ b/nailgun_launcher/Stage0Lib.java @@ -3,6 +3,7 @@ import java.lang.reflect.*; import java.net.*; import java.nio.*; +import java.nio.file.attribute.*; import java.nio.file.*; import java.security.*; import java.util.*; @@ -46,23 +47,29 @@ public static String classpath( String... files ){ return join( pathSeparator, files ); } - public static File write(File file, String content, OpenOption... options) throws Exception{ - file.getParentFile().mkdirs(); - Files.write(file.toPath(), content.getBytes(), options); + public static Path write(Path file, String content, OpenOption... options) throws Exception{ + Files.createDirectories(file.getParent()); + Files.write(file, content.getBytes(), options); return file; } public static Boolean compile( Boolean changed, Long start, String classpath, String target, - EarlyDependencies earlyDeps, List sourceFiles, SecurityManager defaultSecurityManager + EarlyDependencies earlyDeps, List sourceFiles, SecurityManager defaultSecurityManager ) throws Exception{ - File statusFile = new File( new File(target) + ".last-success" ); - Long lastSuccessfullCompile = statusFile.lastModified(); - for( File file: sourceFiles ){ - if( file.lastModified() > lastSuccessfullCompile ){ - changed = true; - break; + Path statusFile = Paths.get(target.substring(0, target.length() - 1) + ".last-success" ); + try{ + FileTime lastSuccessfullCompile = Files.getLastModifiedTime(statusFile, LinkOption.NOFOLLOW_LINKS ); + for( Path file: sourceFiles ){ + FileTime lastModified = Files.getLastModifiedTime( file, LinkOption.NOFOLLOW_LINKS ); + if( lastModified.compareTo(lastSuccessfullCompile) > 0 ){ + changed = true; + break; + } } + } catch (Exception e) { + // throws exception if status file isn't found + changed = true; } if(changed){ List zincArgs = new ArrayList( @@ -82,17 +89,16 @@ public static Boolean compile( ) ); - for( File f: sourceFiles ){ + for( Path f: sourceFiles ){ zincArgs.add(f.toString()); } - PrintStream oldOut = System.out; try{ System.setOut(System.err); int exitCode = runMain( "com.typesafe.zinc.Main", zincArgs.toArray(new String[zincArgs.size()]), earlyDeps.zinc, defaultSecurityManager ); if( exitCode == 0 ){ write( statusFile, "" ); - Files.setLastModifiedTime( statusFile.toPath(), FileTime.fromMillis(start) ); + Files.setLastModifiedTime( statusFile, FileTime.fromMillis(start) ); } else { System.exit( exitCode ); } @@ -158,7 +164,7 @@ public static HttpURLConnection openConnectionConsideringProxy(URL urlString) public static void download(URL urlString, Path target, String sha1) throws Exception { final Path unverified = Paths.get(target+".unverified"); if(!Files.exists(target)) { - new File(target.toString()).getParentFile().mkdirs(); + Files.createDirectories(target.getParent()); System.err.println("downloading " + urlString); System.err.println("to " + target); final InputStream stream = openConnectionConsideringProxy(urlString).getInputStream(); diff --git a/stage1/CbtPaths.scala b/stage1/CbtPaths.scala index 71c2ef14..1c338646 100644 --- a/stage1/CbtPaths.scala +++ b/stage1/CbtPaths.scala @@ -1,15 +1,15 @@ package cbt -import java.io._ -case class CbtPaths(private val cbtHome: File, private val cache: File){ - val userHome: File = new File(Option(System.getProperty("user.home")).get) - val nailgun: File = cbtHome ++ "/nailgun_launcher" - val stage1: File = cbtHome ++ "/stage1" - val stage2: File = cbtHome ++ "/stage2" - val mavenCache: File = cache ++ "/maven" +import java.nio.file._ +case class CbtPaths(private val cbtHome: Path, private val cache: Path){ + val userHome: Path = Paths.get(Option(System.getProperty("user.home")).get) + val nailgun: Path = cbtHome ++ "nailgun_launcher" + val stage1: Path = cbtHome ++ "stage1" + val stage2: Path = cbtHome ++ "stage2" + val mavenCache: Path = cache ++ "/maven" private val target = NailgunLauncher.TARGET.stripSuffix("/") - val stage1Target: File = stage1 ++ ("/" ++ target) - val stage2Target: File = stage2 ++ ("/" ++ target) - val stage2StatusFile: File = stage2Target ++ ".last-success" - val compatibility: File = cbtHome ++ "/compatibility" - val nailgunTarget: File = nailgun ++ ("/" ++ target) + val stage1Target: Path = stage1 ++ target + val stage2Target: Path = stage2 ++ target + val stage2StatusFile: Path = Paths.get(stage2Target.toString.stripSuffix("/") + ".last-success") + val compatibility: Path = cbtHome ++ "compatibility" + val nailgunTarget: Path = nailgun ++ target } diff --git a/stage1/ClassPath.scala b/stage1/ClassPath.scala index 6e6f1139..99bb8fbf 100644 --- a/stage1/ClassPath.scala +++ b/stage1/ClassPath.scala @@ -1,28 +1,30 @@ package cbt import java.io._ +import java.nio._ +import java.nio.file._ import java.net._ object ClassPath{ def flatten( classPaths: Seq[ClassPath] ): ClassPath = ClassPath( classPaths.map(_.files).flatten ) } -case class ClassPath(files: Seq[File] = Seq()){ +case class ClassPath(files: Seq[Path] = Seq()){ private val duplicates = (files diff files.distinct).distinct assert( duplicates.isEmpty, "Duplicate classpath entries found:\n" ++ duplicates.mkString("\n") ++ "\nin classpath:\n"++string ) - private val nonExisting = files.distinct.filterNot(_.exists) + private val nonExisting = files.distinct.filterNot(f => Files.exists(f, LinkOption.NOFOLLOW_LINKS) ) assert( nonExisting.isEmpty, "Classpath contains entires that don't exist on disk:\n" ++ nonExisting.mkString("\n") ++ "\nin classpath:\n"++string ) - def +:(file: File) = ClassPath(file +: files) - def :+(file: File) = ClassPath(files :+ file) + def +:(file: Path) = ClassPath(file +: files) + def :+(file: Path) = ClassPath(files :+ file) def ++(other: ClassPath) = ClassPath(files ++ other.files) def string = strings.mkString( File.pathSeparator ) def strings = files.map{ - f => f.string ++ ( if(f.isDirectory) "/" else "" ) + f => f.toString ++ ( if( Files.isDirectory ( f, LinkOption.NOFOLLOW_LINKS ) ) "/" else "" ) }.sorted def toConsole = string } diff --git a/stage1/ContextImplementation.scala b/stage1/ContextImplementation.scala index 91c54f42..a77d1c68 100644 --- a/stage1/ContextImplementation.scala +++ b/stage1/ContextImplementation.scala @@ -1,11 +1,13 @@ package cbt import java.io._ +import java.nio._ +import java.nio.file._ import java.util.concurrent.ConcurrentHashMap import java.lang._ case class ContextImplementation( - projectDirectory: File, - cwd: File, + projectDirectory: Path, + cwd: Path, argsArray: Array[String], enabledLoggersArray: Array[String], startCompat: Long, @@ -14,9 +16,9 @@ case class ContextImplementation( scalaVersionOrNull: String, permanentKeys: ConcurrentHashMap[String,AnyRef], permanentClassLoaders: ConcurrentHashMap[AnyRef,ClassLoader], - cache: File, - cbtHome: File, - cbtRootHome: File, - compatibilityTarget: File, + cache: Path, + cbtHome: Path, + cbtRootHome: Path, + compatibilityTarget: Path, parentBuildOrNull: BuildInterface ) extends Context \ No newline at end of file diff --git a/stage1/MavenRepository.scala b/stage1/MavenRepository.scala index 4184d2d8..5ac7a4ce 100644 --- a/stage1/MavenRepository.scala +++ b/stage1/MavenRepository.scala @@ -1,7 +1,8 @@ package cbt -import java.io._ +import java.nio._ +import java.nio.file._ import java.net._ -case class MavenResolver( cbtHasChanged: Boolean, mavenCache: File, urls: URL* ){ +case class MavenResolver( cbtHasChanged: Boolean, mavenCache: Path, urls: URL* ){ def bind( dependencies: MavenDependency* )(implicit logger: Logger): Seq[BoundMavenDependency] = dependencies.map( BoundMavenDependency(cbtHasChanged,mavenCache,_,urls.to) ).to def bindOne( dependency: MavenDependency )(implicit logger: Logger): BoundMavenDependency diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index c94d1a4b..b1ad227c 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -1,6 +1,8 @@ package cbt import java.io._ +import java.nio._ +import java.nio.file._ import java.util.concurrent.ConcurrentHashMap import scala.collection.JavaConverters._ @@ -37,13 +39,13 @@ abstract class Stage2Base{ } case class Stage2Args( - cwd: File, + cwd: Path, args: Seq[String], cbtHasChanged: Boolean, classLoaderCache: ClassLoaderCache, - cache: File, - cbtHome: File, - compatibilityTarget: File + cache: Path, + cbtHome: Path, + compatibilityTarget: Path ){ val ClassLoaderCache( logger, @@ -52,8 +54,10 @@ case class Stage2Args( ) = classLoaderCache } object Stage1{ - protected def newerThan( a: File, b: File ) ={ - a.lastModified > b.lastModified + protected def newerThan( a: Path, b: Path ) ={ + val t1 = Files.getLastModifiedTime(a, LinkOption.NOFOLLOW_LINKS ) + val t2 = Files.getLastModifiedTime(b, LinkOption.NOFOLLOW_LINKS ) + t1.compareTo(t2) > 0 } def getBuild( _context: java.lang.Object, _cbtChanged: java.lang.Boolean ) = { @@ -78,7 +82,7 @@ object Stage1{ } def buildStage2( - compatibilityTarget: File, classLoaderCache: ClassLoaderCache, _cbtChanged: Boolean, cbtHome: File, cache: File + compatibilityTarget: Path, classLoaderCache: ClassLoaderCache, _cbtChanged: Boolean, cbtHome: Path, cache: Path ): (Boolean, ClassLoader) = { import classLoaderCache.logger @@ -86,10 +90,12 @@ object Stage1{ import lib._ val paths = CbtPaths(cbtHome, cache) import paths._ + import scala.collection.JavaConverters val stage2sourceFiles = ( - stage2.listFiles ++ (stage2 ++ "/plugins").listFiles - ).toVector.filter(_.isFile).filter(_.toString.endsWith(".scala")) + Files.newDirectoryStream(stage2).iterator.asScala.toSeq ++ + Files.newDirectoryStream(stage2 ++ "plugins").iterator.asScala.toSeq + ).toVector.filter( path => !Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS) ).filter(_.toString.endsWith(".scala") ) val cbtHasChanged = _cbtChanged || lib.needsUpdate(stage2sourceFiles, stage2StatusFile) @@ -142,10 +148,10 @@ object Stage1{ def run( _args: Array[String], - cache: File, - cbtHome: File, + cache: Path, + cbtHome: Path, _cbtChanged: java.lang.Boolean, - compatibilityTarget: File, + compatibilityTarget: Path, start: java.lang.Long, classLoaderCacheKeys: ConcurrentHashMap[String,AnyRef], classLoaderCacheValues: ConcurrentHashMap[AnyRef,ClassLoader] @@ -164,7 +170,7 @@ object Stage1{ val (cbtHasChanged, classLoader) = buildStage2( compatibilityTarget, classLoaderCache, _cbtChanged, cbtHome, cache ) val stage2Args = Stage2Args( - new File( args.args(0) ), + Paths.get( args.args(0) ), args.args.drop(1).toVector, // launcher changes cause entire nailgun restart, so no need for them here cbtHasChanged = cbtHasChanged, diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 9e500a3a..4bec260a 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -12,6 +12,8 @@ import java.util.{Set=>_,Map=>_,_} import java.util.concurrent.ConcurrentHashMap import javax.xml.bind.annotation.adapters.HexBinaryAdapter +import scala.collection.JavaConverters._ + // CLI interop case class ExitCode(integer: Int) object ExitCode{ @@ -30,7 +32,7 @@ object CatchTrappedExitCode{ } class BaseLib{ - def realpath(name: File) = new File(java.nio.file.Paths.get(name.getAbsolutePath).normalize.toString) + def realpath(name: Path) = Paths.get(java.nio.file.Paths.get(name.toString).normalize.toString) } class Stage1Lib( val logger: Logger ) extends BaseLib{ @@ -52,14 +54,14 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ def blue(string: String) = scala.Console.BLUE++string++scala.Console.RESET def green(string: String) = scala.Console.GREEN++string++scala.Console.RESET - def write(file: File, content: String, options: OpenOption*): File = Stage0Lib.write(file, content, options:_*) + def write(file: Path, content: String, options: OpenOption*): Path = Stage0Lib.write(file, content, options:_*) - def download(url: URL, target: File, sha1: Option[String]): Boolean = { - if( target.exists ){ + def download(url: URL, target: Path, sha1: Option[String]): Boolean = { + if( Files.exists(target, LinkOption.NOFOLLOW_LINKS) ){ logger.resolver(green("found ") ++ url.string) true } else { - val incomplete = ( target ++ ".incomplete" ).toPath; + val incomplete = ( target ++ ".incomplete" ) val connection = Stage0Lib.openConnectionConsideringProxy(url) if(connection.getResponseCode != HttpURLConnection.HTTP_OK){ logger.resolver(blue("not found: ") ++ url.string) @@ -67,7 +69,7 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ } else { System.err.println(blue("downloading ") ++ url.string) logger.resolver(blue("to ") ++ target.string) - target.getParentFile.mkdirs + Files createDirectories target.getParent val stream = connection.getInputStream try{ Files.copy(stream, incomplete, StandardCopyOption.REPLACE_EXISTING) @@ -81,15 +83,17 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ assert( expected == actual, s"$expected == $actual" ) logger.resolver( green("verified") ++ " checksum for " ++ target.string) } - Files.move(incomplete, target.toPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); + Files.move(incomplete, target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE); true } } } - def listFilesRecursive(f: File): Seq[File] = { + def listFilesRecursive(f: Path): Seq[Path] = { f +: ( - if( f.isDirectory ) f.listFiles.flatMap(listFilesRecursive).toVector else Seq[File]() + if( Files.isDirectory(f, LinkOption.NOFOLLOW_LINKS) ) + Files.newDirectoryStream(f).iterator.asScala.toSeq.flatMap(file => listFilesRecursive(file) ).toVector + else Seq[Path]() ) } @@ -123,24 +127,28 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ } } - def needsUpdate( sourceFiles: Seq[File], statusFile: File ) = { - val lastCompile = statusFile.lastModified - sourceFiles.filter(_.lastModified > lastCompile).nonEmpty + def needsUpdate( sourceFiles: Seq[Path], statusFile: Path ) = { + try { + val lastCompile = Files.getLastModifiedTime(statusFile, LinkOption.NOFOLLOW_LINKS ) + sourceFiles.filter(f => (Files.getLastModifiedTime(f, LinkOption.NOFOLLOW_LINKS ) compareTo lastCompile) > 0).nonEmpty + } catch { + case e: Throwable => true + } } def compile( cbtHasChanged: Boolean, needsRecompile: Boolean, - files: Seq[File], - compileTarget: File, - statusFile: File, + files: Seq[Path], + compileTarget: Path, + statusFile: Path, classpath: ClassPath, - mavenCache: File, + mavenCache: Path, scalacOptions: Seq[String] = Seq(), classLoaderCache: ClassLoaderCache, zincVersion: String, scalaVersion: String - ): Option[File] = { + ): Option[Path] = { val cp = classpath.string if(classpath.files.isEmpty) @@ -232,7 +240,7 @@ ${files.sorted.mkString(" \\\n")} // write version and when last compilation started so we can trigger // recompile if cbt version changed or newer source files are seen write(statusFile, "")//cbtVersion.getBytes) - Files.setLastModifiedTime(statusFile.toPath, FileTime.fromMillis(start) ) + Files.setLastModifiedTime(statusFile, FileTime.fromMillis(start) ) } else { System.exit(code.integer) // FIXME: let's find a better solution for error handling. Maybe a monad after all. } @@ -271,14 +279,14 @@ ${files.sorted.mkString(" \\\n")} ) def cacheOnDisk[T] - ( cbtHasChanged: Boolean, cacheFile: File ) + ( cbtHasChanged: Boolean, cacheFile: Path ) ( deserialize: String => T ) ( serialize: T => String ) ( compute: => Seq[T] ) = { - if(!cbtHasChanged && cacheFile.exists){ + if(!cbtHasChanged && Files.exists(cacheFile, LinkOption.NOFOLLOW_LINKS) ){ import collection.JavaConversions._ Files - .readAllLines( cacheFile.toPath, StandardCharsets.UTF_8 ) + .readAllLines( cacheFile, StandardCharsets.UTF_8 ) .toStream .map(deserialize) } else { diff --git a/stage1/cbt.scala b/stage1/cbt.scala index 85646954..17796d84 100644 --- a/stage1/cbt.scala +++ b/stage1/cbt.scala @@ -1,5 +1,6 @@ package cbt import java.io._ +import java.nio._ import java.nio.file._ import java.net._ import java.util.concurrent.ConcurrentHashMap @@ -13,12 +14,12 @@ object `package`{ val sonatypeSnapshots = sonatypeBase ++ "snapshots" private val lib = new BaseLib - implicit class FileExtensionMethods( file: File ){ - def ++( s: String ): File = { + implicit class FileExtensionMethods( file: Path ){ + def ++( s: String ): Path = { if(s endsWith "/") throw new Exception( """Trying to append a String that ends in "/" to a File would loose the trailing "/". Use .stripSuffix("/") if you need to.""" ) - new File( file.toString ++ s ) + Paths.get( file.toString ++ java.io.File.separator ++ s ) } def parent = lib.realpath(file ++ "/..") def string = file.toString @@ -29,7 +30,7 @@ object `package`{ } implicit class BuildInterfaceExtensions(build: BuildInterface){ import build._ - def triggerLoopFiles: Seq[File] = triggerLoopFilesArray.to + def triggerLoopFiles: Seq[Path] = triggerLoopFilesArray.to def crossScalaVersions: Seq[String] = crossScalaVersionsArray.to } implicit class ArtifactInfoExtensions(subject: ArtifactInfo){ @@ -67,14 +68,14 @@ object `package`{ def cbtHasChanged: scala.Boolean = cbtHasChangedCompat def copy( - projectDirectory: File = projectDirectory, + projectDirectory: Path = projectDirectory, args: Seq[String] = args, enabledLoggers: Set[String] = enabledLoggers, cbtHasChanged: Boolean = cbtHasChanged, version: Option[String] = version, scalaVersion: Option[String] = scalaVersion, - cache: File = cache, - cbtHome: File = cbtHome, + cache: Path = cache, + cbtHome: Path = cbtHome, parentBuild: Option[BuildInterface] = None ): Context = ContextImplementation( projectDirectory, diff --git a/stage1/resolver.scala b/stage1/resolver.scala index c2ebb62a..1cd090c2 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -1,4 +1,5 @@ package cbt +import java.nio._ import java.nio.file._ import java.nio.charset.StandardCharsets import java.net._ @@ -14,8 +15,8 @@ abstract class DependencyImplementation extends Dependency{ def needsUpdate: Boolean //def cacheClassLoader: Boolean = false private[cbt] def targetClasspath: ClassPath - def dependencyClasspathArray: Array[File] = dependencyClasspath.files.toArray - def exportedClasspathArray: Array[File] = exportedClasspath.files.toArray + def dependencyClasspathArray: Array[Path] = dependencyClasspath.files.toArray + def exportedClasspathArray: Array[Path] = exportedClasspath.files.toArray def exportedClasspath: ClassPath def dependenciesArray: Array[Dependency] = dependencies.to @@ -108,11 +109,11 @@ abstract class DependencyImplementation extends Dependency{ } // TODO: all this hard codes the scala version, needs more flexibility -class ScalaCompilerDependency(cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(mavenCentral)) -class ScalaLibraryDependency (cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(mavenCentral)) -class ScalaReflectDependency (cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(mavenCentral)) +class ScalaCompilerDependency(cbtHasChanged: Boolean, mavenCache: Path, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-compiler",version, Classifier.none), Seq(mavenCentral)) +class ScalaLibraryDependency (cbtHasChanged: Boolean, mavenCache: Path, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-library",version, Classifier.none), Seq(mavenCentral)) +class ScalaReflectDependency (cbtHasChanged: Boolean, mavenCache: Path, version: String)(implicit logger: Logger) extends BoundMavenDependency(cbtHasChanged, mavenCache, MavenDependency("org.scala-lang","scala-reflect",version, Classifier.none), Seq(mavenCentral)) -case class ScalaDependencies(cbtHasChanged: Boolean, mavenCache: File, version: String)(implicit val logger: Logger) extends DependencyImplementation{ sd => +case class ScalaDependencies(cbtHasChanged: Boolean, mavenCache: Path, version: String)(implicit val logger: Logger) extends DependencyImplementation{ sd => override final val needsUpdate = false def targetClasspath = ClassPath() def exportedClasspath = ClassPath() @@ -123,7 +124,7 @@ case class ScalaDependencies(cbtHasChanged: Boolean, mavenCache: File, version: ) } -case class BinaryDependency( path: File, dependencies: Seq[Dependency] )(implicit val logger: Logger) extends DependencyImplementation{ +case class BinaryDependency( path: Path, dependencies: Seq[Dependency] )(implicit val logger: Logger) extends DependencyImplementation{ def exportedClasspath = ClassPath(Seq(path)) override def needsUpdate = false def targetClasspath = exportedClasspath @@ -136,7 +137,7 @@ case class Dependencies( dependencies: Seq[Dependency] )(implicit val logger: Lo override def targetClasspath = ClassPath() } -case class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{ +case class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: Path, nailgunTarget: Path, stage1Target: Path, compatibilityTarget: Path)(implicit val logger: Logger) extends DependencyImplementation{ override def needsUpdate = cbtHasChanged override def targetClasspath = exportedClasspath override def exportedClasspath = ClassPath( Seq(nailgunTarget, stage1Target) ) @@ -149,13 +150,13 @@ case class Stage1Dependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTar MavenDependency("org.scala-lang.modules","scala-xml_"+constants.scalaMajorVersion,constants.scalaXmlVersion) ) } -case class CompatibilityDependency(cbtHasChanged: Boolean, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{ +case class CompatibilityDependency(cbtHasChanged: Boolean, compatibilityTarget: Path)(implicit val logger: Logger) extends DependencyImplementation{ override def needsUpdate = cbtHasChanged override def targetClasspath = exportedClasspath override def exportedClasspath = ClassPath( Seq(compatibilityTarget) ) override def dependencies = Seq() } -case class CbtDependency(cbtHasChanged: Boolean, mavenCache: File, nailgunTarget: File, stage1Target: File, stage2Target: File, compatibilityTarget: File)(implicit val logger: Logger) extends DependencyImplementation{ +case class CbtDependency(cbtHasChanged: Boolean, mavenCache: Path, nailgunTarget: Path, stage1Target: Path, stage2Target: Path, compatibilityTarget: Path)(implicit val logger: Logger) extends DependencyImplementation{ override def needsUpdate = cbtHasChanged override def targetClasspath = exportedClasspath override def exportedClasspath = ClassPath( Seq( stage2Target ) ) @@ -179,7 +180,7 @@ abstract class DependenciesProxy{ } class BoundMavenDependencies( - cbtHasChanged: Boolean, mavenCache: File, urls: Seq[URL], mavenDependencies: Seq[MavenDependency] + cbtHasChanged: Boolean, mavenCache: Path, urls: Seq[URL], mavenDependencies: Seq[MavenDependency] )(implicit logger: Logger) extends Dependencies( mavenDependencies.map( BoundMavenDependency(cbtHasChanged,mavenCache,_,urls) ) ) @@ -195,7 +196,7 @@ object MavenDependency{ } // FIXME: take MavenResolver instead of mavenCache and repositories separately case class BoundMavenDependency( - cbtHasChanged: Boolean, mavenCache: File, mavenDependency: MavenDependency, repositories: Seq[URL] + cbtHasChanged: Boolean, mavenCache: Path, mavenDependency: MavenDependency, repositories: Seq[URL] )(implicit val logger: Logger) extends DependencyImplementation with ArtifactInfo{ val MavenDependency( groupId, artifactId, version, classifier ) = mavenDependency assert( @@ -228,10 +229,10 @@ case class BoundMavenDependency( override def targetClasspath = exportedClasspath import scala.collection.JavaConversions._ - private def resolve(suffix: String, hash: Option[String]): File = { + private def resolve(suffix: String, hash: Option[String]): Path = { logger.resolver("Resolving "+this) - val file = mavenCache ++ basePath ++ "." ++ suffix - val urls = repositories.map(_ ++ basePath ++ "." ++ suffix) + val file = Paths.get( mavenCache + basePath + "." + suffix ) + val urls = repositories.map(f => Paths.get( f.toString + basePath.toString + "." + suffix).toUri.toURL ) urls.find( lib.download(_, file, hash) ).getOrElse( @@ -242,7 +243,7 @@ case class BoundMavenDependency( private def resolveHash(suffix: String) = { Files.readAllLines( - resolve( suffix ++ ".sha1", None ).toPath, + resolve( suffix.toString + ".sha1" , None ), StandardCharsets.UTF_8 ).mkString("\n").split(" ").head.trim } @@ -253,11 +254,11 @@ case class BoundMavenDependency( private object pomSha1Cache extends Cache[String] def pomSha1: String = pomSha1Cache{ resolveHash("pom") } - private object jarCache extends Cache[File] - def jar: File = jarCache{ resolve("jar", Some(jarSha1)) } + private object jarCache extends Cache[Path] + def jar: Path = jarCache{ resolve("jar", Some(jarSha1)) } - private object pomCache extends Cache[File] - def pom: File = pomCache{ resolve("pom", Some(pomSha1)) } + private object pomCache extends Cache[Path] + def pom: Path = pomCache{ resolve("pom", Some(pomSha1)) } private def pomXml = XML.loadFile(pom.string) // ========== pom traversal ========== diff --git a/stage2/BasicBuild.scala b/stage2/BasicBuild.scala index 42384db6..7e82aa94 100644 --- a/stage2/BasicBuild.scala +++ b/stage2/BasicBuild.scala @@ -2,12 +2,13 @@ package cbt import java.io._ import java.net._ -import java.nio.file.{Path =>_,_} +import java.nio.file._ import java.nio.file.Files.readAllBytes import java.security.MessageDigest import java.util.jar._ import scala.util._ +import scala.collection.JavaConverters._ class BasicBuild(val context: Context) extends BaseBuild trait BaseBuild extends DependencyImplementation with BuildInterface with TriggerLoop with SbtDependencyDsl{ @@ -22,8 +23,8 @@ trait BaseBuild extends DependencyImplementation with BuildInterface with Trigge // ========== general stuff ========== def enableConcurrency = false - final def projectDirectory: File = lib.realpath(context.projectDirectory) - assert( projectDirectory.exists, "projectDirectory does not exist: " ++ projectDirectory.string ) + final def projectDirectory: Path = lib.realpath(context.projectDirectory) + assert( Files.exists( projectDirectory, LinkOption.NOFOLLOW_LINKS ), "projectDirectory does not exist: " ++ projectDirectory.toString ) final def usage: String = lib.usage(this.getClass, show) // ========== meta data ========== @@ -46,35 +47,35 @@ trait BaseBuild extends DependencyImplementation with BuildInterface with Trigge ) // ========== paths ========== - final private val defaultSourceDirectory = projectDirectory ++ "/src" + final private val defaultSourceDirectory = projectDirectory ++ "src" /** base directory where stuff should be generated */ - def target: File = projectDirectory ++ "/target" + def target: Path = projectDirectory ++ "target" /** base directory where stuff should be generated for this scala version*/ - def scalaTarget: File = target ++ s"/scala-$scalaMajorVersion" + def scalaTarget: Path = target ++ s"scala-$scalaMajorVersion" /** directory where jars (and the pom file) should be put */ - def jarTarget: File = scalaTarget + def jarTarget: Path = scalaTarget /** directory where the scaladoc should be put */ - def apiTarget: File = scalaTarget ++ "/api" + def apiTarget: Path = scalaTarget ++ "api" /** directory where the class files should be put (in package directories) */ - def compileTarget: File = scalaTarget ++ "/classes" + def compileTarget: Path = scalaTarget ++ "classes" /** File which cbt uses to determine if it needs to trigger an incremental re-compile. Last modified date is the time when the last successful compilation started. Contents is the cbt version git hash. */ - def compileStatusFile: File = compileTarget ++ ".last-success" + def compileStatusFile: Path = Paths.get(compileTarget.toString + ".last-success") /** Source directories and files. Defaults to .scala and .java files in src/ and top-level. */ - def sources: Seq[File] = Seq(defaultSourceDirectory) ++ projectDirectory.listFiles.toVector.filter(lib.sourceFileFilter) + def sources: Seq[Path] = Seq(defaultSourceDirectory) ++ Files.newDirectoryStream(projectDirectory).iterator.asScala.filter(lib.sourceFileFilter) /** Absolute path names for all individual files found in sources directly or contained in directories. */ - final def sourceFiles: Seq[File] = lib.sourceFiles(sources) + final def sourceFiles: Seq[Path] = lib.sourceFiles(sources) protected def logEmptySourceDirectories(): Unit = { val nonExisting = sources - .filterNot( _.exists ) + .filterNot( f => Files.exists(f, LinkOption.NOFOLLOW_LINKS) ) .diff( Seq(defaultSourceDirectory) ) if(!nonExisting.isEmpty) logger.stage2("Some sources do not exist: \n"++nonExisting.mkString("\n")) } @@ -87,16 +88,16 @@ trait BaseBuild extends DependencyImplementation with BuildInterface with Trigge scalaVersion: String = scalaMajorVersion ) = lib.ScalaDependency( groupId, artifactId, version, classifier, scalaVersion ) - final def DirectoryDependency(path: File) = cbt.DirectoryDependency( + final def DirectoryDependency(path: Path) = cbt.DirectoryDependency( context.copy( projectDirectory = path, args = Seq() ) ) - def triggerLoopFiles: Seq[File] = sources ++ transitiveDependencies.collect{ case b: TriggerLoop => b.triggerLoopFiles }.flatten + def triggerLoopFiles: Seq[Path] = sources ++ transitiveDependencies.collect{ case b: TriggerLoop => b.triggerLoopFiles }.flatten - def localJars : Seq[File] = - Seq(projectDirectory ++ "/lib") - .filter(_.exists) - .flatMap(_.listFiles) + def localJars : Seq[Path] = + Seq(projectDirectory ++ "lib") + .filter(f => Files.exists(f, LinkOption.NOFOLLOW_LINKS) ) + .flatMap( f => Files.newDirectoryStream(f).iterator.asScala.toSeq ) .filter(_.toString.endsWith(".jar")) override def dependencyClasspath : ClassPath = ClassPath(localJars) ++ super.dependencyClasspath @@ -122,8 +123,8 @@ trait BaseBuild extends DependencyImplementation with BuildInterface with Trigge || transitiveDependencies.filterNot(_ == context.parentBuild).exists(_.needsUpdate) ) - private object compileCache extends Cache[Option[File]] - def compile: Option[File] = compileCache{ + private object compileCache extends Cache[Option[Path]] + def compile: Option[Path] = compileCache{ lib.compile( context.cbtHasChanged, needsUpdate || context.parentBuild.map(_.needsUpdate).getOrElse(false), diff --git a/stage2/BuildBuild.scala b/stage2/BuildBuild.scala index c57ce1bc..ccfea01b 100644 --- a/stage2/BuildBuild.scala +++ b/stage2/BuildBuild.scala @@ -1,4 +1,5 @@ package cbt +import java.nio._ import java.nio.file._ trait BuildBuild extends BaseBuild{ @@ -8,25 +9,25 @@ trait BuildBuild extends BaseBuild{ ) object plugins{ - final val scalaTest = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalatest" ) - final val sbtLayout = DirectoryDependency( managedContext.cbtHome ++ "/plugins/sbt_layout" ) - final val scalaJs = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalajs" ) - final val scalariform = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalariform" ) - final val scalafmt = DirectoryDependency( managedContext.cbtHome ++ "/plugins/scalafmt" ) - final val uberJar = DirectoryDependency( managedContext.cbtHome ++ "/plugins/uber-jar" ) + final val scalaTest = DirectoryDependency( managedContext.cbtHome ++ "plugins/scalatest" ) + final val sbtLayout = DirectoryDependency( managedContext.cbtHome ++ "plugins/sbt_layout" ) + final val scalaJs = DirectoryDependency( managedContext.cbtHome ++ "plugins/scalajs" ) + final val scalariform = DirectoryDependency( managedContext.cbtHome ++ "plugins/scalariform" ) + final val scalafmt = DirectoryDependency( managedContext.cbtHome ++ "plugins/scalafmt" ) + final val uberJar = DirectoryDependency( managedContext.cbtHome ++ "plugins/uber-jar" ) } override def dependencies = super.dependencies :+ context.cbtDependency - def managedBuildDirectory: java.io.File = lib.realpath( projectDirectory.parent ) + def managedBuildDirectory: Path = lib.realpath( projectDirectory.getParent ) private object managedBuildCache extends Cache[BuildInterface] def managedBuild = managedBuildCache{ try{ - val managedBuildFile = projectDirectory++"/build.scala" + val managedBuildFile = projectDirectory++"build.scala" logger.composition("Loading build at "++managedContext.projectDirectory.toString) ( - if(managedBuildFile.exists){ - val contents = new String(Files.readAllBytes(managedBuildFile.toPath)) + if(Files.exists( managedBuildFile, LinkOption.NOFOLLOW_LINKS ) ){ + val contents = new String(Files.readAllBytes(managedBuildFile)) val cbtUrl = ("cbt:"++GitDependency.GitUrl.regex++"#[a-z0-9A-Z]+").r cbtUrl .findFirstIn(contents) diff --git a/stage2/BuildDependency.scala b/stage2/BuildDependency.scala index c0b53adb..4403e6e8 100644 --- a/stage2/BuildDependency.scala +++ b/stage2/BuildDependency.scala @@ -1,5 +1,6 @@ package cbt -import java.io.File +import java.nio._ +import java.nio.file._ /* sealed abstract class ProjectProxy extends Ha{ protected def delegate: ProjectMetaData @@ -12,7 +13,7 @@ sealed abstract class ProjectProxy extends Ha{ */ trait TriggerLoop extends DependencyImplementation{ final def triggerLoopFilesArray = triggerLoopFiles.toArray - def triggerLoopFiles: Seq[File] + def triggerLoopFiles: Seq[Path] } /** You likely want to use the factory method in the BasicBuild class instead of this. */ case class DirectoryDependency(context: Context) extends TriggerLoop{ diff --git a/stage2/GitDependency.scala b/stage2/GitDependency.scala index 6510ede8..d10b6126 100644 --- a/stage2/GitDependency.scala +++ b/stage2/GitDependency.scala @@ -1,5 +1,7 @@ package cbt import java.io._ +import java.nio._ +import java.nio.file._ import java.net._ import org.eclipse.jgit.api._ import org.eclipse.jgit.lib.Ref @@ -17,17 +19,17 @@ case class GitDependency( // See http://www.codeaffine.com/2014/12/09/jgit-authentication/ private val GitUrl( _, domain, path ) = url - private object checkoutCache extends Cache[File] - def checkout: File = checkoutCache{ - val checkoutDirectory = context.cache ++ s"/git/$domain/$path/$ref" - if(checkoutDirectory.exists){ + private object checkoutCache extends Cache[Path] + def checkout: Path = checkoutCache{ + val checkoutDirectory = context.cache ++ s"git/$domain/$path/$ref" + if(Files.exists( checkoutDirectory, LinkOption.NOFOLLOW_LINKS ) ){ logger.git(s"Found existing checkout of $url#$ref in $checkoutDirectory") } else { logger.git(s"Cloning $url into $checkoutDirectory") val git = Git.cloneRepository() .setURI(url) - .setDirectory(checkoutDirectory) + .setDirectory( new File ( checkoutDirectory.toString ) ) .call() logger.git(s"Checking out ref $ref") @@ -41,7 +43,7 @@ case class GitDependency( def dependency = dependencyCache{ DirectoryDependency( context.copy( - projectDirectory = checkout ++ subDirectory.map("/" ++ _).getOrElse("") + projectDirectory = checkout ++ subDirectory.getOrElse("") ) ) } diff --git a/stage2/Lib.scala b/stage2/Lib.scala index 118c9a40..9d109095 100644 --- a/stage2/Lib.scala +++ b/stage2/Lib.scala @@ -3,7 +3,8 @@ package cbt import java.io._ import java.net._ import java.lang.reflect.InvocationTargetException -import java.nio.file.{Path =>_,_} +import java.nio._ +import java.nio.file._ import java.nio.file.Files.readAllBytes import java.security.MessageDigest import java.util.jar._ @@ -37,9 +38,9 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ */ def loadRoot(context: Context, default: Context => BuildInterface = new BasicBuild(_)): BuildInterface = { context.logger.composition( context.logger.showInvocation("Build.loadRoot",context.projectDirectory) ) - def findStartDir(projectDirectory: File): File = { - val buildDir = realpath( projectDirectory ++ "/build" ) - if(buildDir.exists) findStartDir(buildDir) else projectDirectory + def findStartDir(projectDirectory: Path): Path = { + val buildDir = realpath( projectDirectory ++ "build" ) + if( Files.exists( buildDir, LinkOption.NOFOLLOW_LINKS) ) findStartDir(buildDir) else projectDirectory } val start = findStartDir(context.projectDirectory) @@ -55,16 +56,16 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ } } - def srcJar(sourceFiles: Seq[File], artifactId: String, scalaMajorVersion: String, version: String, jarTarget: File): Option[File] = { + def srcJar(sourceFiles: Seq[Path], artifactId: String, scalaMajorVersion: String, version: String, jarTarget: Path): Option[Path] = { lib.jarFile( - jarTarget ++ ("/"++artifactId++"_"++scalaMajorVersion++"-"++version++"-sources.jar"), + jarTarget ++ (artifactId++"_"++scalaMajorVersion++"-"++version++"-sources.jar"), sourceFiles ) } - def jar(artifactId: String, scalaMajorVersion: String, version: String, compileTarget: File, jarTarget: File): Option[File] = { + def jar(artifactId: String, scalaMajorVersion: String, version: String, compileTarget: Path, jarTarget: Path): Option[Path] = { lib.jarFile( - jarTarget ++ ("/"++artifactId++"_"++scalaMajorVersion++"-"++version++".jar"), + jarTarget ++ ( artifactId++"_"++scalaMajorVersion++"-"++version++".jar"), Seq(compileTarget) ) } @@ -72,21 +73,21 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ def docJar( cbtHasChanged: Boolean, scalaVersion: String, - sourceFiles: Seq[File], + sourceFiles: Seq[Path], dependencyClasspath: ClassPath, - apiTarget: File, - jarTarget: File, + apiTarget: Path, + jarTarget: Path, artifactId: String, scalaMajorVersion: String, version: String, compileArgs: Seq[String], classLoaderCache: ClassLoaderCache, - mavenCache: File - ): Option[File] = { + mavenCache: Path + ): Option[Path] = { if(sourceFiles.isEmpty){ None } else { - apiTarget.mkdirs + Files.createDirectory(apiTarget) val args = Seq( // FIXME: can we use compiler dependency here? "-cp", dependencyClasspath.string, // FIXME: does this break for builds that don't have scalac dependencies? @@ -101,7 +102,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ ) } lib.jarFile( - jarTarget ++ ("/"++artifactId++"_"++scalaMajorVersion++"-"++version++"-javadoc.jar"), + jarTarget ++ ( artifactId++"_"++scalaMajorVersion++"-"++version++"-javadoc.jar" ), Vector(apiTarget) ) } @@ -200,27 +201,27 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ } // file system helpers - def basename(path: File): String = path.toString.stripSuffix("/").split("/").last - def dirname(path: File): File = new File(realpath(path).string.stripSuffix("/").split("/").dropRight(1).mkString("/")) - def nameAndContents(file: File) = basename(file) -> readAllBytes(file.toPath) + def basename(path: Path): String = path.toString.stripSuffix("/").split("/").last + def dirname(path: Path): Path = Paths.get(realpath(path).string.stripSuffix("/").split("/").dropRight(1).mkString("/")) + def nameAndContents(file: Path) = basename(file) -> readAllBytes(file) /** Which file endings to consider being source files. */ - def sourceFileFilter(file: File): Boolean = file.toString.endsWith(".scala") || file.toString.endsWith(".java") + def sourceFileFilter(file: Path): Boolean = file.toString.endsWith(".scala") || file.toString.endsWith(".java") - def sourceFiles( sources: Seq[File], sourceFileFilter: File => Boolean = sourceFileFilter ): Seq[File] = { + def sourceFiles( sources: Seq[Path], sourceFileFilter: Path => Boolean = sourceFileFilter ): Seq[Path] = { for { - base <- sources.filter(_.exists).map(lib.realpath) - file <- lib.listFilesRecursive(base) if file.isFile && sourceFileFilter(file) + base <- sources.filter(f => Files.exists(f) ).map(lib.realpath) + file <- lib.listFilesRecursive(base) if !Files.isDirectory(file) && sourceFileFilter(file) } yield file } - def jarFile( jarFile: File, files: Seq[File], mainClass: Option[String] = None ): Option[File] = { - Files.deleteIfExists(jarFile.toPath) + def jarFile( jarFile: Path, files: Seq[Path], mainClass: Option[String] = None ): Option[Path] = { + Files.deleteIfExists(jarFile) if( files.isEmpty ){ None } else { - jarFile.getParentFile.mkdirs - logger.lib("Start packaging "++jarFile.string) + Files createDirectory jarFile.getParent + logger.lib("Start packaging "++jarFile.toString) val manifest = new Manifest() manifest.getMainAttributes.put(Attributes.Name.MANIFEST_VERSION, "1.0") manifest.getMainAttributes.putValue("Created-By", @@ -228,19 +229,19 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ mainClass foreach { className => manifest.getMainAttributes.put(Attributes.Name.MAIN_CLASS, className) } - val jar = new JarOutputStream(new FileOutputStream(jarFile), manifest) + val jar = new JarOutputStream(Files.newOutputStream(jarFile, StandardOpenOption.READ), manifest) try{ val names = for { - base <- files.filter(_.exists).map(realpath) - file <- listFilesRecursive(base) if file.isFile + base <- files.filter(f => Files.exists(f, LinkOption.NOFOLLOW_LINKS)).map(realpath) + file <- listFilesRecursive(base) if !Files.isDirectory(file) } yield { - val name = if(base.isDirectory){ + val name = if(Files.isDirectory(base)){ file.toString stripPrefix (base.toString ++ File.separator) } else file.toString val entry = new JarEntry( name ) - entry.setTime(file.lastModified) + entry.setTime( Files.getLastModifiedTime(file, LinkOption.NOFOLLOW_LINKS).toMillis ) jar.putNextEntry(entry) - jar.write( readAllBytes( file.toPath ) ) + jar.write( readAllBytes( file ) ) jar.closeEntry() name } @@ -267,7 +268,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ "GPG Passphrase please:" ).mkString - def sign(file: File): File = { + def sign(file: Path): Path = { //http://stackoverflow.com/questions/16662408/correct-way-to-sign-and-verify-signature-using-bouncycastle val statusCode = new ProcessBuilder( "gpg", "--batch", "--yes", "-a", "-b", "-s", "--passphrase", passphrase, file.toString ) @@ -295,8 +296,8 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ inceptionYear: Int, organization: Option[Organization], dependencies: Seq[Dependency], - jarTarget: File - ): File = { + jarTarget: Path + ): Path = { val xml = 4.0.0 @@ -350,7 +351,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ // FIXME: do not build this file name including scalaMajorVersion in multiple places val path = jarTarget.toString ++ ( "/" ++ artifactId++ "_" ++ scalaMajorVersion ++ "-" ++ version ++ ".pom" ) - val file = new File(path) + val file = Paths.get(path) write(file, "\n" ++ xml.toString) } @@ -359,32 +360,32 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ else items.map(projection) } - def publishUnsigned( sourceFiles: Seq[File], artifacts: Seq[File], url: URL, credentials: Option[String] = None ): Unit = { + def publishUnsigned( sourceFiles: Seq[Path], artifacts: Seq[Path], url: URL, credentials: Option[String] = None ): Unit = { if(sourceFiles.nonEmpty){ publish( artifacts, url, credentials ) } } - def publishLocal( sourceFiles: Seq[File], artifacts: Seq[File], mavenCache: File, releaseFolder: String ): Unit = { + def publishLocal( sourceFiles: Seq[Path], artifacts: Seq[Path], mavenCache: Path, releaseFolder: String ): Unit = { if(sourceFiles.nonEmpty){ val targetDir = mavenCache ++ releaseFolder.stripSuffix("/") - targetDir.mkdirs + Files createDirectory targetDir artifacts.foreach{ a => - val target = targetDir ++ ("/" ++ a.getName) - System.err.println(blue("publishing ") ++ target.getPath) - Files.copy( a.toPath, target.toPath, StandardCopyOption.REPLACE_EXISTING ) + val target = targetDir ++ a.getFileName.toString + System.err.println(blue("publishing ") ++ target.toString) + Files.copy( a, target, StandardCopyOption.REPLACE_EXISTING ) } } } - def publishSigned( sourceFiles: Seq[File], artifacts: Seq[File], url: URL, credentials: Option[String] = None ): Unit = { + def publishSigned( sourceFiles: Seq[Path], artifacts: Seq[Path], url: URL, credentials: Option[String] = None ): Unit = { // TODO: make concurrency configurable here if(sourceFiles.nonEmpty){ publish( artifacts ++ artifacts.map(sign), url, credentials ) } } - private def publish(artifacts: Seq[File], url: URL, credentials: Option[String]): Unit = { + private def publish(artifacts: Seq[Path], url: URL, credentials: Option[String]): Unit = { val files = artifacts.map(nameAndContents) lazy val checksums = files.flatMap{ case (name, content) => Seq( @@ -422,7 +423,7 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ // code for continuous compile - def watch(files: Seq[File])(action: PartialFunction[File, Unit]): Unit = { + def watch(files: Seq[Path])(action: PartialFunction[File, Unit]): Unit = { import com.barbarysoftware.watchservice._ import scala.collection.JavaConversions._ val watcher = WatchService.newWatchService @@ -431,10 +432,10 @@ final class Lib(logger: Logger) extends Stage1Lib(logger) with Scaffold{ realFiles.map{ // WatchService can only watch folders - case file if file.isFile => dirname(file) + case file if !( Files isDirectory file ) => dirname(file) case file => file }.distinct.map{ file => - val watchableFile = new WatchableFile(file) + val watchableFile = new WatchableFile( new File ( file.toString ) ) val key = watchableFile.register( watcher, StandardWatchEventKind.ENTRY_CREATE, diff --git a/stage2/PackageJars.scala b/stage2/PackageJars.scala index 05e625bf..febc140c 100644 --- a/stage2/PackageJars.scala +++ b/stage2/PackageJars.scala @@ -1,27 +1,28 @@ package cbt -import java.io.File +import java.nio._ +import java.nio.file._ // would love to call this just `Package` but that conflicts with scala package objects. trait PackageJars extends BaseBuild with ArtifactInfo{ def name: String def artifactId = name def defaultVersion: String final def version = context.version getOrElse defaultVersion - def `package`: Seq[File] = lib.concurrently( enableConcurrency )( + def `package`: Seq[Path] = lib.concurrently( enableConcurrency )( Seq(() => jar, () => docJar, () => srcJar) )( _() ).flatten - private object cacheJarBasicBuild extends Cache[Option[File]] - def jar: Option[File] = cacheJarBasicBuild{ + private object cacheJarBasicBuild extends Cache[Option[Path]] + def jar: Option[Path] = cacheJarBasicBuild{ compile.flatMap( lib.jar( artifactId, scalaMajorVersion, version, _, jarTarget ) ) } - private object cacheSrcJarBasicBuild extends Cache[Option[File]] - def srcJar: Option[File] = cacheSrcJarBasicBuild{ + private object cacheSrcJarBasicBuild extends Cache[Option[Path]] + def srcJar: Option[Path] = cacheSrcJarBasicBuild{ lib.srcJar( sourceFiles, artifactId, scalaMajorVersion, version, scalaTarget ) } - private object cacheDocBasicBuild extends Cache[Option[File]] - def docJar: Option[File] = cacheDocBasicBuild{ + private object cacheDocBasicBuild extends Cache[Option[Path]] + def docJar: Option[Path] = cacheDocBasicBuild{ lib.docJar( context.cbtHasChanged, scalaVersion, sourceFiles, dependencyClasspath, apiTarget, diff --git a/stage2/Publish.scala b/stage2/Publish.scala index 96e856bb..f92ef4b0 100644 --- a/stage2/Publish.scala +++ b/stage2/Publish.scala @@ -1,4 +1,6 @@ package cbt +import java.nio._ +import java.nio.file._ import java.io.File import java.net.URL import java.nio.file.Files.readAllBytes @@ -16,7 +18,7 @@ trait Publish extends PackageJars{ // ========== package ========== /** put additional xml that should go into the POM file in here */ - def pom: File = lib.pom( + def pom: Path = lib.pom( groupId = groupId, artifactId = artifactId, version = version, @@ -43,7 +45,7 @@ trait Publish extends PackageJars{ protected def sonatypeCredentials: Option[String] = { // FIXME: this should probably not use cbtHome, but some reference to the system's host cbt - Some(new String(readAllBytes((context.cbtRootHome ++ "/sonatype.login").toPath)).trim) + Some(new String(readAllBytes((context.cbtRootHome ++ "/sonatype.login"))).trim) } def publishSnapshot: Unit = { diff --git a/stage2/Scaffold.scala b/stage2/Scaffold.scala index 32e474f6..d0da8466 100644 --- a/stage2/Scaffold.scala +++ b/stage2/Scaffold.scala @@ -1,19 +1,20 @@ package cbt import java.io._ +import java.nio._ import java.nio.file._ import java.net._ trait Scaffold{ def logger: Logger - private def createFile( projectDirectory: File, fileName: String, code: String ){ - val outputFile = projectDirectory ++ ("/" ++ fileName) + private def createFile( projectDirectory: Path, fileName: String, code: String ){ + val outputFile = projectDirectory ++ (fileName) Stage0Lib.write( outputFile, code, StandardOpenOption.CREATE_NEW ) import scala.Console._ println( GREEN ++ "Created " ++ fileName ++ RESET ) } def createMain( - projectDirectory: File + projectDirectory: Path ): Unit = { createFile(projectDirectory, "Main.scala", s"""object Main{ def main( args: Array[String] ): Unit = { @@ -25,7 +26,7 @@ trait Scaffold{ } def createBuild( - projectDirectory: File + projectDirectory: Path ): Unit = { createFile(projectDirectory, "build/build.scala", s"""import cbt._ class Build(val context: Context) extends BaseBuild{ diff --git a/stage2/Stage2.scala b/stage2/Stage2.scala index 9ef96faf..e2d70c1d 100644 --- a/stage2/Stage2.scala +++ b/stage2/Stage2.scala @@ -1,5 +1,7 @@ package cbt import java.io._ +import java.nio._ +import java.nio.file._ object Stage2 extends Stage2Base{ def getBuild(__context: java.lang.Object, _cbtChanged: java.lang.Boolean) = { diff --git a/stage2/ToolsTasks.scala b/stage2/ToolsTasks.scala index 2c4978e7..5c392560 100644 --- a/stage2/ToolsTasks.scala +++ b/stage2/ToolsTasks.scala @@ -1,14 +1,15 @@ package cbt import java.net._ import java.io.{Console=>_,_} +import java.nio._ import java.nio.file._ class ToolsTasks( lib: Lib, args: Seq[String], - cwd: File, + cwd: Path, classLoaderCache: ClassLoaderCache, - cache: File, - cbtHome: File, + cache: Path, + cbtHome: Path, cbtHasChanged: Boolean ){ private val paths = CbtPaths(cbtHome, cache) From f3d9341aa40f0d50c15ffe64b9a70ecaaff64947 Mon Sep 17 00:00:00 2001 From: ChavXO Date: Sun, 14 Aug 2016 20:15:19 -0400 Subject: [PATCH 2/2] Added utility methods and updated some examples. --- build/build.scala | 2 +- plugins/sbt_layout/SbtLayout.scala | 4 ++-- plugins/uber-jar/src/UberJar.scala | 14 +++++++------- stage1/CbtPaths.scala | 4 ++-- stage1/ClassPath.scala | 4 ++-- stage1/Stage1.scala | 12 +++++------- stage1/Stage1Lib.scala | 15 ++++++++------- stage1/cbt.scala | 15 +++++++++++---- stage1/resolver.scala | 4 ++-- test/test.scala | 14 +++++++------- 10 files changed, 47 insertions(+), 41 deletions(-) diff --git a/build/build.scala b/build/build.scala index 0dffc8c4..2fbaeb3b 100644 --- a/build/build.scala +++ b/build/build.scala @@ -14,7 +14,7 @@ class Build(val context: Context) extends Publish{ } override def sources = Seq( "nailgun_launcher", "stage1", "stage2", "compatibility" - ).map(d => Path.get( projectDirectory.toString + ("/" + d) ) ) + ).map(d => Paths.get( projectDirectory.toString + ("/" + d) ) ) def groupId: String = "org.cvogt" diff --git a/plugins/sbt_layout/SbtLayout.scala b/plugins/sbt_layout/SbtLayout.scala index 5cd7a032..d342fc2d 100644 --- a/plugins/sbt_layout/SbtLayout.scala +++ b/plugins/sbt_layout/SbtLayout.scala @@ -2,9 +2,9 @@ package cbt trait SbtLayoutTest extends BaseBuild{ override def sources = Seq(projectDirectory ++ "/src/test/scala") - override def compileTarget = super.compileTarget.getParentFile ++ "/test-classes" + override def compileTarget = super.compileTarget.getParent ++ "test-classes" } trait SbtLayoutMain extends BaseBuild{ - override def sources = Seq( projectDirectory ++ "/src/main/scala" ) + override def sources = Seq( projectDirectory ++ "src/main/scala" ) } diff --git a/plugins/uber-jar/src/UberJar.scala b/plugins/uber-jar/src/UberJar.scala index c6815b4c..d54b554c 100644 --- a/plugins/uber-jar/src/UberJar.scala +++ b/plugins/uber-jar/src/UberJar.scala @@ -1,7 +1,7 @@ package cbt import java.io.File -import java.nio.file.{FileSystems, Files, Path} +import java.nio.file._ import java.util.jar.JarFile trait UberJar extends BaseBuild { @@ -35,7 +35,7 @@ class UberJarLib(logger: Logger) { * @param mainClass optional main class * @param jarName name of resulting jar file */ - def create(target: File, + def create(target: Path, classpath: ClassPath, mainClass: Option[String], jarName: String): Unit = { @@ -44,7 +44,7 @@ class UberJarLib(logger: Logger) { log(s"Jar name is: $jarName") mainClass foreach (c => log(s"Main class is is: $c")) - val (jars, dirs) = classpath.files partition (f => jarFileMatcher.matches(f.toPath)) + val (jars, dirs) = classpath.files partition (f => jarFileMatcher.matches(f)) log(s"Found ${jars.length} jar dependencies: \n ${jars mkString "\n"}") log(s"Found ${dirs.length} directories in classpath: \n ${dirs mkString "\n"}") @@ -53,7 +53,7 @@ class UberJarLib(logger: Logger) { log("Extracting jars - DONE") log("Writing jar file...") - val uberJarPath = target.toPath.resolve(jarName) + val uberJarPath = target.resolve(jarName) val uberJar = lib.jarFile(uberJarPath.toFile, dirs :+ extractedJarsRoot, mainClass) getOrElse { throw new Exception("Jar file wasn't created!") } @@ -90,9 +90,9 @@ class UberJarLib(logger: Logger) { * @param destDir destination directory * @param log logger */ - private def extractJar(jarFile: File, destDir: Path)(log: String => Unit): Unit = { + private def extractJar(jarFile: Path, destDir: Path)(log: String => Unit): Unit = { log(s"Extracting jar: $jarFile") - val jar = new JarFile(jarFile) + val jar = new JarFile( new File ( jarFile.string ) ) val enumEntries = jar.entries while (enumEntries.hasMoreElements) { val entry = enumEntries.nextElement() @@ -101,7 +101,7 @@ class UberJarLib(logger: Logger) { if (excludeFileMatcher.matches(entryPath)) { log(s"Excluded file ${entryPath.getFileName} from jar: $jarFile") } else { - val exists = Files.exists(entryPath) + val exists = entryPath.exists if (entry.isDirectory) { if (!exists) { Files.createDirectory(entryPath) diff --git a/stage1/CbtPaths.scala b/stage1/CbtPaths.scala index 1c338646..24a88711 100644 --- a/stage1/CbtPaths.scala +++ b/stage1/CbtPaths.scala @@ -1,7 +1,7 @@ package cbt import java.nio.file._ case class CbtPaths(private val cbtHome: Path, private val cache: Path){ - val userHome: Path = Paths.get(Option(System.getProperty("user.home")).get) + val userHome: Path = FileSystems.getDefault().getPath(Option(System.getProperty("user.home")).get) val nailgun: Path = cbtHome ++ "nailgun_launcher" val stage1: Path = cbtHome ++ "stage1" val stage2: Path = cbtHome ++ "stage2" @@ -9,7 +9,7 @@ case class CbtPaths(private val cbtHome: Path, private val cache: Path){ private val target = NailgunLauncher.TARGET.stripSuffix("/") val stage1Target: Path = stage1 ++ target val stage2Target: Path = stage2 ++ target - val stage2StatusFile: Path = Paths.get(stage2Target.toString.stripSuffix("/") + ".last-success") + val stage2StatusFile: Path = FileSystems.getDefault().getPath(stage2Target.toString.stripSuffix("/") + ".last-success") val compatibility: Path = cbtHome ++ "compatibility" val nailgunTarget: Path = nailgun ++ target } diff --git a/stage1/ClassPath.scala b/stage1/ClassPath.scala index 99bb8fbf..9c461f24 100644 --- a/stage1/ClassPath.scala +++ b/stage1/ClassPath.scala @@ -13,7 +13,7 @@ case class ClassPath(files: Seq[Path] = Seq()){ duplicates.isEmpty, "Duplicate classpath entries found:\n" ++ duplicates.mkString("\n") ++ "\nin classpath:\n"++string ) - private val nonExisting = files.distinct.filterNot(f => Files.exists(f, LinkOption.NOFOLLOW_LINKS) ) + private val nonExisting = files.distinct.filterNot( _.exists ) assert( nonExisting.isEmpty, "Classpath contains entires that don't exist on disk:\n" ++ nonExisting.mkString("\n") ++ "\nin classpath:\n"++string @@ -24,7 +24,7 @@ case class ClassPath(files: Seq[Path] = Seq()){ def ++(other: ClassPath) = ClassPath(files ++ other.files) def string = strings.mkString( File.pathSeparator ) def strings = files.map{ - f => f.toString ++ ( if( Files.isDirectory ( f, LinkOption.NOFOLLOW_LINKS ) ) "/" else "" ) + f => f.toString ++ ( if( f.isDirectory ) "/" else "" ) }.sorted def toConsole = string } diff --git a/stage1/Stage1.scala b/stage1/Stage1.scala index b1ad227c..27a894ba 100644 --- a/stage1/Stage1.scala +++ b/stage1/Stage1.scala @@ -54,10 +54,8 @@ case class Stage2Args( ) = classLoaderCache } object Stage1{ - protected def newerThan( a: Path, b: Path ) ={ - val t1 = Files.getLastModifiedTime(a, LinkOption.NOFOLLOW_LINKS ) - val t2 = Files.getLastModifiedTime(b, LinkOption.NOFOLLOW_LINKS ) - t1.compareTo(t2) > 0 + protected def newerThan( a: Path, b: Path ) = { + a.lastModified.compareTo(b.lastModified) > 0 } def getBuild( _context: java.lang.Object, _cbtChanged: java.lang.Boolean ) = { @@ -93,9 +91,9 @@ object Stage1{ import scala.collection.JavaConverters val stage2sourceFiles = ( - Files.newDirectoryStream(stage2).iterator.asScala.toSeq ++ - Files.newDirectoryStream(stage2 ++ "plugins").iterator.asScala.toSeq - ).toVector.filter( path => !Files.isDirectory(path, LinkOption.NOFOLLOW_LINKS) ).filter(_.toString.endsWith(".scala") ) + stage2.listFiles ++ + (stage2 ++ "plugins").listFiles + ).toVector.filter( _.isFile ).filter(_.toString.endsWith(".scala") ) val cbtHasChanged = _cbtChanged || lib.needsUpdate(stage2sourceFiles, stage2StatusFile) diff --git a/stage1/Stage1Lib.scala b/stage1/Stage1Lib.scala index 4bec260a..5d04b838 100644 --- a/stage1/Stage1Lib.scala +++ b/stage1/Stage1Lib.scala @@ -57,11 +57,12 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ def write(file: Path, content: String, options: OpenOption*): Path = Stage0Lib.write(file, content, options:_*) def download(url: URL, target: Path, sha1: Option[String]): Boolean = { - if( Files.exists(target, LinkOption.NOFOLLOW_LINKS) ){ + if( target.exists ){ logger.resolver(green("found ") ++ url.string) true } else { - val incomplete = ( target ++ ".incomplete" ) + val incomplete = ( FileSystems.getDefault().getPath( target.string ++ ".incomplete" ) ) + println(url) val connection = Stage0Lib.openConnectionConsideringProxy(url) if(connection.getResponseCode != HttpURLConnection.HTTP_OK){ logger.resolver(blue("not found: ") ++ url.string) @@ -91,8 +92,8 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ def listFilesRecursive(f: Path): Seq[Path] = { f +: ( - if( Files.isDirectory(f, LinkOption.NOFOLLOW_LINKS) ) - Files.newDirectoryStream(f).iterator.asScala.toSeq.flatMap(file => listFilesRecursive(file) ).toVector + if( f.isDirectory ) + f.listFiles.flatMap(file => listFilesRecursive(file) ).toVector else Seq[Path]() ) } @@ -129,8 +130,8 @@ class Stage1Lib( val logger: Logger ) extends BaseLib{ def needsUpdate( sourceFiles: Seq[Path], statusFile: Path ) = { try { - val lastCompile = Files.getLastModifiedTime(statusFile, LinkOption.NOFOLLOW_LINKS ) - sourceFiles.filter(f => (Files.getLastModifiedTime(f, LinkOption.NOFOLLOW_LINKS ) compareTo lastCompile) > 0).nonEmpty + val lastCompile = statusFile.lastModified + sourceFiles.filter(f => ( f.lastModified compareTo lastCompile) > 0).nonEmpty } catch { case e: Throwable => true } @@ -283,7 +284,7 @@ ${files.sorted.mkString(" \\\n")} ( deserialize: String => T ) ( serialize: T => String ) ( compute: => Seq[T] ) = { - if(!cbtHasChanged && Files.exists(cacheFile, LinkOption.NOFOLLOW_LINKS) ){ + if(!cbtHasChanged && cacheFile.exists ){ import collection.JavaConversions._ Files .readAllLines( cacheFile, StandardCharsets.UTF_8 ) diff --git a/stage1/cbt.scala b/stage1/cbt.scala index 17796d84..066b9547 100644 --- a/stage1/cbt.scala +++ b/stage1/cbt.scala @@ -5,6 +5,8 @@ import java.nio.file._ import java.net._ import java.util.concurrent.ConcurrentHashMap +import scala.collection.JavaConverters._ + object `package`{ val mavenCentral = new URL("https://repo1.maven.org/maven2") val jcenter = new URL("https://jcenter.bintray.com") @@ -14,15 +16,20 @@ object `package`{ val sonatypeSnapshots = sonatypeBase ++ "snapshots" private val lib = new BaseLib - implicit class FileExtensionMethods( file: Path ){ + implicit class FileExtensionMethods( path: Path ){ def ++( s: String ): Path = { if(s endsWith "/") throw new Exception( """Trying to append a String that ends in "/" to a File would loose the trailing "/". Use .stripSuffix("/") if you need to.""" ) - Paths.get( file.toString ++ java.io.File.separator ++ s ) + Paths.get( path.toString ++ java.io.File.separator ++ s ) } - def parent = lib.realpath(file ++ "/..") - def string = file.toString + def parent = path.getParent + def string = path.toString + def lastModified = Files.getLastModifiedTime( path, LinkOption.NOFOLLOW_LINKS ) + def exists = Files.exists( path, LinkOption.NOFOLLOW_LINKS ) + def isDirectory = Files.isDirectory( path, LinkOption.NOFOLLOW_LINKS ) + def isFile = !isDirectory + def listFiles = Files.newDirectoryStream(path).iterator.asScala.toSeq } implicit class URLExtensionMethods( url: URL ){ def ++( s: String ): URL = new URL( url.toString ++ s ) diff --git a/stage1/resolver.scala b/stage1/resolver.scala index 1cd090c2..5f5f5057 100644 --- a/stage1/resolver.scala +++ b/stage1/resolver.scala @@ -231,8 +231,8 @@ case class BoundMavenDependency( private def resolve(suffix: String, hash: Option[String]): Path = { logger.resolver("Resolving "+this) - val file = Paths.get( mavenCache + basePath + "." + suffix ) - val urls = repositories.map(f => Paths.get( f.toString + basePath.toString + "." + suffix).toUri.toURL ) + val file = FileSystems.getDefault().getPath( mavenCache + basePath + "." + suffix ) + val urls = repositories.map( _ ++ basePath ++ "." ++ suffix ) urls.find( lib.download(_, file, hash) ).getOrElse( diff --git a/test/test.scala b/test/test.scala index 92d4abf1..a6c44800 100644 --- a/test/test.scala +++ b/test/test.scala @@ -1,6 +1,6 @@ import cbt._ import java.util.concurrent.ConcurrentHashMap -import java.io.File +import java.nio.file._ import java.net.URL // micro framework @@ -10,7 +10,7 @@ object Main{ val args = new Stage1ArgsParser(_args.toVector) implicit val logger: Logger = new Logger(args.enabledLoggers, System.currentTimeMillis) val lib = new Lib(logger) - val cbtHome = new File(System.getenv("CBT_HOME")) + val cbtHome = FileSystems.getDefault().getPath(System.getenv("CBT_HOME")) var successes = 0 var failures = 0 @@ -39,7 +39,7 @@ object Main{ val allArgs: Seq[String] = ((cbtHome.string ++ "/cbt") +: "direct" +: (_args ++ args.propsRaw)) logger.test(allArgs.toString) val pb = new ProcessBuilder( allArgs :_* ) - pb.directory(cbtHome ++ ("/test/" ++ path)) + pb.directory( new File ( ( cbtHome ++ ("/test/" ++ path) ).string ) ) val p = pb.start val berr = new BufferedReader(new InputStreamReader(p.getErrorStream)); val bout = new BufferedReader(new InputStreamReader(p.getInputStream)); @@ -74,8 +74,8 @@ object Main{ logger.test( "Running tests " ++ _args.toList.toString ) - val cache = cbtHome ++ "/cache" - val mavenCache = cache ++ "/maven" + val cache = cbtHome ++ "cache" + val mavenCache = cache ++ "maven" val cbtHasChanged = true def Resolver(urls: URL*) = MavenResolver(cbtHasChanged, mavenCache, urls: _*) @@ -94,7 +94,7 @@ object Main{ cache, cbtHome, cbtHome, - cbtHome ++ "/compatibilityTarget", + cbtHome ++ "compatibilityTarget", null ) @@ -145,7 +145,7 @@ object Main{ ) ).classpath.strings ).foreach{ - path => assert(new File(path).exists, path) + path => assert(FileSystems.getDefault().getPath(path).exists, path) } usage("nothing")