Skip to content

Commit 149358a

Browse files
committed
Add JavaRepositoryTests to test dependencies resolving with custom repositories
1 parent 9416c56 commit 149358a

File tree

2 files changed

+292
-0
lines changed

2 files changed

+292
-0
lines changed

Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,7 @@ let package = Package(
454454
name: "SwiftJavaTests",
455455
dependencies: [
456456
"SwiftJava",
457+
"SwiftJavaTool",
457458
"JavaNet"
458459
],
459460
swiftSettings: [
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2024 Apple Inc. and the Swift.org project authors
6+
// Licensed under Apache License v2.0
7+
//
8+
// See LICENSE.txt for license information
9+
// See CONTRIBUTORS.txt for the list of Swift.org project authors
10+
//
11+
// SPDX-License-Identifier: Apache-2.0
12+
//
13+
//===----------------------------------------------------------------------===//
14+
15+
import Foundation
16+
@testable import SwiftJavaConfigurationShared
17+
@testable import SwiftJavaTool // test in terminal, if xcode can't find the module
18+
import Testing
19+
20+
@Suite(.serialized)
21+
class JavaRepositoryTests {
22+
static let localRepo: String = {
23+
let directory = FileManager.default.temporaryDirectory.appendingPathComponent("SwiftJavaTest-Local-Repo", isDirectory: true)
24+
try! FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
25+
return directory.path
26+
}()
27+
28+
static let localJarRepo: String = {
29+
let directory = FileManager.default.temporaryDirectory.appendingPathComponent("SwiftJavaTest-Local-Repo-Jar-Only", isDirectory: true)
30+
try! FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
31+
return directory.path
32+
}()
33+
34+
static let localPomRepo: String = {
35+
let directory = FileManager.default.temporaryDirectory.appendingPathComponent("SwiftJavaTest-Local-Repo-Pom-Only", isDirectory: true)
36+
try! FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true)
37+
return directory.path
38+
}()
39+
40+
deinit {
41+
for item in [Self.localRepo, Self.localJarRepo, Self.localPomRepo] {
42+
try? FileManager.default.removeItem(atPath: item)
43+
}
44+
}
45+
46+
@Test(arguments: Configuration.resolvableConfigurations)
47+
func resolvableDependency(configuration: SwiftJavaConfigurationShared.Configuration) async throws {
48+
try await resolve(configuration: configuration)
49+
}
50+
51+
@Test
52+
func nonResolvableDependency() async throws {
53+
try await #expect(processExitsWith: .failure, "commonCSVWithUnknownDependencies") {
54+
try await resolve(configuration: .commonCSVWithUnknownDependencies)
55+
}
56+
try await #expect(processExitsWith: .failure, "jitpackJsonUsingCentralRepository") {
57+
try await resolve(configuration: .jitpackJsonUsingCentralRepository)
58+
}
59+
try await #expect(processExitsWith: .failure, "jitpackJsonInRepoIncludeIOOnly") {
60+
try await resolve(configuration: .jitpackJsonInRepoIncludeIOOnly)
61+
}
62+
try await #expect(processExitsWith: .failure, "andriodCoreInCentral") {
63+
try await resolve(configuration: .andriodCoreInCentral)
64+
}
65+
}
66+
67+
@Test
68+
func respositoryDecoding() throws {
69+
let data = #"[{"type":"maven","url":"https://repo.mycompany.com/maven2"},{"type":"maven","url":"https://repo2.mycompany.com/maven2","artifactUrls":["https://repo.mycompany.com/jars","https://repo.mycompany.com/jars2"]},{"type":"maven","url":"https://secure.repo.com/maven2","credentials":{"username":"user123","password":"secret"}},{"type":"mavenLocal","includeGroups":["com.example.myproject"]},{"type":"maven","url":"build/repo"},{"type":"mavenCentral"},{"type":"mavenLocal"},{"type":"google"}]"#.data(using: .utf8)!
70+
let repositories = try JSONDecoder().decode([JavaRepositoryDescriptor].self, from: data)
71+
#expect(!repositories.isEmpty, "Expected to decode at least one repository")
72+
#expect(repositories.contains(.maven(url: "https://repo.mycompany.com/maven2")), "Expected to contain the default repository")
73+
#expect(repositories.contains(.maven(url: "build/repo")), "Expected to contain a repository from a build repo")
74+
#expect(repositories.contains(.maven(url: "https://repo2.mycompany.com/maven2", artifactUrls: ["https://repo.mycompany.com/jars", "https://repo.mycompany.com/jars2"])), "Expected to contain a repository with artifact URLs")
75+
#expect(repositories.contains(.mavenLocal(includeGroups: ["com.example.myproject"])), "Expected to contain mavenLocal with includeGroups")
76+
#expect(repositories.contains(.mavenLocal()), "Expected to contain mavenLocal")
77+
#expect(repositories.contains(.other("mavenCentral")), "Expected to contain mavenCentral")
78+
#expect(repositories.contains(.other("google")), "Expected to contain google")
79+
}
80+
}
81+
82+
// Wired issue with #require, marking the function as static seems to resolve it
83+
private func resolve(configuration: SwiftJavaConfigurationShared.Configuration) async throws {
84+
var config = configuration
85+
var command = try SwiftJava.ResolveCommand.parse([
86+
"--output-directory",
87+
".build/\(configuration.swiftModule!)/destination/SwiftJavaPlugin/",
88+
89+
"--swift-module",
90+
configuration.swiftModule!
91+
])
92+
try await config.downloadIfNeeded()
93+
try await command.runSwiftJavaCommand(config: &config)
94+
}
95+
96+
extension SwiftJavaConfigurationShared.Configuration {
97+
static var resolvableConfigurations: [Configuration] = [
98+
.commonCSV, .jitpackJson,
99+
.jitpackJsonInRepo,
100+
andriodCoreInGoogle
101+
]
102+
103+
static let commonCSV: Configuration = {
104+
var configuration = Configuration()
105+
configuration.swiftModule = "JavaCommonCSV"
106+
configuration.dependencies = [
107+
JavaDependencyDescriptor(groupID: "org.apache.commons", artifactID: "commons-csv", version: "1.12.0")
108+
]
109+
return configuration
110+
}()
111+
112+
static let jitpackJson: Configuration = {
113+
var configuration = Configuration()
114+
configuration.swiftModule = "JavaJson"
115+
configuration.dependencies = [
116+
JavaDependencyDescriptor(groupID: "org.andrejs", artifactID: "json", version: "1.2")
117+
]
118+
configuration.repositories = [.maven(url: "https://jitpack.io")]
119+
return configuration
120+
}()
121+
122+
static let jitpackJsonInRepo: Configuration = {
123+
var configuration = Configuration()
124+
configuration.swiftModule = "JavaJson"
125+
configuration.dependencies = [
126+
JavaDependencyDescriptor(groupID: "org.andrejs", artifactID: "json", version: "1.2")
127+
]
128+
// using the following property to download to local repo
129+
configuration.packageToDownload = #""org.andrejs:json:1.2""#
130+
configuration.remoteRepo = "https://jitpack.io"
131+
132+
let repo = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".m2/repository")
133+
configuration.repositories = [.maven(url: repo.path)]
134+
return configuration
135+
}()
136+
137+
static let androidLifecycleInRepoWithCustomArtifacts: Configuration = {
138+
var configuration = Configuration()
139+
configuration.swiftModule = "JavaAndroidLifecycle"
140+
configuration.dependencies = [
141+
JavaDependencyDescriptor(groupID: "android.arch.lifecycle", artifactID: "common", version: "1.1.1")
142+
]
143+
// using the following property to download to local repo
144+
configuration.packageToDownload = #""android.arch.lifecycle:common:1.1.1""#
145+
configuration.remoteRepo = "https://maven.google.com"
146+
configuration.splitPackage = true
147+
148+
configuration.repositories = [
149+
.maven(url: JavaRepositoryTests.localJarRepo, artifactUrls: [
150+
JavaRepositoryTests.localPomRepo
151+
])
152+
]
153+
return configuration
154+
}()
155+
156+
static let andriodCoreInGoogle: Configuration = {
157+
var configuration = Configuration()
158+
configuration.swiftModule = "JavaAndroidCommon"
159+
configuration.dependencies = [
160+
JavaDependencyDescriptor(groupID: "android.arch.core", artifactID: "common", version: "1.1.1")
161+
]
162+
configuration.repositories = [.other("google")] // google()
163+
return configuration
164+
}()
165+
166+
// MARK: - Non resolvable dependencies
167+
168+
static let commonCSVWithUnknownDependencies: Configuration = {
169+
var configuration = Configuration.commonCSV
170+
configuration.dependencies = [
171+
JavaDependencyDescriptor(groupID: "org.apache.commons.unknown", artifactID: "commons-csv", version: "1.12.0")
172+
]
173+
return configuration
174+
}()
175+
176+
static let jitpackJsonInRepoIncludeIOOnly: Configuration = {
177+
var configuration = Configuration()
178+
configuration.swiftModule = "JavaJson"
179+
configuration.dependencies = [
180+
JavaDependencyDescriptor(groupID: "org.andrejs", artifactID: "json", version: "1.2")
181+
]
182+
// using the following property to download to local repo
183+
configuration.packageToDownload = #""org.andrejs:json:1.2""#
184+
configuration.remoteRepo = "https://jitpack.io"
185+
// use local repo, since includeGroups only applied to mavenLocal
186+
configuration.preferredLocalRepo = FileManager.default.homeDirectoryForCurrentUser.appendingPathComponent(".m2/repository").path
187+
188+
configuration.repositories = [.mavenLocal(includeGroups: ["commons-io"])]
189+
return configuration
190+
}()
191+
192+
static let jitpackJsonUsingCentralRepository: Configuration = {
193+
var configuration = Configuration()
194+
configuration.swiftModule = "JavaJson"
195+
configuration.dependencies = [
196+
JavaDependencyDescriptor(groupID: "org.andrejs", artifactID: "json", version: "1.2")
197+
]
198+
return configuration
199+
}()
200+
201+
static let andriodCoreInCentral: Configuration = {
202+
var configuration = Configuration()
203+
configuration.swiftModule = "JavaAndroidCommon"
204+
configuration.dependencies = [
205+
JavaDependencyDescriptor(groupID: "android.arch.core", artifactID: "common", version: "1.1.1")
206+
]
207+
return configuration
208+
}()
209+
}
210+
211+
// MARK: - Download to local repo
212+
213+
private extension SwiftJavaConfigurationShared.Configuration {
214+
/// in json format, which means string needs to be quoted
215+
var packageToDownload: String? {
216+
get { javaPackage }
217+
set { javaPackage = newValue }
218+
}
219+
220+
var remoteRepo: String? {
221+
get { outputJavaDirectory }
222+
set { outputJavaDirectory = newValue }
223+
}
224+
225+
/// whether to download jar and pom files separately
226+
var splitPackage: Bool? {
227+
get { writeEmptyFiles }
228+
set { writeEmptyFiles = newValue }
229+
}
230+
231+
var preferredLocalRepo: String? {
232+
get { classpath }
233+
set { classpath = newValue }
234+
}
235+
236+
func downloadIfNeeded() async throws {
237+
guard
238+
let data = packageToDownload?.data(using: .utf8),
239+
let descriptor = try? JSONDecoder().decode(JavaDependencyDescriptor.self, from: data),
240+
let repo = remoteRepo
241+
else {
242+
return
243+
}
244+
let splitPackage = splitPackage ?? false
245+
246+
let process = Process()
247+
process.executableURL = URL(fileURLWithPath: "/usr/bin/env")
248+
process.arguments = [
249+
"mvn", "dependency:get",
250+
"-DremoteRepositories=\(repo)",
251+
"-DgroupId=\(descriptor.groupID)",
252+
"-DartifactId=\(descriptor.artifactID)",
253+
"-Dversion=\(descriptor.version)",
254+
"-q"
255+
]
256+
257+
if splitPackage {
258+
print("Downloading: \(descriptor) from \(repo) to \(JavaRepositoryTests.localJarRepo) and \(JavaRepositoryTests.localPomRepo)".yellow)
259+
process.arguments?.append(contentsOf: [
260+
"-Dpackaging=jar",
261+
"-Dmaven.repo.local=\(JavaRepositoryTests.localJarRepo)",
262+
"&&",
263+
"mvn", "dependency:get",
264+
"-DremoteRepositories=\(repo)",
265+
"-DgroupId=\(descriptor.groupID)",
266+
"-DartifactId=\(descriptor.artifactID)",
267+
"-Dversion=\(descriptor.version)",
268+
"-Dpackaging=pom",
269+
"-Dmaven.repo.local=\(JavaRepositoryTests.localPomRepo)",
270+
"-q"
271+
])
272+
} else {
273+
let repoPath = classpath ?? JavaRepositoryTests.localRepo
274+
print("Downloading: \(descriptor) from \(repo) to \(repoPath)".yellow)
275+
process.arguments?.append("-Dmaven.repo.local=\(repoPath)")
276+
}
277+
278+
try process.run()
279+
process.waitUntilExit()
280+
281+
if process.terminationStatus == 0 {
282+
print("Download complete: \(descriptor)".green)
283+
} else {
284+
throw NSError(
285+
domain: "DownloadError",
286+
code: Int(process.terminationStatus),
287+
userInfo: [NSLocalizedDescriptionKey: "Unzip failed with status \(process.terminationStatus)"]
288+
)
289+
}
290+
}
291+
}

0 commit comments

Comments
 (0)