xccache 0.0.2 → 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.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/lib/xccache/cache/cachemap.rb +28 -11
  3. data/lib/xccache/command/base.rb +1 -4
  4. data/lib/xccache/command/build.rb +1 -14
  5. data/lib/xccache/command/off.rb +26 -0
  6. data/lib/xccache/command.rb +10 -1
  7. data/lib/xccache/core/config.rb +10 -4
  8. data/lib/xccache/core/lockfile.rb +4 -0
  9. data/lib/xccache/core/sh.rb +3 -17
  10. data/lib/xccache/core/syntax/hash.rb +4 -0
  11. data/lib/xccache/core/system.rb +2 -1
  12. data/lib/xccache/installer/build.rb +3 -1
  13. data/lib/xccache/installer/integration/build.rb +28 -0
  14. data/lib/xccache/installer/integration/descs.rb +27 -0
  15. data/lib/xccache/installer/integration/supporting_files.rb +29 -0
  16. data/lib/xccache/installer/integration/viz.rb +38 -0
  17. data/lib/xccache/installer/integration.rb +12 -0
  18. data/lib/xccache/installer.rb +33 -9
  19. data/lib/xccache/spm/build.rb +1 -1
  20. data/lib/xccache/spm/desc/base.rb +1 -4
  21. data/lib/xccache/spm/desc/desc.rb +2 -30
  22. data/lib/xccache/spm/mixin.rb +5 -4
  23. data/lib/xccache/spm/pkg/base.rb +40 -34
  24. data/lib/xccache/spm/pkg/proxy.rb +60 -0
  25. data/lib/xccache/spm/pkg/proxy_executable.rb +51 -0
  26. data/lib/xccache/utils/template.rb +1 -1
  27. data/lib/xccache/xcodeproj/pkg.rb +1 -1
  28. data/lib/xccache/xcodeproj/pkg_product_dependency.rb +2 -2
  29. data/lib/xccache/xcodeproj/project.rb +3 -3
  30. data/lib/xccache/xcodeproj/target.rb +2 -2
  31. data/lib/xccache.rb +5 -0
  32. metadata +12 -12
  33. data/lib/xccache/assets/templates/umbrella.Package.swift.template +0 -182
  34. data/lib/xccache/spm/pkg/umbrella/build.rb +0 -30
  35. data/lib/xccache/spm/pkg/umbrella/cachemap.rb +0 -110
  36. data/lib/xccache/spm/pkg/umbrella/descs.rb +0 -35
  37. data/lib/xccache/spm/pkg/umbrella/manifest.rb +0 -83
  38. data/lib/xccache/spm/pkg/umbrella/viz.rb +0 -40
  39. data/lib/xccache/spm/pkg/umbrella/xcconfigs.rb +0 -31
  40. data/lib/xccache/spm/pkg/umbrella.rb +0 -91
@@ -2,11 +2,15 @@ require "json"
2
2
  require "xccache/spm/xcframework/slice"
3
3
  require "xccache/spm/xcframework/xcframework"
4
4
  require "xccache/spm/xcframework/metadata"
5
+ require "xccache/spm/pkg/proxy"
5
6
  require "xccache/swift/sdk"
6
7
 
7
8
  module XCCache
8
9
  module SPM
9
10
  class Package
11
+ include Config::Mixin
12
+ include Proxy::Mixin
13
+
10
14
  include Cacheable
11
15
  cacheable :pkg_desc_of_target
12
16
 
@@ -14,7 +18,6 @@ module XCCache
14
18
 
15
19
  def initialize(options = {})
16
20
  @root_dir = Pathname(options[:root_dir] || ".").expand_path
17
- @warn_if_not_direct_target = options.fetch(:warn_if_not_direct_target, true)
18
21
  end
19
22
 
20
23
  def build(options = {})
@@ -33,7 +36,10 @@ module XCCache
33
36
  end
34
37
 
35
38
  def build_target(target: nil, sdks: nil, config: nil, out_dir: nil, **options)
36
- target_pkg_desc = pkg_desc_of_target(target, skip_resolving_dependencies: options[:skip_resolving_dependencies])
39
+ target_pkg_desc = pkg_desc_of_target(
40
+ target,
41
+ ensure_exist: true,
42
+ )
37
43
  if target_pkg_desc.binary_targets.any? { |t| t.name == target }
