xccache 0.0.2 → 1.0.0
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/git.rb +1 -1
- data/lib/xccache/core/lockfile.rb +4 -0
- data/lib/xccache/core/sh.rb +3 -17
- data/lib/xccache/core/syntax/hash.rb +4 -0
- data/lib/xccache/core/system.rb +3 -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.rb +33 -9
- 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 +77 -0
- data/lib/xccache/utils/template.rb +1 -1
- data/lib/xccache/xcodeproj/pkg.rb +1 -1
- data/lib/xccache/xcodeproj/pkg_product_dependency.rb +2 -2
- data/lib/xccache/xcodeproj/project.rb +3 -3
- data/lib/xccache/xcodeproj/target.rb +2 -2
- data/lib/xccache.rb +5 -0
- metadata +10 -10
- 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
@@ -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
|