xccache 1.0.2 → 1.0.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2357c61b242803e69f54fe2b9a4db8eef00deabb636dbd98e84a808bd6c3d56a
4
- data.tar.gz: b4d9615136cb599bff14e73ef51472c6b6d3838acd5518d6e17ce9446275de4a
3
+ metadata.gz: e985d50b212e526c36c94d40d93210a81850267fb205a3c2b10aee659357a039
4
+ data.tar.gz: 8e720a6bda28fc18cefd3bcc18b37aab2ecbf29acee27f688db5508ab9c38af2
5
5
  SHA512:
6
- metadata.gz: b353117fdc74f92fe4c091d94936b55548b7f4b8450441dd51ebe6728b4513960af76f0278095b7f777aec0189c5c371c8a268a10092d1d522494b7da26e4f74
7
- data.tar.gz: ab9c2d5bb982bb0d7c86703ca4d1ca84ab1a3b8598eb671400a0eee47ac1caf26ff54cf9d2567c47d35702eca071d909b648243d2fa194f0b982b3d879ec7cbb
6
+ metadata.gz: 7f84d4d129ae5e4b5e07aa96dd47d9618d9f117f2a28679f49de286075173eac12c51e8c4c47b52d85da20d5fb024cd395b1e76c3203598a5199a05c278d6027
7
+ data.tar.gz: e0d610301f133cc22ede54d34db62e57bf1f98701b3f57b408217c6a92ccb21ba6a65a0296e102c98bd337963544d4333918aa9c4aa6556c1eea118343c7ef69
@@ -57,15 +57,18 @@ module XCCache
57
57
  end
58
58
 
59
59
  def get_cache_data(type)
60
- cache_data.select { |k, v| v == type && !k.end_with?(".xccache") }.keys
60
+ cache_data.select { |_, v| v == type }.keys
61
61
  end
62
62
 
63
63
  def update_from_graph(graph)
64
- cache_data = graph["cache"].to_h do |k, v|
65
- next [k, :hit] if v
66
- next [k, :ignored] if Config.instance.ignore?(k)
67
- [k, :missed]
68
- end
64
+ cache_data =
65
+ graph["cache"]
66
+ .reject { |k, _| k.end_with?(".xccache") }
67
+ .to_h do |k, v|
68
+ next [k, :hit] if v
69
+ next [k, :ignored] if Config.instance.ignore?(k)
70
+ [k, :missed]
71
+ end
69
72
 
70
73
  deps = graph["deps"]
71
74
  edges = deps.flat_map { |k, xs| xs.map { |v| { :source => k, :target => v } } }
@@ -5,6 +5,7 @@ module XCCache
5
5
  class Options
6
6
  SDK = ["--sdk=foo,bar", "SDKs (iphonesimulator, iphoneos, macos, etc.)"].freeze
7
7
  CONFIG = ["--config=foo", "Configuration (debug, release) (default: debug)"].freeze
8
+ LOG_DIR = ["--log-dir=foo", "Build log directory"].freeze
8
9
  MERGE_SLICES = [
9
10
  "--merge-slices/--no-merge-slices",
10
11
  "Whether to merge with existing slices/sdks in the xcframework (default: true)",
@@ -19,7 +20,7 @@ module XCCache
19
20
  end
20
21
 
21
22
  def self.build_options
22
- install_options + [MERGE_SLICES, LIBRARY_EVOLUTION]
23
+ install_options + [LOG_DIR, MERGE_SLICES, LIBRARY_EVOLUTION]
23
24
  end
24
25
  end
25
26
  end
@@ -24,6 +24,7 @@ module XCCache
24
24
  }
25
25
  @build_options = {
26
26
  **@install_options,
27
+ :log_dir => argv.option("log-dir"),
27
28
  :recursive => argv.flag?("recursive"),
28
29
  :merge_slices => argv.flag?("merge-slices", true),
29
30
  :library_evolution => argv.flag?("library-evolution"),
@@ -40,11 +40,11 @@ module XCCache
40
40
  end
41
41
 
42
42
  def spm_local_pkgs_dir
43
- @spm_local_pkgs_dir ||= Dir.prepare(spm_sandbox / "local", clean: true)
43
+ @spm_local_pkgs_dir ||= Dir.prepare(spm_sandbox / "local")
44
44
  end
45
45
 
46
- def spm_xcconfig_dir
47
- @spm_xcconfig_dir ||= Dir.prepare(spm_sandbox / "xcconfigs", clean: true)
46
+ def spm_xcconfigs_dir
47
+ @spm_xcconfigs_dir ||= Dir.prepare(spm_sandbox / "xcconfigs")
48
48
  end
49
49
 
50
50
  def spm_cache_dir
@@ -52,7 +52,7 @@ module XCCache
52
52
  end
53
53
 
54
54
  def spm_binaries_dir
55
- @spm_binaries_dir ||= Dir.prepare(spm_sandbox / "binaries", clean: true)
55
+ @spm_binaries_dir ||= Dir.prepare(spm_sandbox / "binaries")
56
56
  end
57
57
 
58
58
  def spm_build_dir
@@ -0,0 +1,82 @@
1
+ require "monitor"
2
+ require "tty-cursor"
3
+ require "tty-screen"
4
+
5
+ module XCCache
6
+ class LiveLog
7
+ include UI::Mixin
8
+ CURSOR_LOCK = Monitor.new
9
+
10
+ attr_reader :output, :max_lines, :lines, :cursor, :tee
11
+
12
+ def initialize(**options)
13
+ @output = options[:output] || $stdout
14
+ @max_lines = options[:max_lines] || 5
15
+ @n_sticky = 0
16
+ @lines = []
17
+ @cursor = TTY::Cursor
18
+ @screen = TTY::Screen
19
+ @tee = options[:tee]
20
+ end
21
+
22
+ def clear
23
+ commit do
24
+ output.print(cursor.clear_lines(lines.count + @n_sticky))
25
+ @lines = []
26
+ @n_sticky = 0
27
+ end
28
+ end
29
+
30
+ def puts(line, sticky: false)
31
+ commit do
32
+ output.print(cursor.clear_lines(lines.count + 1))
33
+ if sticky
34
+ @n_sticky += 1
35
+ output.puts(truncated(line))
36
+ else
37
+ lines.shift if lines.count >= max_lines
38
+ lines << truncated(line)
39
+ end
40
+ output.puts(lines) # print non-sticky content
41
+ end
42
+ File.open(tee, "a") { |f| f << "#{line}\n" } if tee
43
+ end
44
+
45
+ def capture(header)
46
+ header_start = header.magenta.bold
47
+ header_success = "#{header} ✔".green.bold
48
+ header_error = "#{header} ✖".red.bold
49
+ puts(header_start, sticky: true)
50
+ yield if block_given?
51
+ clear
52
+ update_header(header_success)
53
+ rescue StandardError => e
54
+ update_header(header_error)
55
+ raise e
56
+ end
57
+
58
+ private
59
+
60
+ def update_header(header)
61
+ commit do
62
+ n = lines.count + @n_sticky
63
+ output.print(cursor.up(n) + header + cursor.column(0) + cursor.down(n))
64
+ end
65
+ end
66
+
67
+ def commit
68
+ CURSOR_LOCK.synchronize do
69
+ yield
70
+ output.flush
71
+ end
72
+ end
73
+
74
+ def truncated(msg)
75
+ msg.length > @screen.width ? "#{msg[...@screen.width - 3]}..." : msg
76
+ end
77
+
78
+ def ui_cls
79
+ self
80
+ end
81
+ end
82
+ end
@@ -5,13 +5,13 @@ module XCCache
5
5
  module UI
6
6
  @indent = 0
7
7
 
8
- class << self
8
+ module Mixin
9
9
  include Config::Mixin
10
10
  attr_accessor :indent
11
11
 
12
12
  def section(title, timing: false)
13
13
  start = Time.new if timing
14
- UI.puts(title)
14
+ ui_cls.puts(title)
15
15
  self.indent += 2
16
16
  res = yield if block_given?
17
17
  self.indent -= 2
@@ -22,25 +22,25 @@ module XCCache
22
22
  else
23
23
  "#{duration / 3600}h"
24
24
  end
25
- UI.puts("-> Finished: #{title.dark} (#{duration})")
25
+ ui_cls.puts("-> Finished: #{title.dark} (#{duration})")
26
26
  end
27
27
  res
28
28
  end
29
29
 
30
30
  def message(message)
31
- UI.puts(message) if config.verbose?
31
+ ui_cls.puts(message) if config.verbose?
32
32
  end
33
33
 
34
34
  def info(message)
35
- UI.puts(message)
35
+ ui_cls.puts(message)
36
36
  end
37
37
 
38
38
  def warn(message)
39
- UI.puts(message.yellow)
39
+ ui_cls.puts(message.yellow)
40
40
  end
41
41
 
42
42
  def error(message)
43
- UI.puts("[ERROR] #{message}".red)
43
+ ui_cls.puts("[ERROR] #{message}".red)
44
44
  end
45
45
 
46
46
  def error!(message)
@@ -51,6 +51,16 @@ module XCCache
51
51
  def puts(message)
52
52
  $stdout.puts("#{' ' * self.indent}#{message}")
53
53
  end
54
+
55
+ private
56
+
57
+ def ui_cls
58
+ UI
59
+ end
60
+ end
61
+
62
+ class << self
63
+ include Mixin
54
64
  end
55
65
  end
56
66
  end
@@ -17,14 +17,25 @@ module XCCache
17
17
 
18
18
  def run(*args, env: nil, **options)
19
19
  cmd = args.join(" ")
20
- UI.message("$ #{cmd}".cyan.dark) if config.verbose? && options[:log_cmd] != false
21
- return system(cmd) || (raise GeneralError, "Command '#{cmd}' failed") unless options[:capture]
22
20
 
23
21
  out, err = [], []
22
+ handle_out = options[:handle_out] || proc { |l| out << l }
23
+ handle_err = options[:handle_err] || proc { |l| err << l }
24
+ if (live_log = options[:live_log])
25
+ handle_out = proc { |l| live_log.puts(l) }
26
+ handle_err = proc { |l| live_log.puts(l) }
27
+ live_log.puts("$ #{cmd}") if options[:log_cmd] != false
28
+ elsif options[:log_cmd] != false
29
+ UI.message("$ #{cmd}".cyan.dark)
30
+ end
31
+
32
+ use_popen = options[:capture] || options[:handle_out] || options[:handle_err] || options[:live_log]
33
+ return system(cmd) || (raise GeneralError, "Command '#{cmd}' failed") unless use_popen
34
+
24
35
  popen3_args = env ? [env, cmd] : [cmd]
25
36
  Open3.popen3(*popen3_args) do |_stdin, stdout, stderr, wait_thr|
26
- stdout_thread = Thread.new { stdout.each { |l| out << l } }
27
- stderr_thread = Thread.new { stderr.each { |l| err << l } }
37
+ stdout_thread = Thread.new { stdout.each { |l| handle_out.call(l.strip) } }
38
+ stderr_thread = Thread.new { stderr.each { |l| handle_err.call(l.strip) } }
28
39
  [stdout_thread, stderr_thread].each(&:join)
29
40
  result = wait_thr.value
30
41
  result.exitstatus
@@ -32,6 +43,13 @@ module XCCache
32
43
  end
33
44
  [out.join("\n"), err.join("\n")]
34
45
  end
46
+
47
+ private
48
+
49
+ def log_cmd(cmd, live_log: nil)
50
+ return live_log.puts("$ #{cmd}") if live_log
51
+ UI.message("$ #{cmd}".cyan.dark)
52
+ end
35
53
  end
36
54
  end
37
55
  end
@@ -11,7 +11,7 @@ module XCCache
11
11
 
12
12
  def gen_xcconfigs
13
13
  macros_config_by_targets.each do |target, hash|
14
- xcconfig_path = config.spm_xcconfig_dir / "#{target}.xcconfig"
14
+ xcconfig_path = config.spm_xcconfigs_dir / "#{target}.xcconfig"
15
15
  UI.message("XCConfig of target #{target} at: #{xcconfig_path}")
16
16
  Xcodeproj::Config.new(hash).save_as(xcconfig_path)
17
17
  end
@@ -17,6 +17,7 @@ module XCCache
17
17
 
18
18
  def perform_install
19
19
  verify_projects!
20
+ recreate_config_dirs
20
21
  projects.each { |project| migrate_umbrella_to_proxy(project) }
21
22
  UI.message("Using cache dir: #{config.spm_cache_dir}")
22
23
  config.ensure_file!
@@ -106,9 +107,9 @@ module XCCache
106
107
  end
107
108
 
108
109
  def inject_xcconfig_to_project(project)
109
- group = project.xccache_config_group.ensure_synced_group(name: "xcconfigs", path: config.spm_xcconfig_dir)
110
+ group = project.xccache_config_group.ensure_synced_group(name: "xcconfigs", path: config.spm_xcconfigs_dir)
110
111
  project.targets.each do |target|
111
- xcconfig_path = config.spm_xcconfig_dir / "#{target.name}.xcconfig"
112
+ xcconfig_path = config.spm_xcconfigs_dir / "#{target.name}.xcconfig"
112
113
  target.build_configurations.each do |build_config|
113
114
  if (existing = build_config.base_configuration_xcconfig)
114
115
  next if existing.path == xcconfig_path
@@ -145,5 +146,14 @@ module XCCache
145
146
  ref.path = "xccache/packages/proxy/Package.swift"
146
147
  end
147
148
  end
149
+
150
+ def recreate_config_dirs
151
+ [
152
+ config.spm_binaries_dir,
153
+ config.spm_local_pkgs_dir,
154
+ config.spm_xcconfigs_dir,
155
+ config.spm_metadata_dir,
156
+ ].each { |p| Dir.prepare(p, clean: true) }
157
+ end
148
158
  end
149
159
  end
@@ -1,7 +1,8 @@
1
1
  module XCCache
2
2
  module SPM
3
3
  class Buildable
4
- attr_reader :name, :module_name, :pkg_dir, :pkg_desc, :sdk, :sdks, :config, :path, :tmpdir, :library_evolution
4
+ attr_reader :name, :module_name, :pkg_dir, :pkg_desc, :sdk, :sdks, :config, :path, :tmpdir, :library_evolution,
5
+ :live_log
5
6
  alias library_evolution? library_evolution
6
7
 
7
8
  def initialize(options = {})
@@ -9,12 +10,15 @@ module XCCache
9
10
  @module_name = @name.c99extidentifier
10
11
  @pkg_dir = Pathname(options[:pkg_dir] || ".").expand_path
11
12
  @pkg_desc = options[:pkg_desc]
13
+ @ctx_desc = options[:ctx_desc] # Context desc, could be an umbrella or a standalone pkg
12
14
  @sdks = options[:sdks] || []
13
15
  @sdk = options[:sdk] || @sdks&.first
14
16
  @config = options[:config] || "debug"
15
17
  @path = options[:path]
16
18
  @tmpdir = options[:tmpdir]
17
19
  @library_evolution = options[:library_evolution]
20
+ @sdks.each { |sdk| sdk.version = @ctx_desc.platforms[sdk.platform] } if @ctx_desc
21
+ @live_log = options[:live_log]
18
22
  end
19
23
 
20
24
  def build(options = {})
@@ -35,13 +39,17 @@ module XCCache
35
39
  cmd << "-Xswiftc" << "-emit-module-interface"
36
40
  cmd << "-Xswiftc" << "-no-verify-emitted-module-interface"
37
41
  end
38
- Sh.run(cmd)
42
+ sh(cmd)
43
+ end
44
+
45
+ def sh(cmd)
46
+ Sh.run(cmd, live_log: live_log)
39
47
  end
40
48
 
41
49
  def swift_build_args
42
50
  [
43
51
  "--configuration", config,
44
- "--triple", sdk.triple,
52
+ "--triple", sdk.triple(with_version: true),
45
53
  ]
46
54
  end
47
55
 
@@ -19,6 +19,10 @@ module XCCache
19
19
  raw["_metadata"] ||= {}
20
20
  end
21
21
 
22
+ def platforms
23
+ @platforms ||= raw.fetch("platforms", []).to_h { |h| [h["platformName"].to_sym, h["version"]] }
24
+ end
25
+
22
26
  def dependencies
23
27
  @dependencies ||= fetch("dependencies", Dependency)
24
28
  end
@@ -21,7 +21,7 @@ module XCCache
21
21
  # -> WORKAROUND: Find the associated regular target and build it, then collect the tool binary
22
22
  # ---------------------------------------------------------------------------------
23
23
  associated_target = pkg_desc.targets.find { |t| t.direct_dependency_targets.include?(pkg_target) }
24
- UI.message(
24
+ live_log.info(
25
25
  "#{name.yellow.dark} is a macro target. " \
26
26
  "Will build the associated target #{associated_target.name.dark} to get the tool binary."
27
27
  )
@@ -30,7 +30,7 @@ module XCCache
30
30
  raise GeneralError, "Tool binary not exist at: #{binary_path}" unless binary_path.exist?
31
31
  binary_path.copy(to: path)
32
32
  FileUtils.chmod("+x", path)
33
- UI.info("-> Macro binary: #{path.to_s.dark}")
33
+ live_log.info("-> Macro binary: #{path}")
34
34
  end
35
35
 
36
36
  def products_dir
@@ -22,14 +22,19 @@ module XCCache
22
22
 
23
23
  def build(options = {})
24
24
  validate!
25
- targets = options.delete(:targets) || []
25
+ targets = (options.delete(:targets) || []).map { |t| t.split("/")[-1] }
26
26
  raise GeneralError, "No targets were specified" if targets.empty?
27
27
 
28
- targets.map { |t| t.split("/")[-1] }.each_with_index do |t, i|
29
- UI.section("\n▶ Building target: #{t} (#{i + 1}/#{targets.count})".bold.magenta) do
30
- build_target(**options, target: t)
28
+ Dir.create_tmpdir do |tmpdir|
29
+ targets.each_with_index do |t, i|
30
+ target_tmpdir = Dir.prepare(tmpdir / t)
31
+ log_dir = Dir.prepare(options[:log_dir] || target_tmpdir)
32
+ live_log = LiveLog.new(tee: log_dir / "build_#{t}.log")
33
+ live_log.capture("[#{i + 1}/#{targets.count}] Building target: #{t}") do
34
+ build_target(**options, target: t, live_log: live_log, tmpdir: target_tmpdir)
35
+ end
31
36
  rescue StandardError => e
32
- UI.error("Failed to build target: #{t}. Error: #{e}")
37
+ UI.error("Error: #{e}\n" + "For details, check out: #{live_log.tee}".yellow.bold)
33
38
  raise e unless Config.instance.ignore_build_errors?
34
39
  end
35
40
  end
@@ -52,19 +57,19 @@ module XCCache
52
57
  basename = options[:checksum] ? "#{target.name}-#{target.checksum}" : target.name
53
58
  binary_path = out_dir / "#{basename}#{ext}"
54
59
 
55
- Dir.create_tmpdir do |tmpdir|
56
- cls = target.macro? ? Macro : XCFramework
57
- cls.new(
58
- name: target.name,
59
- pkg_dir: root_dir,
60
- config: config,
61
- sdks: sdks,
62
- path: binary_path,
63
- tmpdir: tmpdir,
64
- pkg_desc: target_pkg_desc,
65
- library_evolution: options[:library_evolution],
66
- ).build(**options)
67
- end
60
+ cls = target.macro? ? Macro : XCFramework
61
+ cls.new(
62
+ name: target.name,
63
+ pkg_dir: root_dir,
64
+ config: config,
65
+ sdks: sdks,
66
+ path: binary_path,
67
+ tmpdir: options[:tmpdir],
68
+ pkg_desc: target_pkg_desc,
69
+ ctx_desc: pkg_desc || target_pkg_desc,
70
+ library_evolution: options[:library_evolution],
71
+ live_log: options[:live_log],
72
+ ).build(**options)
68
73
  return if (symlinks_dir = options[:symlinks_dir]).nil?
69
74
  binary_path.symlink_to(symlinks_dir / target.name / "#{target.name}#{ext}")
70
75
  end
@@ -75,6 +80,10 @@ module XCCache
75
80
  @resolved = true
76
81
  end
77
82
 
83
+ def pkg_desc
84
+ descs_by_name[root_dir.basename.to_s]
85
+ end
86
+
78
87
  def pkg_desc_of_target(name, **options)
79
88
  resolve
80
89
  desc = descs.find { |d| d.has_target?(name) }
@@ -30,7 +30,7 @@ module XCCache
30
30
  end
31
31
 
32
32
  def invalidate_cache(sdks: [])
33
- UI.message("Invalidating cache (sdks: #{sdks.map(&:name)})")
33
+ UI.message("Invalidating cache (sdks: #{sdks.map(&:to_s).join(', ')})")
34
34
 
35
35
  config.spm_cache_dir.glob("*/*.{xcframework,macro}").each do |p|
36
36
  cmps = p.basename(".*").to_s.split("-")
@@ -45,7 +45,7 @@ module XCCache
45
45
 
46
46
  # For regular targets, the xcframework must satisfy the sdk constraints (ie. containing all the slices)
47
47
  metadata = XCFramework::Metadata.new(p / "Info.plist")
48
- expected_triples = sdks.map { |sdk| sdk.triple(without_vendor: true) }
48
+ expected_triples = sdks.map { |sdk| sdk.triple(with_vendor: false) }
49
49
  missing_triples = expected_triples - metadata.triples
50
50
  missing_triples.empty? ? accept_cache.call : reject_cache.call
51
51
  end
@@ -4,11 +4,12 @@ module XCCache
4
4
  class Proxy < Package
5
5
  class Executable
6
6
  REPO_URL = "https://github.com/trinhngocthuyen/xccache-proxy".freeze
7
- VERSION_OR_SHA = "1.0.0rc1".freeze
7
+ VERSION_OR_SHA = "1.0.0".freeze
8
8
 
9
9
  def run(cmd)
10
10
  env = { "FORCE_OUTPUT" => "console", "FORCE_COLOR" => "1" } if Config.instance.ansi?
11
11
  cmd = cmd.is_a?(Array) ? [bin_path.to_s] + cmd : [bin_path.to_s, cmd]
12
+ cmd << "--verbose" if Config.instance.verbose?
12
13
  Sh.run(cmd, env: env)
13
14
  end
14
15
 
@@ -4,10 +4,9 @@ module XCCache
4
4
  module SPM
5
5
  class FrameworkSlice < Buildable
6
6
  def build(_options = {})
7
- UI.section("Building slice: #{name} (#{config}, #{sdk})".bold) do
8
- swift_build
9
- create_framework
10
- end
7
+ live_log.puts("Building #{name}.framework (#{config}, #{sdk})".cyan, sticky: true)
8
+ swift_build
9
+ create_framework
11
10
  end
12
11
 
13
12
  private
@@ -21,7 +20,7 @@ module XCCache
21
20
  # WORKAROUND:
22
21
  # - Overriding resource_bundle_accessor.swift to add `Frameworks/<Target>.framework` to the search list
23
22
  # - Compiling this file into an `.o` file before using `libtool` to create the framework binary
24
- UI.message("Override resource_bundle_accessor")
23
+ live_log.info("Override resource_bundle_accessor")
25
24
  template_name = use_clang? ? "resource_bundle_accessor.m" : "resource_bundle_accessor.swift"
26
25
  source_path = tmpdir / File.basename(template_name)
27
26
  obj_path = products_dir / "#{module_name}.build" / "#{source_path.basename}.o"
@@ -33,18 +32,18 @@ module XCCache
33
32
  if use_clang?
34
33
  cmd = ["xcrun", "clang"]
35
34
  cmd << "-x" << "objective-c"
36
- cmd << "-target" << sdk.triple << "-isysroot" << sdk.sdk_path
35
+ cmd << "-target" << sdk.triple(with_version: true) << "-isysroot" << sdk.sdk_path
37
36
  cmd << "-o" << obj_path.to_s
38
37
  cmd << "-c" << source_path
39
38
  else
40
39
  cmd = ["xcrun", "swiftc"]
41
40
  cmd << "-emit-library" << "-emit-object"
42
41
  cmd << "-module-name" << module_name
43
- cmd << "-target" << sdk.triple << "-sdk" << sdk.sdk_path
42
+ cmd << "-target" << sdk.triple(with_version: true) << "-sdk" << sdk.sdk_path
44
43
  cmd << "-o" << obj_path.to_s
45
44
  cmd << source_path
46
45
  end
47
- Sh.run(cmd)
46
+ sh(cmd)
48
47
  end
49
48
 
50
49
  def create_framework
@@ -67,7 +66,7 @@ module XCCache
67
66
  cmd = ["libtool", "-static"]
68
67
  cmd << "-o" << "#{path}/#{module_name}"
69
68
  cmd << "-filelist" << objlist_path.to_s
70
- Sh.run(cmd)
69
+ sh(cmd)
71
70
  FileUtils.chmod("+x", path / module_name)
72
71
  end
73
72
 
@@ -85,7 +84,7 @@ module XCCache
85
84
  def create_modules
86
85
  copy_swiftmodules unless use_clang?
87
86
 
88
- UI.message("Creating framework modulemap")
87
+ live_log.info("Creating framework modulemap")
89
88
  Template.new("framework.modulemap").render(
90
89
  { :module_name => module_name, :target => name },
91
90
  save_to: modules_dir / "module.modulemap"
@@ -93,7 +92,7 @@ module XCCache
93
92
  end
94
93
 
95
94
  def copy_headers
96
- UI.message("Copying headers")
95
+ live_log.info("Copying headers")
97
96
  swift_header_paths = products_dir.glob("#{module_name}.build/*-Swift.h")
98
97
  paths = swift_header_paths + pkg_target.header_paths
99
98
  paths.each { |p| process_header(p) }
@@ -130,7 +129,7 @@ module XCCache
130
129
  end
131
130
 
132
131
  def copy_swiftmodules
133
- UI.message("Copying swiftmodules")
132
+ live_log.info("Copying swiftmodules")
134
133
  swiftmodule_dir = Dir.prepare("#{modules_dir}/#{module_name}.swiftmodule")
135
134
  swiftinterfaces = products_dir.glob("#{module_name}.build/#{module_name}.swiftinterface")
136
135
  to_copy = products_dir.glob("Modules/#{module_name}.*") + swiftinterfaces
@@ -141,7 +140,7 @@ module XCCache
141
140
 
142
141
  def copy_resource_bundles
143
142
  resolve_resource_symlinks
144
- UI.message("Copy resource bundle to framework: #{resource_bundle_product_path.basename}")
143
+ live_log.info("Copying resource bundle to framework: #{resource_bundle_product_path.basename}")
145
144
  resource_bundle_product_path.copy(to_dir: path)
146
145
  end
147
146
 
@@ -21,35 +21,32 @@ module XCCache
21
21
  tmp_existing_path = tmpdir / "existing.framework"
22
22
 
23
23
  slices.each(&:build)
24
- UI.section("Creating #{name}.xcframework from slices") do
25
- create_xcframework(from: slices.map(&:path), to: tmp_new_path)
26
- end
24
+ create_xcframework(from: slices.map(&:path), to: tmp_new_path)
27
25
 
28
26
  path.copy(to: tmp_existing_path) if path.exist? && merge_slices
29
27
  path.rmtree if path.exist?
30
28
 
31
29
  if merge_slices && tmp_existing_path.exist?
32
- UI.section("Merging #{name}.xcframework with existing slices") do
33
- framework_paths =
34
- [tmp_new_path, tmp_existing_path]
35
- .flat_map { |p| p.glob("*/*.framework") }
36
- .uniq { |p| p.parent.basename.to_s } # uniq by id (ex. ios-arm64), preferred new ones
37
- create_xcframework(from: framework_paths, to: path)
38
- end
30
+ framework_paths =
31
+ [tmp_new_path, tmp_existing_path]
32
+ .flat_map { |p| p.glob("*/*.framework") }
33
+ .uniq { |p| p.parent.basename.to_s } # uniq by id (ex. ios-arm64), preferred new ones
34
+ create_xcframework(from: framework_paths, to: path)
39
35
  else
40
36
  path.parent.mkpath
41
37
  tmp_new_path.copy(to: path)
42
38
  end
43
- UI.info("-> XCFramework: #{path.to_s.dark}")
39
+ live_log.info("-> XCFramework: #{path}")
44
40
  end
45
41
 
46
42
  def create_xcframework(options = {})
43
+ live_log.info("Creating xcframework from slices")
47
44
  cmd = ["xcodebuild", "-create-xcframework"]
48
45
  cmd << "-allow-internal-distribution" unless library_evolution?
49
46
  cmd << "-output" << options[:to]
50
47
  options[:from].each { |p| cmd << "-framework" << p }
51
48
  cmd << "> /dev/null" # Only care about errors
52
- Sh.run(cmd)
49
+ sh(cmd)
53
50
  end
54
51
  end
55
52
  end
@@ -3,38 +3,45 @@ require "xccache/core/sh"
3
3
  module XCCache
4
4
  module Swift
5
5
  class Sdk
6
- attr_reader :name
7
-
8
- NAME_TO_TRIPLE = {
9
- :iphonesimulator => "arm64-apple-ios-simulator",
10
- :iphoneos => "arm64-apple-ios",
11
- :macos => "arm64-apple-macos",
12
- :watchos => "arm64-apple-watchos",
13
- :watchsimulator => "arm64-apple-watchos-simulator",
14
- :appletvos => "arm64-apple-tvos",
15
- :appletvsimulator => "arm64-apple-tvos-simulator",
16
- :xros => "arm64-apple-xros",
17
- :xrsimulator => "arm64-apple-xros-simulator",
6
+ attr_reader :name, :arch, :vendor, :platform
7
+ attr_accessor :version
8
+
9
+ NAME_TO_PLATFORM = {
10
+ :iphonesimulator => :ios,
11
+ :iphoneos => :ios,
12
+ :macos => :macos,
13
+ :watchos => :watchos,
14
+ :watchsimulator => :watchos,
15
+ :appletvos => :tvos,
16
+ :appletvsimulator => :tvos,
17
+ :xros => :xros,
18
+ :xrsimulator => :xros,
18
19
  }.freeze
19
20
 
20
- def initialize(name)
21
- @name = name
22
- return if NAME_TO_TRIPLE.key?(name.to_sym)
23
- raise GeneralError, "Unknown sdk: #{name}. Must be one of #{NAME_TO_TRIPLE.keys}"
21
+ def initialize(name, version: nil)
22
+ @name = name.to_sym
23
+ @vendor = "apple"
24
+ @arch = "arm64"
25
+ @platform = NAME_TO_PLATFORM.fetch(@name, @name)
26
+ @version = version
27
+ return if NAME_TO_PLATFORM.key?(@name)
28
+ raise GeneralError, "Unknown sdk: #{@name}. Must be one of #{NAME_TO_PLATFORM.keys}"
24
29
  end
25
30
 
26
31
  def to_s
27
- name
32
+ name.to_s
28
33
  end
29
34
 
30
- def triple(without_vendor: false)
31
- res = NAME_TO_TRIPLE[name.to_sym]
32
- res = res.sub("-apple", "") if without_vendor
33
- res
35
+ def triple(with_vendor: true, with_version: false)
36
+ cmps = [arch]
37
+ cmps << vendor if with_vendor
38
+ cmps << (with_version && version ? "#{platform}#{version}" : platform.to_s)
39
+ cmps << "simulator" if simulator?
40
+ cmps.join("-")
34
41
  end
35
42
 
36
43
  def sdk_name
37
- name == "macos" ? "macosx" : name
44
+ name == :macos ? :macosx : name
38
45
  end
39
46
 
40
47
  def sdk_path
@@ -56,6 +63,10 @@ module XCCache
56
63
  "-I#{developer_usr_lib_path}",
57
64
  ]
58
65
  end
66
+
67
+ def simulator?
68
+ name.to_s.end_with?("simulator")
69
+ end
59
70
  end
60
71
  end
61
72
  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: 1.0.2
4
+ version: 1.0.4
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-06-08 00:00:00.000000000 Z
11
+ date: 2025-06-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: claide
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: tty-cursor
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: tty-screen
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: xcodeproj
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -91,6 +119,7 @@ files:
91
119
  - lib/xccache/core/error.rb
92
120
  - lib/xccache/core/git.rb
93
121
  - lib/xccache/core/hash.rb
122
+ - lib/xccache/core/live_log.rb
94
123
  - lib/xccache/core/lockfile.rb
95
124
  - lib/xccache/core/log.rb
96
125
  - lib/xccache/core/parallel.rb