xccache 0.0.1 → 1.0.0.rc15341775774
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/xccache/cache/cachemap.rb +28 -11
- data/lib/xccache/command/base.rb +1 -4
- data/lib/xccache/command/build.rb +1 -14
- data/lib/xccache/command/off.rb +26 -0
- data/lib/xccache/command.rb +10 -1
- data/lib/xccache/core/config.rb +10 -4
- data/lib/xccache/core/hash.rb +9 -6
- data/lib/xccache/core/lockfile.rb +62 -7
- data/lib/xccache/core/log.rb +5 -0
- data/lib/xccache/core/sh.rb +3 -17
- data/lib/xccache/core/syntax/hash.rb +4 -0
- data/lib/xccache/core/system.rb +2 -1
- data/lib/xccache/installer/build.rb +3 -1
- data/lib/xccache/installer/integration/build.rb +28 -0
- data/lib/xccache/installer/integration/descs.rb +27 -0
- data/lib/xccache/installer/integration/supporting_files.rb +29 -0
- data/lib/xccache/installer/integration/viz.rb +38 -0
- data/lib/xccache/installer/integration.rb +12 -0
- data/lib/xccache/installer/use.rb +1 -1
- data/lib/xccache/installer.rb +47 -14
- data/lib/xccache/spm/build.rb +1 -1
- data/lib/xccache/spm/desc/base.rb +1 -4
- data/lib/xccache/spm/desc/desc.rb +2 -30
- data/lib/xccache/spm/mixin.rb +5 -4
- data/lib/xccache/spm/pkg/base.rb +40 -34
- data/lib/xccache/spm/pkg/proxy.rb +60 -0
- data/lib/xccache/spm/pkg/proxy_executable.rb +51 -0
- data/lib/xccache/utils/template.rb +1 -1
- data/lib/xccache/xcodeproj/pkg.rb +2 -4
- data/lib/xccache/xcodeproj/pkg_product_dependency.rb +16 -3
- data/lib/xccache/xcodeproj/project.rb +9 -15
- data/lib/xccache/xcodeproj/target.rb +4 -14
- data/lib/xccache.rb +5 -0
- metadata +12 -12
- data/lib/xccache/assets/templates/umbrella.Package.swift.template +0 -182
- data/lib/xccache/spm/pkg/umbrella/build.rb +0 -30
- data/lib/xccache/spm/pkg/umbrella/cachemap.rb +0 -110
- data/lib/xccache/spm/pkg/umbrella/descs.rb +0 -35
- data/lib/xccache/spm/pkg/umbrella/manifest.rb +0 -83
- data/lib/xccache/spm/pkg/umbrella/viz.rb +0 -40
- data/lib/xccache/spm/pkg/umbrella/xcconfigs.rb +0 -31
- data/lib/xccache/spm/pkg/umbrella.rb +0 -91
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: xccache
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 1.0.0.rc15341775774
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Thuyen Trinh
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-05-
|
11
|
+
date: 2025-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: claide
|
@@ -69,7 +69,6 @@ files:
|
|
69
69
|
- lib/xccache/assets/templates/framework.modulemap.template
|
70
70
|
- lib/xccache/assets/templates/resource_bundle_accessor.m.template
|
71
71
|
- lib/xccache/assets/templates/resource_bundle_accessor.swift.template
|
72
|
-
- lib/xccache/assets/templates/umbrella.Package.swift.template
|
73
72
|
- lib/xccache/cache/cachemap.rb
|
74
73
|
- lib/xccache/command.rb
|
75
74
|
- lib/xccache/command/base.rb
|
@@ -77,6 +76,7 @@ files:
|
|
77
76
|
- lib/xccache/command/cache.rb
|
78
77
|
- lib/xccache/command/cache/clean.rb
|
79
78
|
- lib/xccache/command/cache/list.rb
|
79
|
+
- lib/xccache/command/off.rb
|
80
80
|
- lib/xccache/command/pkg.rb
|
81
81
|
- lib/xccache/command/pkg/build.rb
|
82
82
|
- lib/xccache/command/remote.rb
|
@@ -102,6 +102,11 @@ files:
|
|
102
102
|
- lib/xccache/core/system.rb
|
103
103
|
- lib/xccache/installer.rb
|
104
104
|
- lib/xccache/installer/build.rb
|
105
|
+
- lib/xccache/installer/integration.rb
|
106
|
+
- lib/xccache/installer/integration/build.rb
|
107
|
+
- lib/xccache/installer/integration/descs.rb
|
108
|
+
- lib/xccache/installer/integration/supporting_files.rb
|
109
|
+
- lib/xccache/installer/integration/viz.rb
|
105
110
|
- lib/xccache/installer/rollback.rb
|
106
111
|
- lib/xccache/installer/use.rb
|
107
112
|
- lib/xccache/main.rb
|
@@ -119,13 +124,8 @@ files:
|
|
119
124
|
- lib/xccache/spm/mixin.rb
|
120
125
|
- lib/xccache/spm/pkg.rb
|
121
126
|
- lib/xccache/spm/pkg/base.rb
|
122
|
-
- lib/xccache/spm/pkg/
|
123
|
-
- lib/xccache/spm/pkg/
|
124
|
-
- lib/xccache/spm/pkg/umbrella/cachemap.rb
|
125
|
-
- lib/xccache/spm/pkg/umbrella/descs.rb
|
126
|
-
- lib/xccache/spm/pkg/umbrella/manifest.rb
|
127
|
-
- lib/xccache/spm/pkg/umbrella/viz.rb
|
128
|
-
- lib/xccache/spm/pkg/umbrella/xcconfigs.rb
|
127
|
+
- lib/xccache/spm/pkg/proxy.rb
|
128
|
+
- lib/xccache/spm/pkg/proxy_executable.rb
|
129
129
|
- lib/xccache/spm/xcframework.rb
|
130
130
|
- lib/xccache/spm/xcframework/metadata.rb
|
131
131
|
- lib/xccache/spm/xcframework/slice.rb
|
@@ -161,9 +161,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
161
161
|
version: '0'
|
162
162
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
|
-
- - "
|
164
|
+
- - ">"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version:
|
166
|
+
version: 1.3.1
|
167
167
|
requirements: []
|
168
168
|
rubygems_version: 3.2.33
|
169
169
|
signing_key:
|
@@ -1,182 +0,0 @@
|
|
1
|
-
// swift-tools-version: 6.0
|
2
|
-
import Foundation
|
3
|
-
import PackageDescription
|
4
|
-
|
5
|
-
/*
|
6
|
-
MARK: INSTRUCTIONS
|
7
|
-
----------------------------------------------------------------------------------------------------------------------
|
8
|
-
This Package manifest is auto-generated from xccache (last updated: <%= timestamp %>).
|
9
|
-
----------------------------------------------------------------------------------------------------------------------
|
10
|
-
During local development, you can switch between *BINARY mode* and *SOURCE mode* by adding or removing the `.binary`
|
11
|
-
suffix in the JSON below.
|
12
|
-
As a user, you just need to care about the JSON. The rest is just the tool's internal logic.
|
13
|
-
|
14
|
-
NOTE that a product (ex. `pkg/foo.binary`) can only be used as binary if:
|
15
|
-
- Binary exists for `pkg/foo` (in `xccache/packages/binaries/foo/foo.xcframework`)
|
16
|
-
- Binary exists for all of its dependencies
|
17
|
-
The tool auto-fallbacks to the *SOURCE mode* if the conditions are not met.
|
18
|
-
----------------------------------------------------------------------------------------------------------------------
|
19
|
-
*/
|
20
|
-
let JSON = """
|
21
|
-
<%= json %>
|
22
|
-
"""
|
23
|
-
let DEPENDENCIES: [Package.Dependency] = [
|
24
|
-
<%= dependencies %>
|
25
|
-
]
|
26
|
-
let PLATFORMS: [SupportedPlatform] = [
|
27
|
-
<%= platforms %>
|
28
|
-
]
|
29
|
-
let PRODUCTS_TO_TARGETS: [String: [String]] = try parseJSON("""
|
30
|
-
<%= products_to_targets %>
|
31
|
-
""")
|
32
|
-
// ------------------------------------------------------------------------------------
|
33
|
-
|
34
|
-
// MARK: Main
|
35
|
-
_ = try XCCache.Package(parseJSON(JSON)).spm
|
36
|
-
|
37
|
-
// MARK: XCCache
|
38
|
-
enum XCCache {
|
39
|
-
// MARK: Config
|
40
|
-
@MainActor
|
41
|
-
struct Config {
|
42
|
-
static let pkgDir = URL(filePath: #filePath).deletingLastPathComponent()
|
43
|
-
// NOTE: Do NOT change `binariesDir` to `static let`
|
44
|
-
// Somehow, incremental resolution doesnt work causing the `binaryExist` wrongly cached
|
45
|
-
static var binariesDir: URL { pkgDir.appending(path: "binaries") }
|
46
|
-
}
|
47
|
-
|
48
|
-
// MARK: Package
|
49
|
-
@MainActor
|
50
|
-
final class Package {
|
51
|
-
let targets: [XCCache.Target]
|
52
|
-
init(_ dict: [String: [String]]) {
|
53
|
-
targets = dict.map { XCCache.Target($0, $1) }
|
54
|
-
}
|
55
|
-
|
56
|
-
var spm: PackageDescription.Package {
|
57
|
-
let regularTargets = targets.map(\.spm)
|
58
|
-
let binaryTargets = targets.flatMap(\.flattenRegularDeps).unique(by: \.name).compactMap(\.spmBinaryTarget)
|
59
|
-
return .init(
|
60
|
-
name: "xccache",
|
61
|
-
platforms: PLATFORMS,
|
62
|
-
products: targets.map(\.spmProduct),
|
63
|
-
dependencies: DEPENDENCIES,
|
64
|
-
targets: regularTargets + binaryTargets
|
65
|
-
)
|
66
|
-
}
|
67
|
-
}
|
68
|
-
|
69
|
-
// MARK: Target
|
70
|
-
@MainActor
|
71
|
-
final class Target {
|
72
|
-
let name: String
|
73
|
-
let deps: [UmbrellaDependency]
|
74
|
-
init(_ name: String, _ deps: [String]) {
|
75
|
-
self.name = name
|
76
|
-
self.deps = deps.map { UmbrellaDependency($0) }
|
77
|
-
}
|
78
|
-
|
79
|
-
var spmProduct: PackageDescription.Product {
|
80
|
-
.library(name: name, targets: [name])
|
81
|
-
}
|
82
|
-
var spm: PackageDescription.Target {
|
83
|
-
.target(
|
84
|
-
name: name,
|
85
|
-
dependencies: flattenRegularDeps.map(\.spm),
|
86
|
-
path: ".Sources/\(name)",
|
87
|
-
swiftSettings: [
|
88
|
-
.unsafeFlags(macroFlags),
|
89
|
-
]
|
90
|
-
)
|
91
|
-
}
|
92
|
-
var flattenDeps: [Dependency] { deps.flatMap(\.toBinariesIfOk).unique(by: \.name) }
|
93
|
-
var flattenRegularDeps: [Dependency] { flattenDeps.filter(\.regular) }
|
94
|
-
var macroFlags: [String] { flattenDeps.filter(\.macroBinary).flatMap(\.macroFlags) }
|
95
|
-
}
|
96
|
-
|
97
|
-
// MARK: Dependency
|
98
|
-
@MainActor
|
99
|
-
class Dependency {
|
100
|
-
let name: String
|
101
|
-
let bareName: String
|
102
|
-
let binaryURL: URL
|
103
|
-
let binary: Bool
|
104
|
-
let macro: Bool
|
105
|
-
var regular: Bool { !macro }
|
106
|
-
var regularBinary: Bool { binary && regular }
|
107
|
-
var macroBinary: Bool { binary && macro }
|
108
|
-
|
109
|
-
init(_ name: String) {
|
110
|
-
self.name = name
|
111
|
-
self.bareName = String(name.basename.split(separator: ".")[0])
|
112
|
-
self.macro = name.contains(".macro")
|
113
|
-
self.binaryURL = if macro {
|
114
|
-
Config.binariesDir.appending(path: "\(bareName)/\(bareName).macro").readlink()
|
115
|
-
} else {
|
116
|
-
Config.binariesDir.appending(path: "\(bareName)/\(bareName).xcframework").readlink()
|
117
|
-
}
|
118
|
-
self.binary = name.hasSuffix(".binary") && binaryURL.exist
|
119
|
-
}
|
120
|
-
|
121
|
-
var macroFlags: [String] {
|
122
|
-
["-load-plugin-executable", "\(binaryURL.path())#\(bareName)"]
|
123
|
-
}
|
124
|
-
|
125
|
-
var spm: PackageDescription.Target.Dependency {
|
126
|
-
if binary { return .byName(name: name) }
|
127
|
-
return .product(name: bareName, package: name.slug)
|
128
|
-
}
|
129
|
-
var spmBinaryTarget: PackageDescription.Target? {
|
130
|
-
regularBinary ? .binaryTarget(name: name, path: "binaries/\(bareName)/\(bareName).xcframework") : nil
|
131
|
-
}
|
132
|
-
}
|
133
|
-
|
134
|
-
@MainActor
|
135
|
-
class UmbrellaDependency: Dependency {
|
136
|
-
let binaries: [Dependency]
|
137
|
-
override init(_ name: String) {
|
138
|
-
binaries = (PRODUCTS_TO_TARGETS[name.withoutBinary] ?? []).map { Dependency("\($0).binary") }
|
139
|
-
super.init(name)
|
140
|
-
}
|
141
|
-
var toBinariesIfOk: [Dependency] {
|
142
|
-
if name.hasSuffix(".binary"), !binaries.isEmpty && binaries.allSatisfy(\.binary) { return binaries }
|
143
|
-
return [Dependency(name.withoutBinary)]
|
144
|
-
}
|
145
|
-
}
|
146
|
-
}
|
147
|
-
|
148
|
-
// MARK: Helpers
|
149
|
-
func parseJSON<T>(_ content: String) throws -> T {
|
150
|
-
if let data = content.data(using: .utf8), let result = try JSONSerialization.jsonObject(with: data) as? T {
|
151
|
-
return result
|
152
|
-
}
|
153
|
-
throw NSError(domain: "Invalid JSON:\n\(content)", code: 111)
|
154
|
-
}
|
155
|
-
|
156
|
-
extension URL {
|
157
|
-
var basename: String { lastPathComponent }
|
158
|
-
var exist: Bool { FileManager.default.fileExists(atPath: readlink().path()) }
|
159
|
-
/// Resolve symlinks recursively, equivalent to `readlink -f` in bash
|
160
|
-
func readlink() -> URL {
|
161
|
-
var prev = self, cur = resolvingSymlinksInPath()
|
162
|
-
while prev != cur {
|
163
|
-
prev = cur
|
164
|
-
cur = cur.resolvingSymlinksInPath()
|
165
|
-
}
|
166
|
-
return cur
|
167
|
-
}
|
168
|
-
}
|
169
|
-
|
170
|
-
extension String {
|
171
|
-
var slug: String { (self as NSString).deletingLastPathComponent.basename }
|
172
|
-
var basename: String { (self as NSString).lastPathComponent }
|
173
|
-
var withoutExtenstion: String { (self as NSString).deletingPathExtension }
|
174
|
-
var withoutBinary: String { replacing(#/\.binary$/#, with: "") }
|
175
|
-
}
|
176
|
-
|
177
|
-
extension Sequence {
|
178
|
-
func unique<T: Hashable>(by: (Element) -> T) -> [Element] {
|
179
|
-
var seen: Set<T> = []
|
180
|
-
return filter { seen.insert(by($0)).inserted }
|
181
|
-
}
|
182
|
-
}
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module XCCache
|
2
|
-
module SPM
|
3
|
-
class Package
|
4
|
-
module UmbrellaBuildMixin
|
5
|
-
def build(options = {})
|
6
|
-
to_build = targets_to_build(options)
|
7
|
-
return UI.warn("Detected no targets to build among cache-missed targets") if to_build.empty?
|
8
|
-
|
9
|
-
UI.info("-> Targets to build: #{to_build.to_s.bold}")
|
10
|
-
super(options.merge(:targets => to_build))
|
11
|
-
sync_cachemap(sdks: options[:sdks])
|
12
|
-
end
|
13
|
-
|
14
|
-
def targets_to_build(options)
|
15
|
-
items = options[:targets] || []
|
16
|
-
items = config.cachemap.missed.map { |x| File.basename(x) } if items.empty?
|
17
|
-
targets = @descs.flat_map(&:targets).select { |t| items.include?(t.name) }
|
18
|
-
if options[:recursive]
|
19
|
-
UI.message("Will include cache-missed recursive targets")
|
20
|
-
targets += targets.flat_map do |t|
|
21
|
-
t.recursive_targets.select { |x| config.cachemap.missed?(x.full_name) }
|
22
|
-
end
|
23
|
-
end
|
24
|
-
# TODO: Sort by number of dependents
|
25
|
-
targets.map(&:full_name).uniq
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,110 +0,0 @@
|
|
1
|
-
module XCCache
|
2
|
-
module SPM
|
3
|
-
class Package
|
4
|
-
module UmbrellaCachemapMixin
|
5
|
-
def sync_cachemap(sdks: [])
|
6
|
-
UI.section("Syncing cachemap (sdks: #{sdks.map(&:name)})")
|
7
|
-
nodes, edges, parents = xccache_desc.traverse
|
8
|
-
cache_data = gen_cache_data(nodes, parents, sdks)
|
9
|
-
targets_data, macros_data, deps_data = {}, {}, {}
|
10
|
-
xccache_desc.targets.each do |agg_target|
|
11
|
-
targets, macros = [], []
|
12
|
-
agg_target.direct_dependencies.each do |d|
|
13
|
-
all_hit = d.recursive_targets.all? { |t| cache_data[t] == :hit }
|
14
|
-
# If any associated targets is missed -> use original product form
|
15
|
-
# Otherwise, replace with recursive targets' binaries
|
16
|
-
deps_data[d.full_name] = d.recursive_targets.map(&:xccache_id)
|
17
|
-
targets << (all_hit ? "#{d.full_name}.binary" : d.full_name)
|
18
|
-
macros += d.recursive_targets.select(&:macro?).map(&:full_name) if all_hit
|
19
|
-
end
|
20
|
-
targets_data[agg_target.name] = targets.uniq.sort_by(&:downcase)
|
21
|
-
macros_data[agg_target.name] = macros.uniq
|
22
|
-
end
|
23
|
-
|
24
|
-
config.cachemap.raw = {
|
25
|
-
"manifest" => {
|
26
|
-
"targets" => targets_data,
|
27
|
-
"macros" => macros_data,
|
28
|
-
"deps" => deps_data,
|
29
|
-
},
|
30
|
-
"cache" => cache_data.transform_keys(&:full_name),
|
31
|
-
"depgraph" => {
|
32
|
-
"nodes" => nodes.map { |x| target_to_cytoscape_node(x, cache_data) },
|
33
|
-
"edges" => edges.map { |x, y| { :source => x.full_name, :target => y.full_name } },
|
34
|
-
},
|
35
|
-
}
|
36
|
-
config.cachemap.save
|
37
|
-
config.cachemap.print_stats
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def gen_cache_data(nodes, parents, sdks)
|
43
|
-
result = nodes.to_h do |node|
|
44
|
-
res = if config.ignore?(node.full_name) then :ignored
|
45
|
-
else
|
46
|
-
verify_binary?(node, sdks) ? :hit : :missed
|
47
|
-
end
|
48
|
-
[node, res]
|
49
|
-
end
|
50
|
-
|
51
|
-
# Propagate cache miss
|
52
|
-
to_visit = result.select { |_, v| %i[missed ignore].include?(v) }.keys
|
53
|
-
visited = Set.new
|
54
|
-
until to_visit.empty?
|
55
|
-
node = to_visit.pop
|
56
|
-
next if visited.include?(node)
|
57
|
-
visited << node
|
58
|
-
result[node] = :missed if result[node] == :hit
|
59
|
-
to_visit += parents[node] if parents.key?(node)
|
60
|
-
end
|
61
|
-
result.reject { |k, _| k.name.end_with?(".xccache") }
|
62
|
-
end
|
63
|
-
|
64
|
-
def verify_binary?(target, sdks)
|
65
|
-
return true if target.binary?
|
66
|
-
|
67
|
-
bpath = binary_path(target.xccache_id)
|
68
|
-
bpath_with_checksum = binary_path(target.xccache_id, checksum: target.checksum, in_repo: true)
|
69
|
-
|
70
|
-
check = proc do
|
71
|
-
# For macro, we just need the tool binary to exist
|
72
|
-
# For regular targets, the xcframework must satisfy the sdk constraints (ie. containing all the slices)
|
73
|
-
next bpath_with_checksum.exist? if target.macro?
|
74
|
-
|
75
|
-
metadata = XCFramework::Metadata.new(bpath_with_checksum / "Info.plist")
|
76
|
-
expected_triples = sdks.map { |sdk| sdk.triple(without_vendor: true) }
|
77
|
-
missing_triples = expected_triples - metadata.triples
|
78
|
-
missing_triples.empty?
|
79
|
-
end
|
80
|
-
|
81
|
-
# If requirements are meet, create symlink `A-abc123.xcframework` -> `A.framework`
|
82
|
-
# Otherwise, remove symlink `A.xcframework`
|
83
|
-
if check.call
|
84
|
-
bpath_with_checksum.symlink_to(bpath)
|
85
|
-
elsif bpath.exist?
|
86
|
-
bpath.rmtree
|
87
|
-
end
|
88
|
-
bpath.exist?
|
89
|
-
end
|
90
|
-
|
91
|
-
def binary_path(name, checksum: nil, in_repo: false)
|
92
|
-
suffix = checksum.nil? ? "" : "-#{checksum}"
|
93
|
-
ext = File.extname(name) == ".macro" ? ".macro" : ".xcframework"
|
94
|
-
binaries_dir = in_repo ? config.spm_cache_dir : config.spm_binaries_dir
|
95
|
-
p = binaries_dir / File.basename(name, ".*")
|
96
|
-
p / "#{p.basename}#{suffix}#{ext}"
|
97
|
-
end
|
98
|
-
|
99
|
-
def target_to_cytoscape_node(x, cache_data)
|
100
|
-
h = { :id => x.full_name, :cache => cache_data[x] }
|
101
|
-
h[:type] = if x.name.end_with?(".xccache") then "agg"
|
102
|
-
elsif x.macro? then "macro" end
|
103
|
-
h[:checksum] = x.checksum
|
104
|
-
h[:binary] = binary_path(x.xccache_id) if cache_data[x] == :hit
|
105
|
-
h
|
106
|
-
end
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module XCCache
|
2
|
-
module SPM
|
3
|
-
class Package
|
4
|
-
module UmbrellaDescsMixin
|
5
|
-
def gen_metadata
|
6
|
-
UI.section("Generating metadata of packages", timing: true) do
|
7
|
-
@descs, @descs_by_name = Description.descs_in_dir(root_dir, save_to_dir: config.spm_metadata_dir)
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def xccache_desc
|
12
|
-
@xccache_desc ||= desc_of("xccache")
|
13
|
-
end
|
14
|
-
|
15
|
-
def targets_of_products(products)
|
16
|
-
products = [products] if products.is_a?(String)
|
17
|
-
products.flat_map { |x| desc_of(x).targets_of_products(File.basename(x)) }
|
18
|
-
end
|
19
|
-
|
20
|
-
def dependency_targets_of_products(products)
|
21
|
-
products = [products] if products.is_a?(String)
|
22
|
-
products.flat_map { |p| @dependency_targets_by_products[p] || [p] }.uniq
|
23
|
-
end
|
24
|
-
|
25
|
-
def desc_of(d)
|
26
|
-
@descs_by_name[d.split("/").first]
|
27
|
-
end
|
28
|
-
|
29
|
-
def binary_targets
|
30
|
-
@descs_by_name.values.flatten.uniq.flat_map(&:binary_targets)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
module XCCache
|
2
|
-
module SPM
|
3
|
-
class Package
|
4
|
-
module UmbrellaManifestMixin
|
5
|
-
def write_manifest(no_cache: false)
|
6
|
-
UI.info("Writing Package.swift (package: #{root_dir.basename})")
|
7
|
-
Template.new("umbrella.Package.swift").render(
|
8
|
-
{
|
9
|
-
:timestamp => Time.new.strftime("%F %T"),
|
10
|
-
:json => manifest_targets_json(no_cache: no_cache),
|
11
|
-
:products_to_targets => manifest_products_to_targets_json(no_cache: no_cache),
|
12
|
-
:platforms => manifest_platforms,
|
13
|
-
:dependencies => manifest_pkg_dependencies,
|
14
|
-
:swift_version => Swift::Swiftc.version_without_patch,
|
15
|
-
},
|
16
|
-
save_to: root_dir / "Package.swift",
|
17
|
-
)
|
18
|
-
end
|
19
|
-
|
20
|
-
def manifest_targets_json(no_cache: false)
|
21
|
-
data = no_cache ? config.lockfile.targets_data : config.cachemap.manifest_data["targets"]
|
22
|
-
JSON.pretty_generate(data)
|
23
|
-
end
|
24
|
-
|
25
|
-
def manifest_products_to_targets_json(no_cache: false)
|
26
|
-
data = no_cache ? {} : config.cachemap.manifest_data["deps"]
|
27
|
-
JSON.pretty_generate(data)
|
28
|
-
end
|
29
|
-
|
30
|
-
def manifest_pkg_dependencies
|
31
|
-
decl = proc do |hash|
|
32
|
-
if (path_from_root = hash["path_from_root"])
|
33
|
-
absolute_path = (Pathname(".") / path_from_root).expand_path
|
34
|
-
next ".package(path: \"#{absolute_path}\")"
|
35
|
-
end
|
36
|
-
|
37
|
-
requirement = hash["requirement"]
|
38
|
-
case requirement["kind"]
|
39
|
-
when "upToNextMajorVersion"
|
40
|
-
opt = ".upToNextMajor(from: \"#{requirement['minimumVersion']}\")"
|
41
|
-
when "upToNextMinorVersion"
|
42
|
-
opt = ".upToNextMinor(from: \"#{requirement['minimumVersion']}\")"
|
43
|
-
when "exactVersion"
|
44
|
-
opt = "exact: \"#{requirement['version']}\""
|
45
|
-
when "branch"
|
46
|
-
opt = "branch: \"#{requirement['branch']}\""
|
47
|
-
when "revision"
|
48
|
-
opt = "revision: \"#{requirement['revision']}\""
|
49
|
-
when "versionRange"
|
50
|
-
opt = "\"#{requirement['minimumVersion']}\"..<\"#{requirement['maximumVersion']}\""
|
51
|
-
end
|
52
|
-
".package(url: \"#{hash['repositoryURL']}\", #{opt})"
|
53
|
-
end
|
54
|
-
|
55
|
-
config.lockfile.pkgs.map { |h| " #{decl.call(h)}," }.join("\n")
|
56
|
-
end
|
57
|
-
|
58
|
-
def manifest_platforms
|
59
|
-
@manifest_platforms ||= begin
|
60
|
-
to_spm_platform = {
|
61
|
-
:ios => "iOS",
|
62
|
-
:macos => "macOS",
|
63
|
-
:osx => "macOS",
|
64
|
-
:tvos => "tvOS",
|
65
|
-
:watchos => "watchOS",
|
66
|
-
:visionos => "visionOS",
|
67
|
-
}
|
68
|
-
hash = {}
|
69
|
-
config.project_targets.each do |t|
|
70
|
-
platform = to_spm_platform[t.platform_name]
|
71
|
-
hash[platform] ||= []
|
72
|
-
hash[platform] << t.deployment_target.split(".")[0]
|
73
|
-
end
|
74
|
-
hash
|
75
|
-
.transform_values(&:min)
|
76
|
-
.map { |platform, version| " .#{platform}(.v#{version})," }
|
77
|
-
.join("\n")
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module XCCache
|
2
|
-
module SPM
|
3
|
-
class Package
|
4
|
-
module UmbrellaVizMixin
|
5
|
-
def gen_cachemap_viz
|
6
|
-
stats = config.cachemap.stats
|
7
|
-
html_path = config.sandbox / "cachemap.html"
|
8
|
-
js_path = Dir.prepare(config.sandbox / "assets") / "cachemap.js"
|
9
|
-
css_path = config.sandbox / "assets" / "style.css"
|
10
|
-
|
11
|
-
root_dir = Pathname(".").expand_path
|
12
|
-
to_relative = proc do |p|
|
13
|
-
p.to_s.start_with?(root_dir.to_s) ? p.relative_path_from(root_dir).to_s : p.to_s
|
14
|
-
end
|
15
|
-
|
16
|
-
UI.info("Cachemap visualization: #{html_path}")
|
17
|
-
Template.new("cachemap.html").render(
|
18
|
-
{
|
19
|
-
:root_dir => root_dir.to_s,
|
20
|
-
:root_dir_short => root_dir.basename.to_s,
|
21
|
-
:lockfile_path => config.lockfile.path.to_s,
|
22
|
-
:lockfile_path_short => to_relative.call(config.lockfile.path),
|
23
|
-
:binaries_dir => config.spm_binaries_dir.to_s,
|
24
|
-
:binaries_dir_short => to_relative.call(config.spm_binaries_dir),
|
25
|
-
:desc_hit => stats[:hit],
|
26
|
-
:desc_missed => stats[:missed],
|
27
|
-
:desc_ignored => stats[:ignored],
|
28
|
-
},
|
29
|
-
save_to: html_path
|
30
|
-
)
|
31
|
-
Template.new("cachemap.js").render(
|
32
|
-
{ :json => JSON.pretty_generate(config.cachemap.depgraph_data) },
|
33
|
-
save_to: js_path
|
34
|
-
)
|
35
|
-
Template.new("cachemap.style.css").render(save_to: css_path)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
module XCCache
|
2
|
-
module SPM
|
3
|
-
class Package
|
4
|
-
module UmbrellaXCConfigsMixin
|
5
|
-
def gen_xcconfigs
|
6
|
-
UI.section("Generating xcconfigs") do
|
7
|
-
macros_config_by_targets.each do |target, hash|
|
8
|
-
xcconfig_path = config.spm_xcconfig_dir / "#{target}.xcconfig"
|
9
|
-
UI.message("XCConfig of target #{target} at: #{xcconfig_path}")
|
10
|
-
Xcodeproj::Config.new(hash).save_as(xcconfig_path)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
private
|
16
|
-
|
17
|
-
def macros_config_by_targets
|
18
|
-
config.cachemap.manifest_data["macros"].to_h do |target, macros|
|
19
|
-
swift_flags = macros.map do |m|
|
20
|
-
basename = File.basename(m, ".*")
|
21
|
-
binary_path = config.spm_binaries_dir / basename / "#{basename}.macro"
|
22
|
-
"-load-plugin-executable #{binary_path}##{basename}"
|
23
|
-
end
|
24
|
-
hash = { "OTHER_SWIFT_FLAGS" => "$(inherited) #{swift_flags.join(' ')}" }
|
25
|
-
[File.basename(target, ".*"), hash]
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
@@ -1,91 +0,0 @@
|
|
1
|
-
require "xccache/swift/swiftc"
|
2
|
-
require "xccache/utils/template"
|
3
|
-
require "xccache/cache/cachemap"
|
4
|
-
require "xccache/spm/pkg/base"
|
5
|
-
|
6
|
-
Dir["#{__dir__}/#{File.basename(__FILE__, '.rb')}/*.rb"].sort.each { |f| require f }
|
7
|
-
|
8
|
-
module XCCache
|
9
|
-
module SPM
|
10
|
-
class Package
|
11
|
-
class Umbrella < Package
|
12
|
-
include Config::Mixin
|
13
|
-
include UmbrellaCachemapMixin
|
14
|
-
include UmbrellaDescsMixin
|
15
|
-
include UmbrellaBuildMixin
|
16
|
-
include UmbrellaManifestMixin
|
17
|
-
include UmbrellaVizMixin
|
18
|
-
include UmbrellaXCConfigsMixin
|
19
|
-
|
20
|
-
def initialize(options = {})
|
21
|
-
super
|
22
|
-
@descs = []
|
23
|
-
@descs_by_name = {}
|
24
|
-
@dependency_targets_by_products = {}
|
25
|
-
end
|
26
|
-
|
27
|
-
def prepare(options = {})
|
28
|
-
create
|
29
|
-
resolve unless options[:skip_resolving_dependencies]
|
30
|
-
create_symlinks_for_convenience
|
31
|
-
create_symlinks_to_local_pkgs
|
32
|
-
gen_metadata
|
33
|
-
resolve_recursive_dependencies
|
34
|
-
create_symlinks_to_artifacts
|
35
|
-
sync_cachemap(sdks: options[:sdks])
|
36
|
-
end
|
37
|
-
|
38
|
-
def resolve_recursive_dependencies
|
39
|
-
UI.section("Resolving recursive dependencies")
|
40
|
-
@descs.each do |desc|
|
41
|
-
@dependency_targets_by_products.merge!(desc.resolve_recursive_dependencies.transform_keys(&:full_name))
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def create
|
46
|
-
UI.info("Creating umbrella package")
|
47
|
-
# Initially, write json with the original data in lockfile (without cache)
|
48
|
-
write_manifest(no_cache: true)
|
49
|
-
# Create dummy sources dirs prefixed with `.` so that they do not show up in Xcode
|
50
|
-
config.project_targets.each do |target|
|
51
|
-
dir = Dir.prepare(root_dir / ".Sources" / "#{target.name}.xccache")
|
52
|
-
(dir / "dummy.swift").write("")
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
def create_symlinks_for_convenience
|
57
|
-
# Symlinks for convenience
|
58
|
-
(root_dir / "binaries").symlink_to(root_dir.parent / "binaries")
|
59
|
-
(root_dir / ".build").symlink_to(root_dir.parent / ".build")
|
60
|
-
(root_dir / ".build/checkouts").symlink_to(root_dir.parent / "checkouts")
|
61
|
-
end
|
62
|
-
|
63
|
-
def create_symlinks_to_local_pkgs
|
64
|
-
pkg_desc.dependencies.select(&:local?).each do |dep|
|
65
|
-
# For metadata generation
|
66
|
-
dep.path.symlink_to(root_dir / ".build/checkouts/#{dep.slug}")
|
67
|
-
# For convenience, synced group under `xccache.config` group in xcodeproj
|
68
|
-
dep.path.symlink_to(Config.instance.spm_local_pkgs_dir / dep.slug)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def create_symlinks_to_artifacts
|
73
|
-
# Clean up symlinks beforehand
|
74
|
-
config.spm_binaries_dir.glob("*/*.{xcframework,macro}").each do |p|
|
75
|
-
p.rmtree if p.symlink?
|
76
|
-
end
|
77
|
-
|
78
|
-
binary_targets.each do |target|
|
79
|
-
dst_path = config.spm_binaries_dir / target.name / "#{target.name}.xcframework"
|
80
|
-
# For local xcframework, just symlink to the path
|
81
|
-
# Zip frameworks (either of local or remote pkgs) are unzipped in the build artifacts
|
82
|
-
target.local_binary_path.symlink_to(dst_path) if target.local_binary_path&.extname == ".xcframework"
|
83
|
-
config.spm_artifacts_dir.glob("#{target.full_name}/*.xcframework").each do |p|
|
84
|
-
p.symlink_to(dst_path)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|