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
@@ -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