38
44
  return UI.warn("Target #{target} is a binary target -> no need to build")
39
45
  end
@@ -42,33 +48,44 @@ module XCCache
42
48
 
43
49
  out_dir = Pathname(out_dir || ".")
44
50
  out_dir /= target.name if options[:checksum]
51
+ ext = target.macro? ? ".macro" : ".xcframework"
45
52
  basename = options[:checksum] ? "#{target.name}-#{target.checksum}" : target.name
46
- basename += target.macro? ? ".macro" : ".xcframework"
53
+ binary_path = out_dir / "#{basename}#{ext}"
47
54
 
48
- Dir.create_tmpdir do |_tmpdir|
55
+ Dir.create_tmpdir do |tmpdir|
49
56
  cls = target.macro? ? Macro : XCFramework
50
57
  cls.new(
51
58
  name: target.name,
52
59
  pkg_dir: root_dir,
53
60
  config: config,
54
61
  sdks: sdks,
55
- path: out_dir / basename,
56
- tmpdir: Dir.create_tmpdir,
62
+ path: binary_path,
63
+ tmpdir: tmpdir,
57
64
  pkg_desc: target_pkg_desc,
58
65
  library_evolution: options[:library_evolution],
59
66
  ).build(**options)
60
67
  end
68
+ return if (symlinks_dir = options[:symlinks_dir]).nil?
69
+ binary_path.symlink_to(symlinks_dir / target.name / "#{target.name}#{ext}")
61
70
  end
62
71
 
63
- def resolve(force: false)
64
- return if @resolved && !force
65
-
66
- UI.section("Resolving package dependencies (package: #{root_dir.basename})", timing: true) do
67
- Sh.run("swift package resolve --package-path #{root_dir} 2>&1")
68
- end
72
+ def resolve
73
+ return if @resolved
74
+ xccache_proxy.run("resolve --pkg #{root_dir} --metadata #{metadata_dir}")
69
75
  @resolved = true
70
76
  end
71
77
 
78
+ def pkg_desc_of_target(name, **options)
79
+ resolve
80
+ desc = descs.find { |d| d.has_target?(name) }
81
+ raise GeneralError, "Cannot find package with the given target #{name}" if options[:ensure_exist] && desc.nil?
82
+ desc
83
+ end
84
+
85
+ def get_target(name)
86
+ pkg_desc_of_target(name)&.get_target(name)
87
+ end
88
+
72
89
  private
73
90
 
74
91
  def validate!
@@ -76,31 +93,20 @@ module XCCache
76
93
  raise GeneralError, "No Package.swift in #{root_dir}. Are you sure you're running on a package dir?"
77
94
  end
78
95
 
79
- def pkg_desc_of_target(name, skip_resolving_dependencies: false)
80
- # The current package contains the given target
81
- return pkg_desc if pkg_desc.has_target?(name)
96
+ def metadata_dir
97
+ config.in_installation? ? config.spm_metadata_dir : root_dir / ".build/metadata"
98
+ end
82
99
 
83
- if @warn_if_not_direct_target
84
- UI.message(
85
- "#{name.yellow.dark} is not a direct target of package #{root_dir.basename.to_s.dark} " \
86
- "-> trigger from dependencies"
87
- )
88
- end
89
- # Otherwise, it's inside one of the dependencies. Need to resolve then find it
90
- resolve unless skip_resolving_dependencies
91
-
92
- @descs ||= if Config.instance.in_installation?
93
- then Description.descs_in_metadata_dir[0]
94
- else
95
- Description.descs_in_dir(Pathname(".").expand_path)[0]
96
- end
97
- desc = @descs.find { |d| d.has_target?(name) }
98
- return desc unless desc.nil?
99
- raise GeneralError, "Cannot find package with the given target #{name}"
100
+ def descs
101
+ @descs ||= load_descs[0]
102
+ end
103
+
104
+ def descs_by_name
105
+ @descs_by_name ||= load_descs[1]
100
106
  end
101
107
 
102
- def pkg_desc
103
- @pkg_desc ||= Description.in_dir(root_dir)
108
+ def load_descs
109
+ @descs, @descs_by_name = Description.descs_in_metadata_dir(metadata_dir)
104
110
  end
105
111
  end
106
112
  end
