xccache 0.0.1.rc14991851613 → 0.0.2

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: fd5e1c42ab55e9d384b998ec94ca4dfe10c1b71cddde74f1b5a45fe8df9e99c5
4
- data.tar.gz: a516b16ec060985d2bc705eb030b259b2858a96d110fa3ca1e046f89fb3c43f7
3
+ metadata.gz: 4201459bc9efce46e4eee06f18117749de0003131e383d3726ca082abbc6686f
4
+ data.tar.gz: c39f19dc60040641aaa518b192449ec86feee2b4e22c056de528904c04437a4a
5
5
  SHA512:
6
- metadata.gz: 4b1ff0db0ed02e89266e8cd99262a09c53dcac4a2854f48e35f27e56f5b341e5272b63f8afbcffd28241a112ea50c4116793577535a4e8643e693b234bcb7a64
7
- data.tar.gz: 9d57cf95ec5327a3688e0d437c67022fff096182fa9680a5418d75e5e3199bfb14063af67c2d3a4d0e4d8b4ac09f11faf976c5a713addc31b52500c6953336fe
6
+ metadata.gz: 114d1169b34312b251857b5bd93346d7e23ce266c1c05b6df9e9301d472e3995ee3fb8f200a086e3066e2688507a43ad43c3cf584b8505f8c7e2af91d7bc9710
7
+ data.tar.gz: 74bf01cc687ae222fc6a9cc4b2e75ac67faec16dd503f6ca4420d09824720a87f4afbe5ff26340b2abfa289fc72321d99026c2261a95e9cc22c17f34dc713f63
@@ -1,12 +1,12 @@
1
1
  class Hash
2
- def deep_merge(other, uniq_block: nil, &block)
3
- dup.deep_merge!(other, uniq_block: uniq_block, &block)
2
+ def deep_merge(other, uniq_block: nil, sort_block: nil, &block)
3
+ dup.deep_merge!(other, uniq_block: uniq_block, sort_block: sort_block, &block)
4
4
  end
5
5
 
6
- def deep_merge!(other, uniq_block: nil, &block)
6
+ def deep_merge!(other, uniq_block: nil, sort_block: nil, &block)
7
7
  merge!(other) do |key, this_val, other_val|
8
8
  result = if this_val.is_a?(Hash) && other_val.is_a?(Hash)
9
- this_val.deep_merge(other_val, uniq_block: uniq_block, &block)
9
+ this_val.deep_merge(other_val, uniq_block: uniq_block, sort_block: sort_block, &block)
10
10
  elsif this_val.is_a?(Array) && other_val.is_a?(Array)
11
11
  this_val + other_val
12
12
  elsif block_given?
@@ -14,8 +14,11 @@ class Hash
14
14
  else
15
15
  other_val
16
16
  end
17
- next result if uniq_block.nil? || !result.is_a?(Array)
18
- result.reverse.uniq(&uniq_block).reverse # prefer updates
17
+
18
+ # uniq by block, prefer updates
19
+ result = result.reverse.uniq(&uniq_block).reverse if uniq_block && result.is_a?(Array)
20
+ result = result.sort_by(&sort_block) if sort_block && result.is_a?(Array)
21
+ result
19
22
  end
20
23
  end
21
24
  end
@@ -2,6 +2,33 @@ require "xccache/core/syntax/json"
2
2
 
3
3
  module XCCache
4
4
  class Lockfile < JSONRepresentable
5
+ class Pkg < Hash
6
+ def self.from_h(h)
7
+ Pkg.new.merge(h)
8
+ end
9
+
10
+ def key
11
+ @key ||= ["repositoryURL", "path_from_root", "relative_path"].find { |x| key?(x) }
12
+ end
13
+
14
+ def id
15
+ self[key]
16
+ end
17
+
18
+ def local?
19
+ key != "repositoryURL"
20
+ end
21
+
22
+ def slug
23
+ @slug ||= File.basename(id, ".*")
24
+ end
25
+
26
+ def relative_path_from_dir(dir)
27
+ return id if key == "relative_path"
28
+ (Pathname.pwd / id).relative_path_from(dir) if key == "path_from_root"
29
+ end
30
+ end
31
+
5
32
  def hash_for_project(project)
6
33
  raw[project.display_name] ||= {}
7
34
  end
@@ -11,22 +38,31 @@ module XCCache
11
38
  end
12
39
 
13
40
  def deep_merge!(hash)
14
- keys = ["repositoryURL", "path_from_root", "relative_path"]
15
- raw.deep_merge!(hash, uniq_block: proc do |h|
16
- h.is_a?(Hash) && (k = keys.find { |k| h.key?(k) }) ? h[k] : h
17
- end)
41
+ raw.deep_merge!(
42
+ hash,
43
+ uniq_block: proc { |h| h.is_a?(Hash) ? Pkg.from_h(h).id || h : h },
44
+ sort_block: proc { |x| x.to_s.downcase },
45
+ )
46
+ # After deep_merge, clear property cache
47
+ (instance_variables - %i[@path @raw]).each do |ivar|
48
+ remove_instance_variable(ivar)
49
+ end
18
50
  end
