xccache 0.0.1a1 → 0.0.1a3
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/assets/templates/cachemap.html.template +55 -0
- data/lib/xccache/assets/templates/cachemap.js.template +95 -0
- data/lib/xccache/assets/templates/cachemap.style.css.template +94 -0
- data/lib/xccache/assets/templates/framework.info.plist.template +25 -0
- data/lib/xccache/assets/templates/framework.modulemap.template +6 -0
- data/lib/xccache/assets/templates/resource_bundle_accessor.m.template +27 -0
- data/lib/xccache/assets/templates/resource_bundle_accessor.swift.template +24 -0
- data/lib/xccache/assets/templates/umbrella.Package.swift.template +183 -0
- data/lib/xccache/cache/cachemap.rb +56 -0
- data/lib/xccache/command/base.rb +29 -0
- data/lib/xccache/command/build.rb +41 -0
- data/lib/xccache/command/pkg/build.rb +30 -0
- data/lib/xccache/command/pkg.rb +1 -0
- data/lib/xccache/command/remote/pull.rb +15 -0
- data/lib/xccache/command/remote/push.rb +15 -0
- data/lib/xccache/command/remote.rb +39 -0
- data/lib/xccache/command/rollback.rb +14 -0
- data/lib/xccache/command/use.rb +19 -0
- data/lib/xccache/command.rb +27 -1
- data/lib/xccache/core/cacheable.rb +28 -0
- data/lib/xccache/core/config.rb +110 -0
- data/lib/xccache/core/error.rb +7 -0
- data/lib/xccache/core/git.rb +27 -0
- data/lib/xccache/core/hash.rb +21 -0
- data/lib/xccache/core/lockfile.rb +40 -0
- data/lib/xccache/core/log.rb +51 -0
- data/lib/xccache/core/parallel.rb +10 -0
- data/lib/xccache/core/sh.rb +51 -0
- data/lib/xccache/core/syntax/hash.rb +31 -0
- data/lib/xccache/core/syntax/json.rb +16 -0
- data/lib/xccache/core/syntax/plist.rb +17 -0
- data/lib/xccache/core/syntax/yml.rb +16 -0
- data/lib/xccache/core/syntax.rb +1 -0
- data/lib/xccache/core/system.rb +62 -0
- data/lib/xccache/core.rb +1 -0
- data/lib/xccache/installer/build.rb +23 -0
- data/lib/xccache/installer/rollback.rb +37 -0
- data/lib/xccache/installer/use.rb +28 -0
- data/lib/xccache/installer.rb +113 -0
- data/lib/xccache/main.rb +3 -1
- data/lib/xccache/spm/build.rb +53 -0
- data/lib/xccache/spm/desc/base.rb +68 -0
- data/lib/xccache/spm/desc/dep.rb +40 -0
- data/lib/xccache/spm/desc/desc.rb +126 -0
- data/lib/xccache/spm/desc/product.rb +36 -0
- data/lib/xccache/spm/desc/target/binary.rb +8 -0
- data/lib/xccache/spm/desc/target/macro.rb +8 -0
- data/lib/xccache/spm/desc/target.rb +164 -0
- data/lib/xccache/spm/desc.rb +1 -0
- data/lib/xccache/spm/macro.rb +44 -0
- data/lib/xccache/spm/mixin.rb +12 -0
- data/lib/xccache/spm/pkg/base.rb +107 -0
- data/lib/xccache/spm/pkg/umbrella/build.rb +30 -0
- data/lib/xccache/spm/pkg/umbrella/cachemap.rb +110 -0
- data/lib/xccache/spm/pkg/umbrella/descs.rb +35 -0
- data/lib/xccache/spm/pkg/umbrella/manifest.rb +83 -0
- data/lib/xccache/spm/pkg/umbrella/viz.rb +40 -0
- data/lib/xccache/spm/pkg/umbrella/xcconfigs.rb +31 -0
- data/lib/xccache/spm/pkg/umbrella.rb +91 -0
- data/lib/xccache/spm/pkg.rb +1 -0
- data/lib/xccache/spm/xcframework/metadata.rb +41 -0
- data/lib/xccache/spm/xcframework/slice.rb +180 -0
- data/lib/xccache/spm/xcframework/xcframework.rb +56 -0
- data/lib/xccache/spm/xcframework.rb +2 -0
- data/lib/xccache/spm.rb +1 -0
- data/lib/xccache/storage/base.rb +26 -0
- data/lib/xccache/storage/git.rb +46 -0
- data/lib/xccache/storage/s3.rb +53 -0
- data/lib/xccache/storage.rb +1 -0
- data/lib/xccache/swift/sdk.rb +49 -0
- data/lib/xccache/swift/swiftc.rb +16 -0
- data/lib/xccache/utils/template.rb +21 -0
- data/lib/xccache/xcodeproj/build_configuration.rb +20 -0
- data/lib/xccache/xcodeproj/config.rb +9 -0
- data/lib/xccache/xcodeproj/file_system_synchronized_root_group.rb +17 -0
- data/lib/xccache/xcodeproj/group.rb +26 -0
- data/lib/xccache/xcodeproj/pkg.rb +73 -0
- data/lib/xccache/xcodeproj/pkg_product_dependency.rb +19 -0
- data/lib/xccache/xcodeproj/project.rb +83 -0
- data/lib/xccache/xcodeproj/target.rb +52 -0
- data/lib/xccache/xcodeproj.rb +2 -0
- metadata +107 -2
@@ -0,0 +1,62 @@
|
|
1
|
+
require "digest"
|
2
|
+
require "mkmf"
|
3
|
+
|
4
|
+
class String
|
5
|
+
def c99extidentifier
|
6
|
+
gsub(/[^a-zA-Z0-9.]/, "_")
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
class File
|
11
|
+
def self.which(bin)
|
12
|
+
find_executable0(bin)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
class Dir
|
17
|
+
def self.prepare(dir)
|
18
|
+
dir = Pathname(dir)
|
19
|
+
dir.mkpath
|
20
|
+
dir
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.create_tmpdir
|
24
|
+
dir = Pathname(Dir.mktmpdir("xccache"))
|
25
|
+
res = block_given? ? (yield dir) : dir
|
26
|
+
dir.rmtree if block_given?
|
27
|
+
res
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.git?(dir)
|
31
|
+
XCCache::Sh.capture_output("git -C #{dir} rev-parse --git-dir") == ".git"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class Pathname
|
36
|
+
def symlink_to(dst)
|
37
|
+
dst = Pathname(dst)
|
38
|
+
dst.rmtree if dst.symlink?
|
39
|
+
dst.parent.mkpath
|
40
|
+
File.symlink(expand_path, dst)
|
41
|
+
end
|
42
|
+
|
43
|
+
def copy(to: nil, to_dir: nil)
|
44
|
+
dst = to || (Pathname(to_dir) / basename)
|
45
|
+
dst.rmtree if dst.exist? || dst.symlink?
|
46
|
+
dst.parent.mkpath
|
47
|
+
FileUtils.copy_entry(self, dst)
|
48
|
+
dst
|
49
|
+
end
|
50
|
+
|
51
|
+
def checksum
|
52
|
+
hasher = Digest::SHA256.new
|
53
|
+
glob("**/*").reject { |p| p.directory? || p.symlink? }.sort.each do |p|
|
54
|
+
p.open("rb") do |f|
|
55
|
+
while (chunk = f.read(65_536)) # Read 64KB chunks
|
56
|
+
hasher.update(chunk)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
hasher.hexdigest[...8]
|
61
|
+
end
|
62
|
+
end
|
data/lib/xccache/core.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Dir["#{__dir__}/#{File.basename(__FILE__, '.rb')}/*.rb"].sort.each { |f| require f }
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require "xccache/spm"
|
2
|
+
|
3
|
+
module XCCache
|
4
|
+
class Installer
|
5
|
+
class Build < Installer
|
6
|
+
def initialize(options = {})
|
7
|
+
super
|
8
|
+
@targets = options[:targets]
|
9
|
+
end
|
10
|
+
|
11
|
+
def install!
|
12
|
+
perform_install do
|
13
|
+
umbrella_pkg.build(
|
14
|
+
targets: @targets,
|
15
|
+
out_dir: config.spm_repo_dir,
|
16
|
+
checksum: true,
|
17
|
+
**@build_options,
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module XCCache
|
2
|
+
class Installer
|
3
|
+
class Rollback < Installer
|
4
|
+
def install!
|
5
|
+
update_projects do |project|
|
6
|
+
UI.section("Rolling back cache for project #{project.display_name}".bold.green) do
|
7
|
+
rollback_for_project(project)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def rollback_for_project(project)
|
15
|
+
hash = lockfile.hash_for_project(project)
|
16
|
+
pkgs, deps_by_targets = hash["packages"], hash["dependencies"]
|
17
|
+
|
18
|
+
# Add packages back to the project
|
19
|
+
pkgs.reject { |h| project.has_pkg?(h) }.each do |h|
|
20
|
+
project.add_pkg(h)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Add products back to `Link Binary with Libraries` of targets
|
24
|
+
deps_by_targets.each do |name, deps|
|
25
|
+
target = project.get_target(name)
|
26
|
+
deps.reject { |d| target.has_pkg_product_dependency?(d) }.each do |d|
|
27
|
+
target.add_pkg_product_dependency(d)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Remove .binary product from the project
|
32
|
+
project.targets.each(&:remove_xccache_product_dependencies)
|
33
|
+
project.xccache_pkg&.remove_from_project
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "xccache/spm"
|
2
|
+
|
3
|
+
module XCCache
|
4
|
+
class Installer
|
5
|
+
class Use < Installer
|
6
|
+
def install!
|
7
|
+
update_projects do |project|
|
8
|
+
perform_install do
|
9
|
+
UI.section("Using cache for project #{project.display_name}".bold.green) do
|
10
|
+
replace_binaries_for_project(project)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def replace_binaries_for_project(project)
|
19
|
+
project.add_xccache_pkg unless project.has_xccache_pkg?
|
20
|
+
project.targets.each do |target|
|
21
|
+
target.add_xccache_product_dependency unless target.has_xccache_product_dependency?
|
22
|
+
target.remove_pkg_product_dependencies { |d| !d.pkg.xccache_pkg? }
|
23
|
+
end
|
24
|
+
project.remove_pkgs(&:non_xccache_pkg?) unless config.keep_pkgs_in_project?
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require "xccache/spm"
|
2
|
+
Dir["#{__dir__}/#{File.basename(__FILE__, '.rb')}/*.rb"].sort.each { |f| require f }
|
3
|
+
|
4
|
+
module XCCache
|
5
|
+
class Installer
|
6
|
+
include PkgMixin
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
ctx = options[:ctx]
|
10
|
+
raise GeneralError, "Missing context (Command) for #{self.class}" if ctx.nil?
|
11
|
+
@umbrella_pkg = options[:umbrella_pkg]
|
12
|
+
@install_options = ctx.install_options
|
13
|
+
@build_options = ctx.build_options
|
14
|
+
end
|
15
|
+
|
16
|
+
def perform_install
|
17
|
+
config.in_installation = true
|
18
|
+
verify_projects!
|
19
|
+
if @umbrella_pkg.nil?
|
20
|
+
sync_lockfile
|
21
|
+
umbrella_pkg.prepare(**@install_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
yield
|
25
|
+
umbrella_pkg.write_manifest
|
26
|
+
umbrella_pkg.gen_xcconfigs
|
27
|
+
projects.each do |project|
|
28
|
+
add_xccache_refs_to_project(project)
|
29
|
+
inject_xcconfig_to_project(project)
|
30
|
+
end
|
31
|
+
umbrella_pkg.gen_cachemap_viz
|
32
|
+
end
|
33
|
+
|
34
|
+
def sync_lockfile
|
35
|
+
UI.info("Syncing lockfile")
|
36
|
+
update_projects do |project|
|
37
|
+
lockfile.deep_merge!(project.display_name => lockfile_hash_for_project(project))
|
38
|
+
end
|
39
|
+
lockfile.save
|
40
|
+
end
|
41
|
+
|
42
|
+
def lockfile
|
43
|
+
config.lockfile
|
44
|
+
end
|
45
|
+
|
46
|
+
def projects
|
47
|
+
config.projects
|
48
|
+
end
|
49
|
+
|
50
|
+
def save_projects
|
51
|
+
yield if block_given?
|
52
|
+
projects.each(&:save)
|
53
|
+
end
|
54
|
+
|
55
|
+
def update_projects
|
56
|
+
projects.each do |project|
|
57
|
+
yield project if block_given?
|
58
|
+
project.save
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def lockfile_hash_for_project(project)
|
65
|
+
deps_by_targets = project.targets.to_h do |target|
|
66
|
+
deps = target.non_xccache_pkg_product_dependencies.select(&:pkg).map { |d| "#{d.pkg.slug}/#{d.product_name}" }
|
67
|
+
[target.name, deps]
|
68
|
+
end
|
69
|
+
{
|
70
|
+
"packages" => project.non_xccache_pkgs.map(&:to_h),
|
71
|
+
"dependencies" => deps_by_targets,
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
def verify_projects!
|
76
|
+
raise "No projects detected. Are you running on the correct project directory?" if projects.empty?
|
77
|
+
end
|
78
|
+
|
79
|
+
def add_xccache_refs_to_project(project)
|
80
|
+
group = project.xccache_config_group
|
81
|
+
add_file = proc { |p| group[p.basename.to_s] || group.new_file(p) }
|
82
|
+
add_file.call(config.spm_umbrella_sandbox / "Package.swift")
|
83
|
+
add_file.call(config.lockfile.path)
|
84
|
+
add_file.call(config.path) if config.path.exist?
|
85
|
+
group.ensure_synced_group(name: "local-packages", path: config.spm_local_pkgs_dir)
|
86
|
+
end
|
87
|
+
|
88
|
+
def inject_xcconfig_to_project(project)
|
89
|
+
group = project.xccache_config_group.ensure_synced_group(name: "xcconfigs", path: config.spm_xcconfig_dir)
|
90
|
+
project.targets.each do |target|
|
91
|
+
xcconfig_path = config.spm_xcconfig_dir / "#{target.name}.xcconfig"
|
92
|
+
target.build_configurations.each do |build_config|
|
93
|
+
if (existing = build_config.base_configuration_xcconfig)
|
94
|
+
next if existing.path == xcconfig_path
|
95
|
+
|
96
|
+
relative_path = xcconfig_path.relative_path_from(existing.path.parent)
|
97
|
+
next if existing.includes.include?(relative_path.to_s)
|
98
|
+
|
99
|
+
UI.info("Injecting base configuration for #{target} (#{build_config}) (at: #{existing.path})")
|
100
|
+
existing.path.write <<~DESC
|
101
|
+
#include "#{relative_path}" // Injected by xccache, for prebuilt macros support
|
102
|
+
#{existing.path.read.strip}
|
103
|
+
DESC
|
104
|
+
else
|
105
|
+
UI.info("Setting base configuration #{target} (#{build_config}) as #{xcconfig_path}")
|
106
|
+
build_config.base_configuration_reference_anchor = group
|
107
|
+
build_config.base_configuration_reference_relative_path = xcconfig_path.basename.to_s
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/xccache/main.rb
CHANGED
@@ -0,0 +1,53 @@
|
|
1
|
+
module XCCache
|
2
|
+
module SPM
|
3
|
+
class Buildable
|
4
|
+
attr_reader :name, :module_name, :pkg_dir, :pkg_desc, :sdk, :sdks, :config, :path, :tmpdir, :library_evolution
|
5
|
+
alias library_evolution? library_evolution
|
6
|
+
|
7
|
+
def initialize(options = {})
|
8
|
+
@name = options[:name]
|
9
|
+
@module_name = @name.c99extidentifier
|
10
|
+
@pkg_dir = Pathname(options[:pkg_dir] || ".").expand_path
|
11
|
+
@pkg_desc = options[:pkg_desc]
|
12
|
+
@sdks = options[:sdks] || []
|
13
|
+
@sdk = options[:sdk] || @sdks&.first
|
14
|
+
@config = options[:config] || "debug"
|
15
|
+
@path = options[:path]
|
16
|
+
@tmpdir = options[:tmpdir]
|
17
|
+
@library_evolution = options[:library_evolution]
|
18
|
+
end
|
19
|
+
|
20
|
+
def build(options = {})
|
21
|
+
raise NotImplementedError
|
22
|
+
end
|
23
|
+
|
24
|
+
def swift_build(target: nil)
|
25
|
+
cmd = ["swift", "build"] + swift_build_args
|
26
|
+
cmd << "--package-path" << pkg_dir
|
27
|
+
cmd << "--target" << (target || name)
|
28
|
+
cmd << "--sdk" << sdk.sdk_path
|
29
|
+
sdk.swiftc_args.each { |arg| cmd << "-Xswiftc" << arg }
|
30
|
+
if library_evolution?
|
31
|
+
# Workaround for swiftinterface emission
|
32
|
+
# https://github.com/swiftlang/swift/issues/64669#issuecomment-1535335601
|
33
|
+
cmd << "-Xswiftc" << "-enable-library-evolution"
|
34
|
+
cmd << "-Xswiftc" << "-alias-module-names-in-module-interface"
|
35
|
+
cmd << "-Xswiftc" << "-emit-module-interface"
|
36
|
+
cmd << "-Xswiftc" << "-no-verify-emitted-module-interface"
|
37
|
+
end
|
38
|
+
Sh.run(cmd, suppress_err: /(dependency '.*' is not used by any target|unable to create symbolic link)/)
|
39
|
+
end
|
40
|
+
|
41
|
+
def swift_build_args
|
42
|
+
[
|
43
|
+
"--configuration", config,
|
44
|
+
"--triple", sdk.triple,
|
45
|
+
]
|
46
|
+
end
|
47
|
+
|
48
|
+
def pkg_target
|
49
|
+
@pkg_target ||= pkg_desc.get_target(name)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "xccache/core"
|
2
|
+
|
3
|
+
module XCCache
|
4
|
+
module SPM
|
5
|
+
class Package
|
6
|
+
class BaseObject < JSONRepresentable
|
7
|
+
include Config::Mixin
|
8
|
+
|
9
|
+
ATTRS = %i[root retrieve_pkg_desc].freeze
|
10
|
+
attr_accessor(*ATTRS)
|
11
|
+
|
12
|
+
def name
|
13
|
+
raw["name"]
|
14
|
+
end
|
15
|
+
|
16
|
+
def full_name
|
17
|
+
is_a?(Description) ? name : "#{pkg_slug}/#{name}"
|
18
|
+
end
|
19
|
+
|
20
|
+
def inspect
|
21
|
+
to_s
|
22
|
+
end
|
23
|
+
|
24
|
+
def display_name
|
25
|
+
name
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
"<#{self.class} name=#{display_name}>"
|
30
|
+
end
|
31
|
+
|
32
|
+
def cast_to(cls)
|
33
|
+
o = cls.new(path, raw: raw)
|
34
|
+
ATTRS.each { |sym| o.send("#{sym}=", send(sym.to_s)) }
|
35
|
+
o
|
36
|
+
end
|
37
|
+
|
38
|
+
def pkg_name
|
39
|
+
@pkg_name ||= root.name
|
40
|
+
end
|
41
|
+
|
42
|
+
def pkg_slug
|
43
|
+
@pkg_slug ||= src_dir.basename.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def fetch(key, dtype)
|
47
|
+
raw[key].map do |h|
|
48
|
+
o = dtype.new(nil, raw: h)
|
49
|
+
o.root = root
|
50
|
+
o.retrieve_pkg_desc = retrieve_pkg_desc
|
51
|
+
o
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def pkg_desc_of(name)
|
56
|
+
retrieve_pkg_desc.call(name)
|
57
|
+
end
|
58
|
+
|
59
|
+
def src_dir
|
60
|
+
@src_dir ||= begin
|
61
|
+
path = root.raw.fetch("packageKind", {}).fetch("root", [])[0]
|
62
|
+
Pathname.new(path) unless path.nil?
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require "xccache/spm/desc/base"
|
2
|
+
|
3
|
+
module XCCache
|
4
|
+
module SPM
|
5
|
+
class Package
|
6
|
+
class Dependency < BaseObject
|
7
|
+
def display_name
|
8
|
+
slug
|
9
|
+
end
|
10
|
+
|
11
|
+
def local?
|
12
|
+
raw.key?("fileSystem")
|
13
|
+
end
|
14
|
+
|
15
|
+
def hash
|
16
|
+
@hash ||= local? ? raw["fileSystem"].first : raw["sourceControl"].first
|
17
|
+
end
|
18
|
+
|
19
|
+
def slug
|
20
|
+
@slug ||=
|
21
|
+
if hash.key?("path")
|
22
|
+
File.basename(hash["path"])
|
23
|
+
elsif (location = hash["location"]) && location.key?("remote")
|
24
|
+
File.basename(location["remote"].flat_map(&:values)[0], ".*")
|
25
|
+
else
|
26
|
+
hash["identity"]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def path
|
31
|
+
@path ||= Pathname(hash["path"]).expand_path if local?
|
32
|
+
end
|
33
|
+
|
34
|
+
def pkg_desc
|
35
|
+
@pkg_desc ||= pkg_desc_of(slug)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require "xccache/spm/desc/base"
|
2
|
+
|
3
|
+
module XCCache
|
4
|
+
module SPM
|
5
|
+
class Package
|
6
|
+
class Description < BaseObject
|
7
|
+
include Cacheable
|
8
|
+
cacheable :resolve_recursive_dependencies
|
9
|
+
|
10
|
+
def self.descs_in_metadata_dir
|
11
|
+
descs = Config.instance.spm_metadata_dir.glob("*.json").map { |p| Description.new(p) }
|
12
|
+
[descs, combine_descs(descs)]
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.in_dir(dir, save_to_dir: nil)
|
16
|
+
path = save_to_dir / "#{dir.basename}.json" unless save_to_dir.nil?
|
17
|
+
begin
|
18
|
+
raw = JSON.parse(Sh.capture_output("swift package dump-package --package-path #{dir}"))
|
19
|
+
Description.new(path, raw: raw)
|
20
|
+
rescue StandardError => e
|
21
|
+
UI.error("Failed to dump package in #{dir}. Error: #{e}")
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.descs_in_dir(root_dir, save_to_dir: nil)
|
26
|
+
dirs = [root_dir] + root_dir.glob(".build/checkouts/*").reject { |p| p.glob("Package*.swift").empty? }
|
27
|
+
descs = dirs.parallel_map do |dir|
|
28
|
+
desc = Description.in_dir(dir, save_to_dir: save_to_dir)
|
29
|
+
unless save_to_dir.nil?
|
30
|
+
desc.save
|
31
|
+
desc.save(to: desc.path.parent / "#{desc.name}.json") if desc.name != dir.basename.to_s
|
32
|
+
end
|
33
|
+
desc
|
34
|
+
end
|
35
|
+
[descs, combine_descs(descs)]
|
36
|
+
end
|
37
|
+
|
38
|
+
def root
|
39
|
+
self
|
40
|
+
end
|
41
|
+
|
42
|
+
def metadata
|
43
|
+
raw["_metadata"] ||= {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def dependencies
|
47
|
+
@dependencies ||= fetch("dependencies", Dependency)
|
48
|
+
end
|
49
|
+
|
50
|
+
def uniform_dependencies
|
51
|
+
dependencies.filter_map(&:pkg_desc)
|
52
|
+
end
|
53
|
+
|
54
|
+
def products
|
55
|
+
@products ||= fetch("products", Product)
|
56
|
+
end
|
57
|
+
|
58
|
+
def targets
|
59
|
+
@targets ||= fetch("targets", Target).map(&:downcast)
|
60
|
+
end
|
61
|
+
|
62
|
+
def binary_targets
|
63
|
+
@binary_targets ||= targets.select(&:binary?)
|
64
|
+
end
|
65
|
+
|
66
|
+
def has_target?(name)
|
67
|
+
targets.any? { |t| t.name == name }
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_target(name)
|
71
|
+
targets.find { |t| t.name == name }
|
72
|
+
end
|
73
|
+
|
74
|
+
def targets_of_products(name)
|
75
|
+
matched_products = products.select { |p| p.name == name }
|
76
|
+
matched_products
|
77
|
+
.flat_map { |p| targets.select { |t| p.target_names.include?(t.name) } }
|
78
|
+
end
|
79
|
+
|
80
|
+
def resolve_recursive_dependencies(platform: nil)
|
81
|
+
products.to_h { |p| [p, p.recursive_targets(platform: platform)] }
|
82
|
+
end
|
83
|
+
|
84
|
+
def local?
|
85
|
+
# Workaround: If the pkg dir is under the build checkouts dir -> remote
|
86
|
+
!src_dir.to_s.start_with?((config.spm_build_dir / "checkouts").to_s)
|
87
|
+
end
|
88
|
+
|
89
|
+
def traverse
|
90
|
+
nodes, edges, parents = [], [], {}
|
91
|
+
to_visit = targets.dup
|
92
|
+
visited = Set.new
|
93
|
+
until to_visit.empty?
|
94
|
+
cur = to_visit.pop
|
95
|
+
next if visited.include?(cur)
|
96
|
+
|
97
|
+
visited << cur
|
98
|
+
nodes << cur
|
99
|
+
yield cur if block_given?
|
100
|
+
|
101
|
+
# For macro impl, we don't need their dependencies, just the tool binary
|
102
|
+
# So, no need to care about swift-syntax dependencies
|
103
|
+
next if cur.macro?
|
104
|
+
cur.direct_dependency_targets.each do |t|
|
105
|
+
to_visit << t
|
106
|
+
edges << [cur, t]
|
107
|
+
parents[t] ||= []
|
108
|
+
parents[t] << cur
|
109
|
+
end
|
110
|
+
end
|
111
|
+
[nodes, edges, parents]
|
112
|
+
end
|
113
|
+
|
114
|
+
def git
|
115
|
+
@git ||= Git.new(src_dir) if Dir.git?(src_dir)
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.combine_descs(descs)
|
119
|
+
descs_by_name = descs.flat_map { |d| [[d.name, d], [d.pkg_slug, d]] }.to_h
|
120
|
+
descs.each { |d| d.retrieve_pkg_desc = proc { |name| descs_by_name[name] } }
|
121
|
+
descs_by_name
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require "xccache/spm/desc/base"
|
2
|
+
|
3
|
+
module XCCache
|
4
|
+
module SPM
|
5
|
+
class Package
|
6
|
+
class Product < BaseObject
|
7
|
+
include Cacheable
|
8
|
+
cacheable :recursive_targets
|
9
|
+
|
10
|
+
def target_names
|
11
|
+
raw["targets"]
|
12
|
+
end
|
13
|
+
|
14
|
+
def flatten_as_targets
|
15
|
+
targets
|
16
|
+
end
|
17
|
+
|
18
|
+
def targets
|
19
|
+
@targets ||= root.targets.select { |t| target_names.include?(t.name) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def library?
|
23
|
+
type == :library
|
24
|
+
end
|
25
|
+
|
26
|
+
def type
|
27
|
+
@type ||= raw["type"].keys.first.to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
def recursive_targets(platform: nil)
|
31
|
+
targets + targets.flat_map { |t| t.recursive_targets(platform: platform) }.uniq
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|