@@ -0,0 +1,60 @@
1
+ Dir["#{__dir__}/#{File.basename(__FILE__, '.rb')}/*.rb"].sort.each { |f| require f }
2
+ require_relative "proxy_executable"
3
+
4
+ module XCCache
5
+ module SPM
6
+ class Package
7
+ class Proxy < Package
8
+ module Mixin
9
+ def xccache_proxy
10
+ @xccache_proxy ||= Executable.new
11
+ end
12
+ end
13
+
14
+ include Mixin
15
+
16
+ def umbrella
17
+ @umbrella ||= Package.new(root_dir: config.spm_umbrella_sandbox)
18
+ end
19
+
20
+ def prepare(options = {})
21
+ xccache_proxy.run("gen-umbrella")
22
+ umbrella.resolve
23
+ invalidate_cache(sdks: options[:sdks])
24
+ gen_proxy
25
+ end
26
+
27
+ def gen_proxy
28
+ xccache_proxy.run("gen-proxy")
29
+ config.cachemap.update_from_graph(graph.reload)
30
+ end
31
+
32
+ def invalidate_cache(sdks: [])
33
+ UI.message("Invalidating cache (sdks: #{sdks.map(&:name)})")
34
+
35
+ config.spm_cache_dir.glob("*/*.{xcframework,macro}").each do |p|
36
+ cmps = p.basename(".*").to_s.split("-")
37
+ name, checksum = cmps[...-1].join("-"), cmps[-1]
38
+ p_without_checksum = config.spm_binaries_dir / name / "#{name}#{p.extname}"
39
+ accept_cache = proc { p.symlink_to(p_without_checksum) }
40
+ reject_cache = proc { p_without_checksum.rmtree if p_without_checksum.exist? }
41
+ next reject_cache.call if (target = umbrella.get_target(name)).nil?
42
+ next reject_cache.call if target.checksum != checksum
43
+ # For macro, we just need the tool binary to exist
44
+ next accept_cache.call if target.macro?
45
+
46
+ # For regular targets, the xcframework must satisfy the sdk constraints (ie. containing all the slices)
47
+ metadata = XCFramework::Metadata.new(p / "Info.plist")
48
+ expected_triples = sdks.map { |sdk| sdk.triple(without_vendor: true) }
49
+ missing_triples = expected_triples - metadata.triples
50
+ missing_triples.empty? ? accept_cache.call : reject_cache.call
51
+ end
52
+ end
53
+
54
+ def graph
55
+ @graph ||= JSONRepresentable.new(root_dir / "graph.json")
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,51 @@
1
+ module XCCache
2
+ module SPM
3
+ class Package
4
+ class Proxy < Package
5
+ class Executable
6
+ VERSION = "0.0.1rc3".freeze
7
+
8
+ def run(cmd)
9
+ env = { "FORCE_OUTPUT" => "console", "FORCE_COLOR" => "1" } if Config.instance.ansi?
10
+ cmd = cmd.is_a?(Array) ? [bin_path.to_s] + cmd : [bin_path.to_s, cmd]
11
+ Sh.run(cmd, env: env)
12
+ end
13
+
14
+ def bin_path
15
+ @bin_path ||= lookup
16
+ end
17
+
18
+ private
19
+
20
+ def lookup
21
+ [
22
+ local_bin_path,
23
+ default_bin_path,
24
+ ].find(&:exist?) || download
25
+ end
26
+
27
+ def download
28
+ UI.section("Downloading xccache-proxy binary from remote...".magenta) do
29
+ Dir.create_tmpdir do |dir|
30
+ url = "https://github.com/trinhngocthuyen/xccache-proxy/releases/download/#{VERSION}/xccache-proxy.zip"
31
+ default_bin_path.parent.mkpath
32
+ tmp_path = dir / File.basename(url)
33
+ Sh.run("curl -fSL -o #{tmp_path} #{url} && unzip -d #{default_bin_path.parent} #{tmp_path}")
34
+ FileUtils.chmod("+x", default_bin_path)
35
+ end
36
+ end
37
+ default_bin_path
38
+ end
39
+
40
+ def default_bin_path
41
+ @default_bin_path ||= LIBEXEC / ".download" / "xccache-proxy-#{VERSION}" / "xccache-proxy"
42
+ end
43
+
44
+ def local_bin_path
45
+ @local_bin_path ||= LIBEXEC / ".local" / "xccache-proxy"
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -7,7 +7,7 @@ module XCCache
7
7
 
8
8
  def initialize(name)
9
9
  @name = name
10
- @path = Gem.find_files("xccache/assets/templates/#{name}.template").first
10
+ @path = ROOT / "lib/xccache/assets/templates/#{name}.template"
11
11
  end
12
12
 
13
13
  def render(hash = {}, save_to: nil)
@@ -17,7 +17,7 @@ module Xcodeproj
17
17
  end
18
18
 
19
19
  def xccache_pkg?
20
- local? && id == "xccache/packages/umbrella"
20
+ local? && ["xccache/packages/umbrella", "xccache/packages/proxy"].include?(id)
21
21
  end
22
22
 
23
23
  def non_xccache_pkg?
@@ -12,12 +12,12 @@ module Xcodeproj
12
12
  return package if package
13
13
  return if @warned_missing_pkg
14
14
  @warned_missing_pkg = true
15
- XCCache::UI.warn("Missing pkg of product dependency #{uuid}: #{to_hash}")
15
+ Log.warn("Missing pkg of product dependency #{uuid}: #{to_hash}")
16
16
  end
17
17
 
18
18
  def remove_alongside_related
19
19
  target = referrers.find { |x| x.is_a?(PBXNativeTarget) }
20
- XCCache::UI.info(
20
+ Log.info(
21
21
  "(-) Remove #{product_name.red} from product dependencies of target #{target.display_name.bold}"
22
22
  )
23
23
  target.dependencies.each { |x| x.remove_from_project if x.product_ref == self }
@@ -41,7 +41,7 @@ module Xcodeproj
41
41
  pkg_hash = XCCache::Lockfile::Pkg.from_h(hash)
42
42
  pkg_hash["relative_path"] = pkg_hash.relative_path_from_dir(dir).to_s if pkg_hash.key == "path_from_root"
43
43
 
44
- Log.message("Add package #{pkg_hash.id.bold} to project #{display_name.bold}")
44
+ Log.info("Add package #{pkg_hash.id.bold} to project #{display_name.bold}")
45
45
  cls = pkg_hash.local? ? XCLocalSwiftPackageReference : XCRemoteSwiftPackageReference
46
46
  ref = new(cls)
47
47
  custom_keys = ["path_from_root"]
@@ -51,13 +51,13 @@ module Xcodeproj
51
51
  end
52
52
 
53
53
  def add_xccache_pkg
54
- sandbox_path = XCCache::Config.instance.spm_umbrella_sandbox
54
+ sandbox_path = XCCache::Config.instance.spm_proxy_sandbox
55
55
  add_pkg("relative_path" => sandbox_path.relative_path_from(path.parent).to_s)
56
56
  end
57
57
 
58
58
  def remove_pkgs(&block)
59
59
  pkgs.select(&block).each do |pkg|
60
- XCCache::UI.info("(-) Remove #{pkg.display_name.red} from package refs of project #{display_name.bold}")
60
+ Log.info("(-) Remove #{pkg.display_name.red} from package refs of project #{display_name.bold}")
61
61
  pkg.remove_from_project
62
62
  end
63
63
  end
@@ -19,14 +19,14 @@ module Xcodeproj
19
19
  end
20
20
 
21
21
  def add_pkg_product_dependency(name)
22
- Log.message("(+) Add dependency #{name.blue} to target #{display_name.bold}")
22
+ Log.info("(+) Add dependency #{name.blue} to target #{display_name.bold}")
23
23
  pkg_name, product_name = name.split("/")
24
24
  pkg = project.get_pkg(pkg_name)
25
25
  pkg_product_dependencies << pkg.create_target_dependency_ref(product_name).product_ref
26
26
  end
27
27
 
28
28
  def add_xccache_product_dependency
29
- add_pkg_product_dependency("umbrella/#{name}.xccache")
29
+ add_pkg_product_dependency("proxy/#{name}.xccache")
30
30
  end
31
31
 
32
32
  def remove_xccache_product_dependencies
data/lib/xccache.rb CHANGED
@@ -1 +1,6 @@
1
1
  require "xccache/main"
2
+
3
+ module XCCache
4
+ ROOT = Pathname(__dir__).parent
5
+ LIBEXEC = ROOT / "libexec"
6
+ end
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.2
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-18 00:00:00.000000000 Z
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/umbrella.rb
123
- - lib/xccache/spm/pkg/umbrella/build.rb
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: '0'
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