Skip to content

Commit 17a51c8

Browse files
brkyvzJoshRosen
authored andcommitted
[SPARK-7224] [SPARK-7306] mock repository generator for --packages tests without nio.Path
The previous PR for SPARK-7224 (#5790) broke JDK 6, because it used java.nio.Path, which was in jdk 7, and not in 6. This PR uses Guava's `Files` to handle directory creation, and etc... The description from the previous PR: > This patch contains an `IvyTestUtils` file, which dynamically generates jars and pom files to test the `--packages` feature without having to rely on the internet, and Maven Central. cc pwendell I also rand the flaky test about 20 times locally, it didn't fail a single time, but I think it may fail like once every 100 builds? I still haven't figured the cause yet, but the test before it, `--jars` was also failing after we turned off the `--packages` test in `SparkSubmitSuite`. It may be related to the launch of SparkSubmit. Author: Burak Yavuz <[email protected]> Closes #5892 from brkyvz/maven-utils and squashes the following commits: e9b1903 [Burak Yavuz] fix merge conflict 68214e0 [Burak Yavuz] remove ignore for test(neglect spark dependencies) e632381 [Burak Yavuz] fix ignore 9ef1408 [Burak Yavuz] re-enable --packages test 22eea62 [Burak Yavuz] Merge branch 'master' of github.com:apache/spark into maven-utils 05cd0de [Burak Yavuz] added mock repository generator (cherry picked from commit 8014e1f) Signed-off-by: Josh Rosen <[email protected]>
1 parent 130ec21 commit 17a51c8

File tree

5 files changed

+404
-100
lines changed

5 files changed

+404
-100
lines changed

core/src/main/scala/org/apache/spark/TestUtils.scala

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -105,23 +105,18 @@ private[spark] object TestUtils {
105105
URI.create(s"string:///${name.replace(".", "/")}${SOURCE.extension}")
106106
}
107107

108-
private class JavaSourceFromString(val name: String, val code: String)
108+
private[spark] class JavaSourceFromString(val name: String, val code: String)
109109
extends SimpleJavaFileObject(createURI(name), SOURCE) {
110110
override def getCharContent(ignoreEncodingErrors: Boolean): String = code
111111
}
112112

113-
/** Creates a compiled class with the given name. Class file will be placed in destDir. */
113+
/** Creates a compiled class with the source file. Class file will be placed in destDir. */
114114
def createCompiledClass(
115115
className: String,
116116
destDir: File,
117-
toStringValue: String = "",
118-
baseClass: String = null,
119-
classpathUrls: Seq[URL] = Seq()): File = {
117+
sourceFile: JavaSourceFromString,
118+
classpathUrls: Seq[URL]): File = {
120119
val compiler = ToolProvider.getSystemJavaCompiler
121-
val extendsText = Option(baseClass).map { c => s" extends ${c}" }.getOrElse("")
122-
val sourceFile = new JavaSourceFromString(className,
123-
"public class " + className + extendsText + " implements java.io.Serializable {" +
124-
" @Override public String toString() { return \"" + toStringValue + "\"; }}")
125120

126121
// Calling this outputs a class file in pwd. It's easier to just rename the file than
127122
// build a custom FileManager that controls the output location.
@@ -144,4 +139,18 @@ private[spark] object TestUtils {
144139
assert(out.exists(), "Destination file not moved: " + out.getAbsolutePath())
145140
out
146141
}
142+
143+
/** Creates a compiled class with the given name. Class file will be placed in destDir. */
144+
def createCompiledClass(
145+
className: String,
146+
destDir: File,
147+
toStringValue: String = "",
148+
baseClass: String = null,
149+
classpathUrls: Seq[URL] = Seq()): File = {
150+
val extendsText = Option(baseClass).map { c => s" extends ${c}" }.getOrElse("")
151+
val sourceFile = new JavaSourceFromString(className,
152+
"public class " + className + extendsText + " implements java.io.Serializable {" +
153+
" @Override public String toString() { return \"" + toStringValue + "\"; }}")
154+
createCompiledClass(className, destDir, sourceFile, classpathUrls)
155+
}
147156
}

core/src/main/scala/org/apache/spark/deploy/SparkSubmit.scala

Lines changed: 68 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -753,7 +753,9 @@ private[spark] object SparkSubmitUtils {
753753
* @param artifactId the artifactId of the coordinate
754754
* @param version the version of the coordinate
755755
*/
756-
private[deploy] case class MavenCoordinate(groupId: String, artifactId: String, version: String)
756+
private[deploy] case class MavenCoordinate(groupId: String, artifactId: String, version: String) {
757+
override def toString: String = s"$groupId:$artifactId:$version"
758+
}
757759

758760
/**
759761
* Extracts maven coordinates from a comma-delimited string. Coordinates should be provided
@@ -776,6 +778,10 @@ private[spark] object SparkSubmitUtils {
776778
}
777779
}
778780

781+
/** Path of the local Maven cache. */
782+
private[spark] def m2Path: File = new File(System.getProperty("user.home"),
783+
".m2" + File.separator + "repository" + File.separator)
784+
779785
/**
780786
* Extracts maven coordinates from a comma-delimited string
781787
* @param remoteRepos Comma-delimited string of remote repositories
@@ -789,8 +795,7 @@ private[spark] object SparkSubmitUtils {
789795

790796
val localM2 = new IBiblioResolver
791797
localM2.setM2compatible(true)
792-
val m2Path = ".m2" + File.separator + "repository" + File.separator
793-
localM2.setRoot(new File(System.getProperty("user.home"), m2Path).toURI.toString)
798+
localM2.setRoot(m2Path.toURI.toString)
794799
localM2.setUsepoms(true)
795800
localM2.setName("local-m2-cache")
796801
cr.add(localM2)
@@ -915,69 +920,72 @@ private[spark] object SparkSubmitUtils {
915920
""
916921
} else {
917922
val sysOut = System.out
918-
// To prevent ivy from logging to system out
919-
System.setOut(printStream)
920-
val artifacts = extractMavenCoordinates(coordinates)
921-
// Default configuration name for ivy
922-
val ivyConfName = "default"
923-
// set ivy settings for location of cache
924-
val ivySettings: IvySettings = new IvySettings
925-
// Directories for caching downloads through ivy and storing the jars when maven coordinates
926-
// are supplied to spark-submit
927-
val alternateIvyCache = ivyPath.getOrElse("")
928-
val packagesDirectory: File =
929-
if (alternateIvyCache.trim.isEmpty) {
930-
new File(ivySettings.getDefaultIvyUserDir, "jars")
923+
try {
924+
// To prevent ivy from logging to system out
925+
System.setOut(printStream)
926+
val artifacts = extractMavenCoordinates(coordinates)
927+
// Default configuration name for ivy
928+
val ivyConfName = "default"
929+
// set ivy settings for location of cache
930+
val ivySettings: IvySettings = new IvySettings
931+
// Directories for caching downloads through ivy and storing the jars when maven coordinates
932+
// are supplied to spark-submit
933+
val alternateIvyCache = ivyPath.getOrElse("")
934+
val packagesDirectory: File =
935+
if (alternateIvyCache.trim.isEmpty) {
936+
new File(ivySettings.getDefaultIvyUserDir, "jars")
937+
} else {
938+
ivySettings.setDefaultIvyUserDir(new File(alternateIvyCache))
939+
ivySettings.setDefaultCache(new File(alternateIvyCache, "cache"))
940+
new File(alternateIvyCache, "jars")
941+
}
942+
printStream.println(
943+
s"Ivy Default Cache set to: ${ivySettings.getDefaultCache.getAbsolutePath}")
944+
printStream.println(s"The jars for the packages stored in: $packagesDirectory")
945+
// create a pattern matcher
946+
ivySettings.addMatcher(new GlobPatternMatcher)
947+
// create the dependency resolvers
948+
val repoResolver = createRepoResolvers(remoteRepos, ivySettings)
949+
ivySettings.addResolver(repoResolver)
950+
ivySettings.setDefaultResolver(repoResolver.getName)
951+
952+
val ivy = Ivy.newInstance(ivySettings)
953+
// Set resolve options to download transitive dependencies as well
954+
val resolveOptions = new ResolveOptions
955+
resolveOptions.setTransitive(true)
956+
val retrieveOptions = new RetrieveOptions
957+
// Turn downloading and logging off for testing
958+
if (isTest) {
959+
resolveOptions.setDownload(false)
960+
resolveOptions.setLog(LogOptions.LOG_QUIET)
961+
retrieveOptions.setLog(LogOptions.LOG_QUIET)
931962
} else {
932-
ivySettings.setDefaultIvyUserDir(new File(alternateIvyCache))
933-
ivySettings.setDefaultCache(new File(alternateIvyCache, "cache"))
934-
new File(alternateIvyCache, "jars")
963+
resolveOptions.setDownload(true)
935964
}
936-
printStream.println(
937-
s"Ivy Default Cache set to: ${ivySettings.getDefaultCache.getAbsolutePath}")
938-
printStream.println(s"The jars for the packages stored in: $packagesDirectory")
939-
// create a pattern matcher
940-
ivySettings.addMatcher(new GlobPatternMatcher)
941-
// create the dependency resolvers
942-
val repoResolver = createRepoResolvers(remoteRepos, ivySettings)
943-
ivySettings.addResolver(repoResolver)
944-
ivySettings.setDefaultResolver(repoResolver.getName)
945-
946-
val ivy = Ivy.newInstance(ivySettings)
947-
// Set resolve options to download transitive dependencies as well
948-
val resolveOptions = new ResolveOptions
949-
resolveOptions.setTransitive(true)
950-
val retrieveOptions = new RetrieveOptions
951-
// Turn downloading and logging off for testing
952-
if (isTest) {
953-
resolveOptions.setDownload(false)
954-
resolveOptions.setLog(LogOptions.LOG_QUIET)
955-
retrieveOptions.setLog(LogOptions.LOG_QUIET)
956-
} else {
957-
resolveOptions.setDownload(true)
958-
}
959965

960-
// A Module descriptor must be specified. Entries are dummy strings
961-
val md = getModuleDescriptor
962-
md.setDefaultConf(ivyConfName)
966+
// A Module descriptor must be specified. Entries are dummy strings
967+
val md = getModuleDescriptor
968+
md.setDefaultConf(ivyConfName)
963969

964-
// Add exclusion rules for Spark and Scala Library
965-
addExclusionRules(ivySettings, ivyConfName, md)
966-
// add all supplied maven artifacts as dependencies
967-
addDependenciesToIvy(md, artifacts, ivyConfName)
970+
// Add exclusion rules for Spark and Scala Library
971+
addExclusionRules(ivySettings, ivyConfName, md)
972+
// add all supplied maven artifacts as dependencies
973+
addDependenciesToIvy(md, artifacts, ivyConfName)
968974

969-
// resolve dependencies
970-
val rr: ResolveReport = ivy.resolve(md, resolveOptions)
971-
if (rr.hasError) {
972-
throw new RuntimeException(rr.getAllProblemMessages.toString)
975+
// resolve dependencies
976+
val rr: ResolveReport = ivy.resolve(md, resolveOptions)
977+
if (rr.hasError) {
978+
throw new RuntimeException(rr.getAllProblemMessages.toString)
979+
}
980+
// retrieve all resolved dependencies
981+
ivy.retrieve(rr.getModuleDescriptor.getModuleRevisionId,
982+
packagesDirectory.getAbsolutePath + File.separator +
983+
"[organization]_[artifact]-[revision].[ext]",
984+
retrieveOptions.setConfs(Array(ivyConfName)))
985+
resolveDependencyPaths(rr.getArtifacts.toArray, packagesDirectory)
986+
} finally {
987+
System.setOut(sysOut)
973988
}
974-
// retrieve all resolved dependencies
975-
ivy.retrieve(rr.getModuleDescriptor.getModuleRevisionId,
976-
packagesDirectory.getAbsolutePath + File.separator +
977-
"[organization]_[artifact]-[revision].[ext]",
978-
retrieveOptions.setConfs(Array(ivyConfName)))
979-
System.setOut(sysOut)
980-
resolveDependencyPaths(rr.getArtifacts.toArray, packagesDirectory)
981989
}
982990
}
983991
}

0 commit comments

Comments
 (0)