Skip to content

Commit

Permalink
Autodetect package name for nested directory destinations (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
liucijus authored Dec 15, 2023
1 parent e745385 commit 31b6d46
Show file tree
Hide file tree
Showing 15 changed files with 95 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ abstract class SynchronizerCli {
mavenResolver,
localPath,
config.destination,
config.destinationPackage,
storage,
managedDeps,
config.importExternalLoadStatement
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.wix.build.sync.cli

import com.wix.build.bazel.ImportExternalLoadStatement
import com.wix.build.bazel.{DestinationPackage, ImportExternalLoadStatement}
import scopt.OptionParser

object ManagedDepsSynchronizerConfig extends SynchronizerConfigParser
Expand All @@ -15,7 +15,9 @@ case class ManagedDepsSynchronizerConfig(pathToArtifactsFile: String,
pollingMaxAttempts: Int,
millisBetweenPollings: Int,
cacheChecksums: Boolean,
importExternalLoadStatement: ImportExternalLoadStatement)
importExternalLoadStatement: ImportExternalLoadStatement) {
val destinationPackage: DestinationPackage = DestinationPackage.resolveFromDestination(destination)
}

abstract class SynchronizerConfigParser {
val defaultConfiguration = ManagedDepsSynchronizerConfig(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ import java.nio.file.{Files, Paths}

//noinspection TypeAnnotation
class FileSystemBazelLocalWorkspaceIT extends SpecificationWithJUnit {
private val destination = "third_party"
val thirdPartyPaths = new ThirdPartyPaths(destination, DestinationPackage.resolveFromDestination(destination))

"FileSystemBazelLocalWorkspace" should {
"throw exception when given filepath does not exist" in {
val nonExistingPath = Paths.get("/not-very-likely-to-exists-path")

new FileSystemBazelLocalWorkspace(nonExistingPath.toFile, new ThirdPartyPaths("third_party")) must throwA[FileNotFoundException]
new FileSystemBazelLocalWorkspace(nonExistingPath.toFile, thirdPartyPaths) must throwA[FileNotFoundException]
}

"return initial skeleton for third party repos content if third party repos file does not exists" in new blankWorkspaceCtx {
new FileSystemBazelLocalWorkspace(blankWorkspaceRootPath, new ThirdPartyPaths("third_party")).thirdPartyReposFileContent() mustEqual "def dependencies():"
new FileSystemBazelLocalWorkspace(blankWorkspaceRootPath, thirdPartyPaths).thirdPartyReposFileContent() mustEqual "def dependencies():"
}

"Get third party repos file content" in new blankWorkspaceCtx {
Expand Down Expand Up @@ -212,6 +215,10 @@ class FileSystemBazelLocalWorkspaceIT extends SpecificationWithJUnit {
}

private def aFileSystemBazelLocalWorkspace(on: File) = {
new FileSystemBazelLocalWorkspace(on, new ThirdPartyPaths("third_party"))
val destination = "third_party"
new FileSystemBazelLocalWorkspace(
on,
new ThirdPartyPaths(destination, DestinationPackage.resolveFromDestination(destination))
)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.wix.build.sync.e2e

import com.wix.build.bazel.{ImportExternalTargetsFileReader, ThirdPartyPaths}
import com.wix.build.bazel.{DestinationPackage, ImportExternalTargetsFileReader, ThirdPartyPaths}
import com.wix.build.maven.Coordinates
import com.wix.build.translation.MavenToBazelTranslations._
import org.eclipse.jgit.api.Git
Expand All @@ -12,7 +12,8 @@ import java.nio.file.{Files, Paths}
import scala.util.Try

class FakeRemoteRepository() {
val thirdPartyPaths = new ThirdPartyPaths("third_party")
private val destination = "third_party"
val thirdPartyPaths = new ThirdPartyPaths(destination, DestinationPackage.resolveFromDestination(destination))

import thirdPartyPaths._

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ class BazelDependenciesWriter(localWorkspace: BazelLocalWorkspace,
val actual = dependencyNodes.toList.sortBy(_.baseDependency.coordinates.workspaceRuleName)
val existingThirdPartyReposFile = localWorkspace.thirdPartyReposFileContent()
val thirdPartyReposBuilder = actual.map(_.baseDependency.coordinates)
.foldLeft(ThirdPartyReposFile.Builder(existingThirdPartyReposFile))(_.fromCoordinates(_, thirdPartyPaths.thirdPartyImportFilesPathRoot))
.foldLeft(ThirdPartyReposFile.Builder(existingThirdPartyReposFile))(_.fromCoordinates(_, thirdPartyPaths.destinationPackage))

val thirdPartyReposBuilderWithDeletions = noLongerUsedGroupIds.foldLeft(thirdPartyReposBuilder)(_.removeGroupIds(_, thirdPartyPaths.thirdPartyImportFilesPathRoot))
val thirdPartyReposBuilderWithDeletions = noLongerUsedGroupIds
.foldLeft(thirdPartyReposBuilder)(_.removeGroupIds(_, thirdPartyPaths.destinationPackage))
val content = thirdPartyReposBuilderWithDeletions.content

val nonEmptyContent = Option(content).filter(_.trim.nonEmpty).fold(" pass")(c => c)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ trait BazelLocalWorkspace {

def allThirdPartyFileLoadedGroups(): Set[String] = {
val thirdPartyLoadStatementPattern = (
"""^load\("//:""" + thirdPartyPaths.thirdPartyImportFilesPathRoot + """/([_a-zA-Z]+)\.bzl", [_a-zA-Z]+_deps = "dependencies"\)"""
"""^load\("""" + thirdPartyPaths.destinationPackage.bazelPackage + """/([_a-zA-Z]+)\.bzl", [_a-zA-Z]+_deps = "dependencies"\)"""
).r

thirdPartyReposFileContent().split("\n").collect {
Expand All @@ -53,9 +53,21 @@ trait BazelLocalWorkspace {

}

class ThirdPartyPaths(destination: String) {
class ThirdPartyPaths(destination: String, val destinationPackage: DestinationPackage) {
val thirdPartyReposFilePath: String = s"$destination.bzl"
val receiptPath: String = s"$destination-receipt.txt"
val thirdPartyImportFilesPathRoot: String = s"$destination"
val localArtifactOverridesFilePath: String = s"$destination/maven/local_artifact_overrides.bzl"
}

case class DestinationPackage(bazelPackage: String)

object DestinationPackage {
def resolveFromDestination(destination: String): DestinationPackage = {
val packagePath = s"/${destination}"
val lastIndexOfSlash = packagePath.lastIndexOf("/")
val parts = packagePath.splitAt(lastIndexOfSlash)
val thirdPartyPackage = s"//${parts._1.stripPrefix("/")}:${parts._2.stripPrefix("/")}"
DestinationPackage(thirdPartyPackage)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import java.io.File
class NoPersistenceBazelRepository(local: File, thirdPartyDestination: String) extends BazelRepository {

override def resetAndCheckoutMaster(): BazelLocalWorkspace =
new FileSystemBazelLocalWorkspace(local, new ThirdPartyPaths(thirdPartyDestination))
new FileSystemBazelLocalWorkspace(
local,
new ThirdPartyPaths(thirdPartyDestination, DestinationPackage.resolveFromDestination(thirdPartyDestination))
)

override def persist(branchName: String, message: String): Unit = ()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,18 @@ import scala.util.matching.Regex
object ThirdPartyReposFile {

case class Builder(content: String = "") {
def fromCoordinates(coordinates: Coordinates, thirdPartyPath: String): Builder = {
def fromCoordinates(coordinates: Coordinates, destinationPackage: DestinationPackage): Builder = {
coordinates.packaging match {
case Packaging("jar") => withLoadStatementsFor(coordinates, thirdPartyPath)
case Packaging("jar") => withLoadStatementsFor(coordinates, destinationPackage)
case Packaging("war") => unchangedBuilder
case _ => withMavenArtifact(coordinates)
}
}

def removeGroupIds(groupIdForBazel: String, thirdPartyPath: String): Builder = {
def removeGroupIds(groupIdForBazel: String, destinationPackage: DestinationPackage): Builder = {
import NewLinesParser.removeMatched

val contentWithoutLoadStatement = regexOfLoadRuleWithNameMatching(groupIdForBazel, thirdPartyPath)
val contentWithoutLoadStatement = regexOfLoadRuleWithNameMatching(groupIdForBazel, destinationPackage)
.findFirstMatchIn(content) match {
case Some(m) => removeMatched(content, m)
case None => content
Expand All @@ -34,17 +34,17 @@ object ThirdPartyReposFile {
Builder(contentWithoutMethodCall)
}

def withLoadStatementsFor(coordinates: Coordinates, thirdPartyPath: String): Builder = {
val updatedContent = regexOfLoadRuleWithNameMatching(coordinates.groupIdForBazel, thirdPartyPath)
def withLoadStatementsFor(coordinates: Coordinates, destinationPackage: DestinationPackage): Builder = {
val updatedContent = regexOfLoadRuleWithNameMatching(coordinates.groupIdForBazel, destinationPackage)
.findFirstMatchIn(content) match {
case None => appendLoadStatements(content, coordinates, thirdPartyPath)
case None => appendLoadStatements(content, coordinates, destinationPackage)
case _ => content
}
Builder(updatedContent)
}

private def appendLoadStatements(thirdPartyRepos: String, coordinates: Coordinates, thirdPartyPath: String): String = {
s"""${serializedLoadImportExternalTargetsFile(coordinates, thirdPartyPath)}
private def appendLoadStatements(thirdPartyRepos: String, coordinates: Coordinates, destinationPackage: DestinationPackage): String = {
s"""${serializedLoadImportExternalTargetsFile(coordinates, destinationPackage)}
|
|${thirdPartyRepos.stripLineEnd}
|
Expand Down Expand Up @@ -80,9 +80,9 @@ object ThirdPartyReposFile {

}

def serializedLoadImportExternalTargetsFile(fromCoordinates: Coordinates, thirdPartyPath: String): String = {
def serializedLoadImportExternalTargetsFile(fromCoordinates: Coordinates, destinationPackage: DestinationPackage): String = {
val groupId = fromCoordinates.groupIdForBazel
s"""load("//:$thirdPartyPath/${groupId}.bzl", ${groupId}_deps = "dependencies")"""
s"""load("${destinationPackage.bazelPackage}/${groupId}.bzl", ${groupId}_deps = "dependencies")"""
}

def serializedImportExternalTargetsFileMethodCall(fromCoordinates: Coordinates): String = {
Expand Down Expand Up @@ -114,8 +114,8 @@ object ThirdPartyReposFile {
("""(?s)if native\.existing_rule\("""" + pattern + """"\) == None:\s*?[^\s]+"""
+ """\(\s*?name\s*?=\s*?"""" + pattern + """",[\s#]*?artifact.*?\)""").r

private def regexOfLoadRuleWithNameMatching(pattern: String, thirdPartyPath: String) =
("""(?s)load\("//:""" + thirdPartyPath + """/""" + pattern + """.bzl", """ + pattern + """_deps = "dependencies"\)""").r
private def regexOfLoadRuleWithNameMatching(pattern: String, destinationPackage: DestinationPackage) =
("""(?s)load\("""" + destinationPackage.bazelPackage + """/""" + pattern + """.bzl", """ + pattern + """_deps = "dependencies"\)""").r

private def regexOfImportExternalTargetsFileMethodCall(groupIdForBazel: String) = {
(s" ${groupIdForBazel}_deps\\(\\)").r
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.wix.build.sync.core

import com.wix.build.bazel.{BazelDependenciesWriter, FileSystemBazelLocalWorkspace, ImportExternalLoadStatement, ThirdPartyPaths}
import com.wix.build.bazel.{BazelDependenciesWriter, DestinationPackage, FileSystemBazelLocalWorkspace, ImportExternalLoadStatement, ThirdPartyPaths}
import com.wix.build.maven._
import com.wix.build.sync.ArtifactoryRemoteStorage.decorateNodesWithChecksum
import com.wix.build.sync.DependenciesRemoteStorage
Expand All @@ -11,6 +11,7 @@ import java.nio.file.Path
class ManagedDependenciesSynchronizer(mavenDependencyResolver: MavenDependencyResolver,
managedDependenciesRepoPath: Path,
destination: String,
destinationPackage: DestinationPackage,
dependenciesRemoteStorage: DependenciesRemoteStorage,
managedDependencies: List[Dependency],
importExternalLoadStatement: ImportExternalLoadStatement)
Expand All @@ -26,7 +27,10 @@ class ManagedDependenciesSynchronizer(mavenDependencyResolver: MavenDependencyRe
)

new BazelDependenciesWriter(
new FileSystemBazelLocalWorkspace(managedDependenciesRepoPath.toFile, new ThirdPartyPaths(destination)),
new FileSystemBazelLocalWorkspace(
managedDependenciesRepoPath.toFile,
new ThirdPartyPaths(destination, destinationPackage),
),
importExternalLoadStatement = importExternalLoadStatement
).writeDependencies(dependenciesToUpdateWithChecksums)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class BazelWorkspaceDriver(bazelRepo: BazelLocalWorkspace) {
}

private def addImportFileLoadStatementsToThirdPartyReposFile(currentSkylarkFile: String, mavenJar: Coordinates) = {
s"""${serializedLoadImportExternalTargetsFile(mavenJar, bazelRepo.thirdPartyPaths.thirdPartyImportFilesPathRoot)}
s"""${serializedLoadImportExternalTargetsFile(mavenJar, bazelRepo.thirdPartyPaths.destinationPackage)}
|
|$currentSkylarkFile
|
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,10 @@ class BazelDependenciesReaderTest extends SpecificationWithJUnit {
trait emptyThirdPartyReposCtx extends Scope {
val localWorkspaceName = "local_workspace_name"
val thirdPartyPath = "third_party"
val localWorkspace: BazelLocalWorkspace = new FakeLocalBazelWorkspace(localWorkspaceName = localWorkspaceName, thirdPartyPaths = new ThirdPartyPaths("third_party"))
val localWorkspace: BazelLocalWorkspace = new FakeLocalBazelWorkspace(
localWorkspaceName = localWorkspaceName,
thirdPartyPaths = new ThirdPartyPaths("third_party", DestinationPackage.resolveFromDestination("third_party"))
)
val reader = new BazelDependenciesReader(localWorkspace)

def defaultDependency(groupId: String, artifactId: String, version: String, exclusion: Set[Exclusion] = Set.empty) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,10 @@ class BazelDependenciesWriterTest extends SpecificationWithJUnit {
trait emptyThirdPartyReposCtx extends Scope {
val localWorkspaceName = "some_workspace_name"
val thirdPartyPath = "third_party"
val localWorkspace = new FakeLocalBazelWorkspace(localWorkspaceName = localWorkspaceName, thirdPartyPaths = new ThirdPartyPaths(thirdPartyPath))
val localWorkspace = new FakeLocalBazelWorkspace(
localWorkspaceName = localWorkspaceName,
thirdPartyPaths = new ThirdPartyPaths(thirdPartyPath, DestinationPackage.resolveFromDestination(thirdPartyPath))
)

def writer = writerFor(localWorkspace)

Expand Down Expand Up @@ -418,7 +421,10 @@ class BazelDependenciesWriterTest extends SpecificationWithJUnit {
"given an overrided set of neverlink coordinates" should {
"write target with 'neverlink = 1 ' if came from overrided list" in {
val localWorkspaceName = "some_workspace_name"
val localWorkspace = new FakeLocalBazelWorkspace(localWorkspaceName = localWorkspaceName, thirdPartyPaths = new ThirdPartyPaths("third_party"))
val destination = "third_party"
val localWorkspace = new FakeLocalBazelWorkspace(
localWorkspaceName = localWorkspaceName,
thirdPartyPaths = new ThirdPartyPaths(destination, DestinationPackage.resolveFromDestination(destination)))

val artifact = someCoordinates("some-artifact")

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.wix.build.bazel

import org.specs2.mutable.SpecWithJUnit

class DestinationPackageTest extends SpecWithJUnit {
"resolves single element package" in {
DestinationPackage.resolveFromDestination("third_party") mustEqual DestinationPackage("//:third_party")
}

"resolves multiple elements packages" in {
DestinationPackage.resolveFromDestination("some/where/deep") mustEqual DestinationPackage("//some/where:deep")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import scala.collection.mutable

class FakeLocalBazelWorkspace(sourceFiles: mutable.Map[String, String] = mutable.Map.empty,
val localWorkspaceName: String = "",
val thirdPartyPaths: ThirdPartyPaths = new ThirdPartyPaths("third_party")) extends BazelLocalWorkspace {
val thirdPartyPaths: ThirdPartyPaths = new ThirdPartyPaths("third_party", DestinationPackage.resolveFromDestination("third_party")))
extends BazelLocalWorkspace {

import thirdPartyPaths._

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ class ThirdPartyReposFileTest extends SpecificationWithJUnit {

val jars = List(artifactA, artifactB, artifactC)
val thirdPartyPath = "third_party"
val destinationPackage = DestinationPackage.resolveFromDestination(thirdPartyPath)

"third party repos file parser" should {
trait ctx extends Scope {
Expand Down Expand Up @@ -80,7 +81,7 @@ class ThirdPartyReposFileTest extends SpecificationWithJUnit {
"do nothing in case one with same groupId but different artifactId is defined in third party repos" in {
val thirdPartyRepos = createThirdPartyReposWithLoadStatementFor(jars)
val newHead = jars.head.copy(artifactId = "bla-artifact")
ThirdPartyReposFile.Builder(thirdPartyRepos).withLoadStatementsFor(newHead, thirdPartyPath).content mustEqual thirdPartyRepos
ThirdPartyReposFile.Builder(thirdPartyRepos).withLoadStatementsFor(newHead, destinationPackage).content mustEqual thirdPartyRepos
}

"insert new load statement in case there is no load statement with same group id" in {
Expand All @@ -97,28 +98,28 @@ class ThirdPartyReposFileTest extends SpecificationWithJUnit {
| new_group_deps()
|""".stripMargin

ThirdPartyReposFile.Builder(thirdPartyRepos).withLoadStatementsFor(newJar, thirdPartyPath).content mustEqual expectedThirdPartyRepos
ThirdPartyReposFile.Builder(thirdPartyRepos).withLoadStatementsFor(newJar, destinationPackage).content mustEqual expectedThirdPartyRepos
}

"ignore war dependencies" in {
val warDependnecy = MavenMakers.someCoordinates("some-dep", Packaging("war"))
ThirdPartyReposFile.Builder("foo").fromCoordinates(warDependnecy, thirdPartyPath) mustEqual Builder("foo")
ThirdPartyReposFile.Builder("foo").fromCoordinates(warDependnecy, destinationPackage) mustEqual Builder("foo")
}

"delete load statement" in {
val thirdPartyRepos = createThirdPartyReposWithLoadStatementFor(List(artifactA, artifactB, artifactC))
val expectedThirdPartyRepos = createThirdPartyReposWithLoadStatementFor(List(artifactA, artifactB))

ThirdPartyReposFile.Builder(thirdPartyRepos).removeGroupIds(artifactC.groupId, thirdPartyPath).content mustEqual expectedThirdPartyRepos
ThirdPartyReposFile.Builder(thirdPartyRepos).removeGroupIds(artifactC.groupId, destinationPackage).content mustEqual expectedThirdPartyRepos
}

"delete 2 consecutive load statements which have no empty line in between them" in {
val thirdPartyRepos = createThirdPartyReposWithLoadStatementFor(List(artifactA, artifactB, artifactC, artifactD), insertOnlyOneNewLine = true)
val expectedThirdPartyRepos = createThirdPartyReposWithLoadStatementFor(List(artifactA, artifactD))

ThirdPartyReposFile.Builder(thirdPartyRepos)
.removeGroupIds(artifactB.groupId, thirdPartyPath)
.removeGroupIds(artifactC.groupId, thirdPartyPath).content mustEqual expectedThirdPartyRepos
.removeGroupIds(artifactB.groupId, destinationPackage)
.removeGroupIds(artifactC.groupId, destinationPackage).content mustEqual expectedThirdPartyRepos
}
}

Expand Down Expand Up @@ -149,13 +150,13 @@ class ThirdPartyReposFileTest extends SpecificationWithJUnit {
val firstJar: Coordinates = coordinates.head
val restOfJars = coordinates.tail

val restLoads = restOfJars.map(serializedLoadImportExternalTargetsFile(_, thirdPartyPath)).mkString(insertOnlyOneNewLineIfRequired)
val restLoads = restOfJars.map(serializedLoadImportExternalTargetsFile(_, destinationPackage)).mkString(insertOnlyOneNewLineIfRequired)
val restCalls = restOfJars.map(serializedImportExternalTargetsFileMethodCall).mkString(insertOnlyOneNewLineIfRequired)


s"""load("@core_server_build_tools//:macros.bzl", "maven_archive", "maven_proto")
|
|${serializedLoadImportExternalTargetsFile(firstJar, thirdPartyPath)}
|${serializedLoadImportExternalTargetsFile(firstJar, destinationPackage)}
|
|$restLoads
|
Expand Down

0 comments on commit 31b6d46

Please sign in to comment.