19
51
 
20
52
  def pkgs
21
- @pkgs ||= raw.values.flat_map { |h| h["packages"] || [] }
53
+ @pkgs ||= raw.values.flat_map { |h| h["packages"] || [] }.map { |h| Pkg.from_h(h) }
22
54
  end
23
55
 
24
56
  def local_pkgs
25
- @local_pkgs ||= pkgs.select { |h| h.key?("relative_path") || h.key?("path") }
57
+ @local_pkgs ||= pkgs.select(&:local?).uniq
26
58
  end
27
59
 
28
60
  def local_pkg_slugs
29
- @local_pkg_slugs ||= local_pkgs.map { |h| File.basename(h["relative_path"] || h["path"]) }.uniq
61
+ @local_pkg_slugs ||= local_pkgs.map(&:slug).uniq
62
+ end
63
+
64
+ def known_product_dependencies
65
+ raw.empty? ? [] : product_dependencies.reject { |d| File.dirname(d) == "__unknown__" }
30
66
  end
31
67
 
32
68
  def product_dependencies
@@ -36,5 +72,20 @@ module XCCache
36
72
  def targets_data
37
73
  @targets_data ||= product_dependencies_by_targets.transform_keys { |k| "#{k}.xccache" }
38
74
  end
75
+
76
+ def verify!
77
+ known_slugs = pkgs.map(&:slug)
78
+ unknown = product_dependencies.reject { |d| known_slugs.include?(File.dirname(d)) }
79
+ return if unknown.empty?
80
+
81
+ UI.error! <<~DESC
82
+ Unknown product dependencies at #{path}:
83
+
84
+ #{unknown.sort.map { |d| " • #{d}" }.join("\n")}
85
+
86
+ Refer to this doc for how to resolve this issue:
87
+ https://github.com/trinhngocthuyen/xccache/blob/main/docs/troubleshooting.md#unknown-product-dependencies
88
+ DESC
89
+ end
39
90
  end
40
91
  end
@@ -43,6 +43,11 @@ module XCCache
43
43
  UI.puts("[ERROR] #{message}".red)
44
44
  end
45
45
 
46
+ def error!(message)
47
+ error(message)
48
+ raise GeneralError, message
49
+ end
50
+
46
51
  def puts(message)
47
52
  $stdout.puts("#{' ' * self.indent}#{message}")
48
53
  end
@@ -19,7 +19,7 @@ module XCCache
19
19
  project.add_xccache_pkg unless project.has_xccache_pkg?
20
20
  project.targets.each do |target|
21
21
  target.add_xccache_product_dependency unless target.has_xccache_product_dependency?
22
- target.remove_pkg_product_dependencies { |d| !d.pkg.xccache_pkg? }
22
+ target.remove_pkg_product_dependencies { |d| d.pkg.nil? || !d.pkg.xccache_pkg? }
23
23
  end
24
24
  project.remove_pkgs(&:non_xccache_pkg?) unless config.keep_pkgs_in_project?
25
25
  end
@@ -14,6 +14,7 @@ module XCCache
14
14
  end
15
15
 
16
16
  def perform_install
17
+ verify_projects!
17
18
  UI.message("Using cache dir: #{config.spm_cache_dir}")
18
19
  config.in_installation = true
19
20
  if @umbrella_pkg.nil?
@@ -33,10 +34,14 @@ module XCCache
33
34
 
34
35
  def sync_lockfile
35
36
  UI.info("Syncing lockfile")
37
+ known_dependencies = lockfile.known_product_dependencies
36
38
  update_projects do |project|
37
- lockfile.deep_merge!(project.display_name => lockfile_hash_for_project(project))
39
+ lockfile.deep_merge!(
40
+ project.display_name => lockfile_hash_for_project(project, known_dependencies)
41
+ )
38
42
  end
39
43
  lockfile.save
44
+ lockfile.verify!
40
45
  end
41
46
 
42
47
  def lockfile
@@ -53,7 +58,6 @@ module XCCache
53
58
  end
54
59
 
55
60
  def update_projects
56
- verify_projects!
57
61
  projects.each do |project|
58
62
  yield project if block_given?
59
63
  project.save
@@ -62,10 +66,15 @@ module XCCache
62
66
 
63
67
  private
64
68
 
65
- def lockfile_hash_for_project(project)
69
+ def lockfile_hash_for_project(project, known_dependencies)
66
70
  deps_by_targets = project.targets.to_h do |target|
67
- deps = target.non_xccache_pkg_product_dependencies.select(&:pkg).map { |d| "#{d.pkg.slug}/#{d.product_name}" }
68
- [target.name, deps]
71
+ deps = target.non_xccache_pkg_product_dependencies.map do |dep|
72
+ next dep.full_name unless dep.pkg.nil?
73
+ known = known_dependencies.find { |x| File.basename(x) == dep.product_name }
74
+ UI.warn("-> Assuming #{known} for #{dep.full_name}".dark) if known
75
+ known || dep.full_name
76
+ end
77
+ [target.name, deps.sort]
69
78
  end
