This repository has been archived on 2022-03-12. You can view files and clone it, but cannot push or open issues or pull requests.

261 lines
9.4 KiB
Groovy
Raw Permalink Normal View History

2021-04-02 02:24:13 +03:00
import groovy.json.JsonSlurper
import org.gradle.util.VersionNumber
import java.nio.file.Paths
import java.util.regex.Pattern
class Unimodule {
String name
List platforms
List targets
List androidPackages
String directory
String version
String androidGroup
String androidSubdirectory
boolean supportsPlatform(String platform) {
return platforms instanceof List && platforms.contains(platform)
}
boolean supportsTarget(String target) {
return targets.size() == 0 || targets.contains(target)
}
}
def readPackageFromJavaOrKotlinFile(String filePath) {
def file = new File(filePath)
def fileReader = new BufferedReader(new FileReader(file))
def fileContent = ""
while ((fileContent = fileReader.readLine()) != null) {
def match = fileContent =~ /^package ([0-9a-zA-Z._]*);?$/
if (match.size() == 1 && match[0].size() == 2) {
fileReader.close()
return match[0][1]
}
}
fileReader.close()
throw new GradleException("Java or Kotlin file $file does not include package declaration")
}
def readFromBuildGradle(String file) {
def gradleFile = new File(file)
if (!gradleFile.exists()) {
return [:]
}
def fileReader = new BufferedReader(new FileReader(gradleFile))
def result = [:]
for (def line = fileReader.readLine(); line != null; line = fileReader.readLine()) {
def versionMatch = line.trim() =~ /^version ?= ?'([\w.-]+)'$/
def groupMatch = line.trim() =~ /^group ?= ?'([\w.]+)'$/
if (versionMatch.size() == 1 && versionMatch[0].size() == 2) {
result.version = versionMatch[0][1]
}
if (groupMatch.size() == 1 && groupMatch[0].size() == 2) {
result.group = groupMatch[0][1]
}
}
fileReader.close()
return result
}
def findDefaultBasePackage(String packageDir) {
def pathsJava = new FileNameFinder().getFileNames(packageDir, "android/src/**/*Package.java")
def pathsKt = new FileNameFinder().getFileNames(packageDir, "android/src/**/*Package.kt")
def paths = pathsJava + pathsKt
if (paths.size != 1) {
return []
}
def packageName = readPackageFromJavaOrKotlinFile(paths[0])
def className = new File(paths[0]).getName().split(Pattern.quote("."))[0]
return ["$packageName.$className"]
}
def generateBasePackageList(List<Unimodule> unimodules) {
def findMainJavaApp = new FileNameFinder().getFileNames(rootProject.getProjectDir().getPath(), '**/MainApplication.java', '')
def findMainKtApp = new FileNameFinder().getFileNames(rootProject.getProjectDir().getPath(), '**/MainApplication.kt', '')
if (findMainJavaApp.size() != 1 && findMainKtApp.size() != 1) {
throw new GradleException("You need to have MainApplication in your project")
}
def findMainApp = (findMainJavaApp.size() == 1) ? findMainJavaApp : findMainKtApp
def mainAppDirectory = new File(findMainApp[0]).parentFile
def packageName = readPackageFromJavaOrKotlinFile(findMainApp[0])
def fileBuilder = new StringBuilder()
fileBuilder.append("package ${packageName}.generated;\n\n")
fileBuilder.append("import java.util.Arrays;\n")
fileBuilder.append("import java.util.List;\n")
fileBuilder.append("import org.unimodules.core.interfaces.Package;\n\n")
fileBuilder.append("public class BasePackageList {\n")
fileBuilder.append(" public List<Package> getPackageList() {\n")
fileBuilder.append(" return Arrays.<Package>asList(\n")
def isEmptyList = true
for (module in unimodules) {
for (pkg in module.androidPackages) {
fileBuilder.append(" new $pkg(),\n")
isEmptyList = false
}
}
if (!isEmptyList) {
fileBuilder.deleteCharAt(fileBuilder.length() - 2) // remove last comma in a list
}
fileBuilder.append(" );\n")
fileBuilder.append(" }\n")
fileBuilder.append("}\n")
new File(mainAppDirectory, "generated").mkdirs()
def javaFile = new File(mainAppDirectory, "generated/BasePackageList.java")
javaFile.createNewFile()
def javaFileWriter = new BufferedWriter(new FileWriter(javaFile))
javaFileWriter.write(fileBuilder.toString())
javaFileWriter.close()
}
def findUnimodules(String target, List exclude, List modulesPaths) {
def unimodules = [:]
def unimodulesDuplicates = []
for (modulesPath in modulesPaths) {
def baseDir = new File(rootProject.getBuildFile(), modulesPath).toString()
def moduleConfigPaths = new FileNameFinder().getFileNames(baseDir, '**/unimodule.json', '')
for (moduleConfigPath in moduleConfigPaths) {
def unimoduleConfig = Paths.get(moduleConfigPath).toRealPath().toFile()
def unimoduleJson = new JsonSlurper().parseText(unimoduleConfig.text)
def directory = unimoduleConfig.getParent()
def buildGradle = readFromBuildGradle(new File(directory, "android/build.gradle").toString())
def packageJsonFile = new File(directory, 'package.json')
def packageJson = new JsonSlurper().parseText(packageJsonFile.text)
def unimodule = new Unimodule()
unimodule.name = unimoduleJson.name ?: packageJson.name
unimodule.directory = directory
unimodule.version = buildGradle.version ?: packageJson.version ?: "UNVERSIONED"
unimodule.androidGroup = buildGradle.group ?: "org.unimodules"
unimodule.androidSubdirectory = unimoduleJson.android?.subdirectory ?: "android"
unimodule.platforms = unimoduleJson.platforms != null ? unimoduleJson.platforms : []
assert unimodule.platforms instanceof List
unimodule.targets = unimoduleJson.targets != null ? unimoduleJson.targets : []
assert unimodule.targets instanceof List
unimodule.androidPackages = unimoduleJson.android?.packages != null ?
unimoduleJson.android.packages : findDefaultBasePackage(directory)
assert unimodule.androidPackages instanceof List
if (unimodule.supportsPlatform('android') && unimodule.supportsTarget(target)) {
if (!exclude.contains(unimodule.name)) {
if (unimodules[unimodule.name]) {
unimodulesDuplicates.add(unimodule.name)
}
if (!unimodules[unimodule.name] ||
VersionNumber.parse(unimodule.version) >= VersionNumber.parse(unimodules[unimodule.name].version)) {
unimodules[unimodule.name] = unimodule
}
}
}
}
}
return [
unimodules: unimodules.collect { entry -> entry.value },
duplicates: unimodulesDuplicates.unique()
]
}
class Colors {
static final String NORMAL = "\u001B[0m"
static final String RED = "\u001B[31m"
static final String GREEN = "\u001B[32m"
static final String YELLOW = "\u001B[33m"
static final String MAGENTA = "\u001B[35m"
}
def addUnimodulesDependencies(String target, List exclude, List modulesPaths, Closure<Boolean> addUnimodule) {
if (!(new File(project.rootProject.projectDir.parentFile, 'package.json').exists())) {
// There's no package.json
throw new GradleException(
"'addUnimodulesDependencies()' is being used in a project that doesn't seem to be a React Native project."
)
}
def results = findUnimodules(target, exclude, modulesPaths)
def unimodules = results.unimodules
def duplicates = results.duplicates
generateBasePackageList(unimodules)
if (unimodules.size() > 0) {
println()
println Colors.YELLOW + 'Installing unimodules:' + Colors.NORMAL
for (unimodule in unimodules) {
println ' ' + Colors.GREEN + unimodule.name + Colors.YELLOW + '@' + Colors.RED + unimodule.version + Colors.NORMAL + ' from ' + Colors.MAGENTA + unimodule.directory + Colors.NORMAL
addUnimodule(unimodule)
}
if (duplicates.size() > 0) {
println()
println Colors.YELLOW + 'Found some duplicated unimodule packages. Installed the ones with the highest version number.' + Colors.NORMAL
println Colors.YELLOW + 'Make sure following dependencies of your project are resolving to one specific version:' + Colors.NORMAL
println ' ' + duplicates
.collect { unimoduleName -> Colors.GREEN + unimoduleName + Colors.NORMAL }
.join(', ')
}
} else {
println()
println Colors.YELLOW + "No unimodules found. Are you sure you've installed JS dependencies?" + Colors.NORMAL
}
}
ext.addUnimodulesDependencies = { Map customOptions = [:] ->
def options = [
modulesPaths : ['../../node_modules'],
configuration: 'implementation',
target : 'react-native',
exclude : [],
] << customOptions
addUnimodulesDependencies(options.target, options.exclude, options.modulesPaths, {unimodule ->
Object dependency = project.project(':' + unimodule.name)
project.dependencies.add(options.configuration, dependency)
})
}
ext.addMavenUnimodulesDependencies = { Map customOptions = [:] ->
def options = [
modulesPaths : ['../../node_modules'],
configuration: 'implementation',
target : 'react-native',
exclude : [],
] << customOptions
addUnimodulesDependencies(options.target, options.exclude, options.modulesPaths, {unimodule ->
project.dependencies.add(
options.configuration,
"${unimodule.androidGroup}:${unimodule.name}:${unimodule.version}"
)
})
}
ext.includeUnimodulesProjects = { Map customOptions = [:] ->
def options = [
modulesPaths: ['../../node_modules'],
target : 'react-native',
exclude : [],
] << customOptions
def unimodules = findUnimodules(options.target, options.exclude, options.modulesPaths).unimodules
for (unimodule in unimodules) {
include ":${unimodule.name}"
project(":${unimodule.name}").projectDir = new File(unimodule.directory, unimodule.androidSubdirectory)
}
}