70
79
  {
71
80
  "packages" => project.non_xccache_pkgs.map(&:to_h),
@@ -50,9 +50,7 @@ module Xcodeproj
50
50
 
51
51
  def to_h
52
52
  {
53
- "relative_path" => relative_path,
54
- "path" => path,
55
- "path_from_root" => absolute_path.relative_path_from(Pathname(".").expand_path).to_s,
53
+ "path_from_root" => absolute_path.relative_path_from(Pathname.pwd).to_s,
56
54
  }
57
55
  end
58
56
 
@@ -5,13 +5,26 @@ module Xcodeproj
5
5
  module Object
6
6
  class XCSwiftPackageProductDependency
7
7
  def full_name
8
- "#{pkg.slug}/#{product_name}"
8
+ @full_name ||= "#{pkg&.slug || '__unknown__'}/#{product_name}"
9
9
  end
10
10
 
11
11
  def pkg
12
- return package unless package.nil?
12
+ return package if package
13
+ return if @warned_missing_pkg
14
+ @warned_missing_pkg = true
15
+ XCCache::UI.warn("Missing pkg of product dependency #{uuid}: #{to_hash}")
16
+ end
13
17
 
14
- Log.warn("Missing pkg for #{inspect}")
18
+ def remove_alongside_related
19
+ target = referrers.find { |x| x.is_a?(PBXNativeTarget) }
20
+ XCCache::UI.info(
21
+ "(-) Remove #{product_name.red} from product dependencies of target #{target.display_name.bold}"
22
+ )
23
+ target.dependencies.each { |x| x.remove_from_project if x.product_ref == self }
24
+ target.build_phases.each do |phase|
25
+ phase.files.select { |f| f.remove_from_project if f.product_ref == self }
26
+ end
27
+ remove_from_project
15
28
  end
16
29
  end
17
30
  end
@@ -29,8 +29,8 @@ module Xcodeproj
29
29
  end
30
30
 
31
31
  def has_pkg?(hash)
32
- id = hash[pkg_key_in_hash(hash)]
33
- pkgs.any? { |p| p.id == id }
32
+ pkg_hash = XCCache::Lockfile::Pkg.from_h(hash)
33
+ pkgs.any? { |p| p.id == pkg_hash.id }
34
34
  end
35
35
 
36
36
  def has_xccache_pkg?
@@ -38,14 +38,14 @@ module Xcodeproj
38
38
  end
39
39
 
40
40
  def add_pkg(hash)
41
- key = pkg_key_in_hash(hash)
42
- is_local = ["relative_path", "path"].include?(key)
41
+ pkg_hash = XCCache::Lockfile::Pkg.from_h(hash)
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 #{hash[key].bold} to project #{display_name.bold}")
45
- cls = is_local ? XCLocalSwiftPackageReference : XCRemoteSwiftPackageReference
44
+ Log.message("Add package #{pkg_hash.id.bold} to project #{display_name.bold}")
45
+ cls = pkg_hash.local? ? XCLocalSwiftPackageReference : XCRemoteSwiftPackageReference
46
46
  ref = new(cls)
47
47
  custom_keys = ["path_from_root"]
48
- hash.each { |k, v| ref.send("#{k}=", v) unless custom_keys.include?(k) }
48
+ pkg_hash.each { |k, v| ref.send("#{k}=", v) unless custom_keys.include?(k) }
49
49
  root_object.package_references << ref
50
50
  ref
51
51
  end
@@ -73,11 +73,5 @@ module Xcodeproj
73
73
  def xccache_config_group
74
74
  self["xccache.config"] || new_group("xccache.config")
75
75
  end
76
-
77
- private
78
-
79
- def pkg_key_in_hash(hash)
80
- ["repositoryURL", "relative_path", "path"].find { |k| hash.key?(k) }
81
- end
82
76
  end
83
77
  end
@@ -30,21 +30,11 @@ module Xcodeproj
30
30
  end
31
31
 
32
32
  def remove_xccache_product_dependencies
33
- remove_pkg_product_dependencies { |d| d.pkg.xccache_pkg? }
33
+ remove_pkg_product_dependencies { |d| d.pkg&.xccache_pkg? }
34
34
  end
35
35
 
36
36
  def remove_pkg_product_dependencies(&block)
37
- package_product_dependencies.select(&block).each do |d|
38
- XCCache::UI.info(
39
- "(-) Remove #{d.product_name.red} from product dependencies of target #{display_name.bold}"
40
- )
41
- build_phases.each do |phase|
42
- phase.files.select { |f| f.remove_from_project if f.product_ref == d }
43
- end
44
- # Remove it from target dependencies
45
- dependencies.each { |x| x.remove_from_project if x.product_ref == d }
46
- d.remove_from_project
47
- end
37
+ package_product_dependencies.select(&block).each(&:remove_alongside_related)
48
38
  end
49
39
  end
50
40
  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.1.rc14991851613
4
+ version: 0.0.2
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-13 00:00:00.000000000 Z
11
+ date: 2025-05-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: claide
@@ -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: 1.3.1
166
+ version: '0'
167
167
  requirements: []
168
168
  rubygems_version: 3.2.33
169
169
  signing_key: