cocoapods-spm 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b31c9b35087187bc68aa7537abeb5fec4fb45e496c767382b8b8300ebadebf30
4
- data.tar.gz: fa9dcb1a770f7aeb42db04739bc81ae9ff52c9e0fffe0368e7769f36e1b99977
3
+ metadata.gz: 4b9b83e3ac7c7282f49cce528a02e34e2fed09ca2223678d1163e19cc207622d
4
+ data.tar.gz: 5f53852020f6c43d8f30b779b5d368c5e12947879dce8bd36ebc957432b0a526
5
5
  SHA512:
6
- metadata.gz: e644e4b8ba131f6eac0694ee25548e85f0782fadc794d68c944a18c969671f175aa14baaa0928b31cbbdbea0a8b3e14cd8ca01fb78022d8b4db1a66f676758e7
7
- data.tar.gz: ea77387bf7c1e8ecb35fc00693450d0456b3535490561c4012397ab347127381719038d3ce6de88b529ba3966645d40d9d42adc8e5481763006f731f0c4e82d2
6
+ metadata.gz: e4ded83745f975f6c72c5e1661f819f402b29a86265afdb7769b3109e9ea457bd4305fcb022af68240b1181860027ca16f5c659616b5ce550f0277b338ff00f7
7
+ data.tar.gz: ace85ea8679705143e58c81f0c0f4d1831a2848939f083031baff3469fb41a982172c41a7caca23a3368f3afb1ef11302ced2445497afceb35c0e35c8fcf8d12
@@ -0,0 +1,11 @@
1
+ module Pod
2
+ module SPM
3
+ class Config
4
+ module PodConfigMixin
5
+ def pod_config
6
+ Pod::Config.instance
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,32 @@
1
+ module Pod
2
+ module SPM
3
+ class Config
4
+ module ProjectConfigMixin
5
+ def project_config
6
+ ProjectConfig.instance
7
+ end
8
+ end
9
+
10
+ class ProjectConfig
11
+ def self.instance
12
+ @instance ||= ProjectConfig.new
13
+ end
14
+
15
+ def workspace
16
+ @workspace ||= Pod::Config.instance.podfile.defined_in_file.parent.glob("*.xcworkspace").first
17
+ end
18
+
19
+ def scheme
20
+ workspace.parent.glob("*.xcodeproj/**/*.xcscheme").first.basename(".xcscheme")
21
+ end
22
+
23
+ def default_derived_data_path
24
+ @default_derived_data_path ||= begin
25
+ raw = `xcodebuild -showBuildSettings -workspace #{workspace.shellescape} -scheme #{scheme.shellescape}`
26
+ Pathname(raw[/BUILD_DIR = (.*)/, 1]).parent.parent
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,92 @@
1
+ module Pod
2
+ module SPM
3
+ class Config
4
+ module SPMConfigMixin
5
+ def spm_config
6
+ Config.instance
7
+ end
8
+
9
+ def macro_pods
10
+ pod_config.podfile.macro_pods
11
+ end
12
+ end
13
+
14
+ attr_accessor :dsl_config, :cli_config
15
+
16
+ def initialize
17
+ @dsl_config = {
18
+ :dont_prebuild_macros => false,
19
+ :dont_prebuild_macros_if_exist => true
20
+ }
21
+ @cli_config = {}
22
+ end
23
+
24
+ def self.instance
25
+ @instance ||= Config.new
26
+ end
27
+
28
+ def merged_config
29
+ @dsl_config.merge(@cli_config)
30
+ end
31
+
32
+ def dont_prebuild_macros?
33
+ merged_config[:dont_prebuild_macros]
34
+ end
35
+
36
+ def dont_prebuild_macros_if_exist?
37
+ merged_config[:dont_prebuild_macros_if_exist]
38
+ end
39
+
40
+ def macro_config
41
+ merged_config[:config] || merged_config[:default_macro_config] || "debug"
42
+ end
43
+
44
+ def all_macros
45
+ @all_macros ||= Pod::Config.instance.podfile.macro_pods.keys
46
+ end
47
+
48
+ def macros
49
+ merged_config[:all] ? all_macros : (merged_config[:macros] || [])
50
+ end
51
+
52
+ def root_dir
53
+ @root_dir ||= Pathname(".spm.pods")
54
+ end
55
+
56
+ def pkg_root_dir
57
+ @pkg_root_dir ||= prepare_dir(root_dir / "packages")
58
+ end
59
+
60
+ def macro_root_dir
61
+ root_dir # To be updated: rootdir / "macros"
62
+ end
63
+
64
+ def macro_downloaded_root_dir
65
+ macro_root_dir / ".downloaded"
66
+ end
67
+
68
+ def macro_downloaded_sandbox
69
+ @macro_downloaded_sandbox ||= Sandbox.new(macro_downloaded_root_dir)
70
+ end
71
+
72
+ def pkg_umbrella_dir
73
+ @pkg_umbrella_dir ||= prepare_dir(root_dir / ".umbrella")
74
+ end
75
+
76
+ def pkg_checkouts_dir
77
+ pkg_umbrella_dir / ".build" / "checkouts"
78
+ end
79
+
80
+ def pkg_metadata_dir
81
+ @pkg_metadata_dir ||= prepare_dir(pkg_root_dir / "metadata")
82
+ end
83
+
84
+ private
85
+
86
+ def prepare_dir(dir)
87
+ dir.mkpath
88
+ dir
89
+ end
90
+ end
91
+ end
92
+ end
@@ -1,64 +1,14 @@
1
+ require "cocoapods-spm/config/spm"
2
+ require "cocoapods-spm/config/pod"
3
+ require "cocoapods-spm/config/project"
4
+
1
5
  module Pod
2
6
  module SPM
3
7
  class Config
4
8
  module Mixin
5
- def spm_config
6
- Config.instance
7
- end
8
-
9
- def macro_pods
10
- Pod::Config.instance.podfile.macro_pods
11
- end
12
- end
13
-
14
- attr_accessor :dsl_config, :cli_config
15
-
16
- def initialize
17
- @dsl_config = {
18
- :dont_prebuild_macros => false,
19
- :dont_prebuild_macros_if_exist => true
20
- }
21
- @cli_config = {}
22
- end
23
-
24
- def self.instance
25
- @instance ||= Config.new
26
- end
27
-
28
- def merged_config
29
- @dsl_config.merge(@cli_config)
30
- end
31
-
32
- def dont_prebuild_macros?
33
- merged_config[:dont_prebuild_macros]
34
- end
35
-
36
- def dont_prebuild_macros_if_exist?
37
- merged_config[:dont_prebuild_macros_if_exist]
38
- end
39
-
40
- def macro_config
41
- merged_config[:config] || merged_config[:default_macro_config] || "debug"
42
- end
43
-
44
- def all_macros
45
- @all_macros ||= Pod::Config.instance.podfile.macro_pods.keys
46
- end
47
-
48
- def macros
49
- merged_config[:all] ? all_macros : (merged_config[:macros] || [])
50
- end
51
-
52
- def macro_root_dir
53
- @macro_root_dir ||= Pathname(".spm.pods")
54
- end
55
-
56
- def macro_downloaded_root_dir
57
- macro_root_dir / ".downloaded"
58
- end
59
-
60
- def macro_downloaded_sandbox
61
- @macro_downloaded_sandbox ||= Sandbox.new(macro_downloaded_root_dir)
9
+ include ProjectConfigMixin
10
+ include PodConfigMixin
11
+ include SPMConfigMixin
62
12
  end
63
13
  end
64
14
  end
@@ -2,7 +2,7 @@ require "cocoapods-spm/config"
2
2
 
3
3
  module Pod
4
4
  class Podfile
5
- attr_accessor :spm_analyzer
5
+ attr_accessor :spm_resolver
6
6
 
7
7
  alias origin_pod pod
8
8
  def config_cocoapods_spm(options)
@@ -14,15 +14,6 @@ module Pod
14
14
  @pkg = pkg
15
15
  end
16
16
 
17
- def linkage
18
- # TODO: How to detect the linkage of an SPM library?
19
- @pkg.linkage.is_a?(Hash) ? @pkg.linkage[@product] : @pkg.linkage
20
- end
21
-
22
- def dynamic?
23
- linkage == :dynamic
24
- end
25
-
26
17
  def inspect
27
18
  "#<#{self.class} name=#{name} product=#{product} pkg=#{pkg}>"
28
19
  end
@@ -4,7 +4,7 @@ require "cocoapods-spm/def/spm_dependency"
4
4
  module Pod
5
5
  module SPM
6
6
  class Package
7
- attr_reader :name, :requirement, :url, :relative_path, :linkage
7
+ attr_reader :name, :requirement, :url, :relative_path
8
8
 
9
9
  def initialize(name, options = {})
10
10
  @name = name
@@ -18,11 +18,18 @@ module Pod
18
18
 
19
19
  def parse_options(options)
20
20
  @url = options[:url] || options[:git]
21
- @linkage = options[:linkage]
22
21
  @relative_path = relative_path_from(options)
23
22
  @requirement = requirement_from(options)
24
23
  end
25
24
 
25
+ def slug
26
+ @slug ||= File.basename(@url || @relative_path, ".*")
27
+ end
28
+
29
+ def absolute_path
30
+ (Pathname("Pods") / relative_path).realpath.to_s
31
+ end
32
+
26
33
  def relative_path_from(options)
27
34
  if (relative_path = options[:relative_path])
28
35
  relative_path
@@ -10,7 +10,7 @@ module Pod
10
10
  def initialize(context, options = {})
11
11
  @context = context
12
12
  @options = options
13
- @spm_analyzer = options[:spm_analyzer]
13
+ @spm_resolver = options[:spm_resolver]
14
14
  @analysis_result = options[:analysis_result]
15
15
  end
16
16
 
@@ -38,12 +38,16 @@ module Pod
38
38
  Config.instance
39
39
  end
40
40
 
41
+ def podfile
42
+ pod_config.podfile
43
+ end
44
+
41
45
  def run; end
42
46
 
43
47
  def self.run_hooks(phase, context, options)
44
48
  Dir["#{__dir__}/#{phase}/*.rb"].sort.each do |f|
45
49
  require f
46
- id = File.basename(f, ".*")
50
+ id = File.basename(f, ".*").split(".").last
47
51
  cls_name = "Pod::SPM::Hook::#{id.camelize}"
48
52
  UI.message "- Running hook: #{cls_name}" do
49
53
  cls_name.constantize.new(context, options).run
@@ -1,12 +1,12 @@
1
1
  require "cocoapods-spm/hooks/base"
2
- require "cocoapods-spm/installer/analyzer"
2
+ require "cocoapods-spm/resolver"
3
3
 
4
4
  module Pod
5
5
  module SPM
6
6
  class Hook
7
7
  class AddSpmPkgs < Hook
8
8
  def run
9
- return unless @spm_analyzer.spm_pkgs
9
+ return if @spm_resolver.result.spm_pkgs.empty?
10
10
 
11
11
  add_spm_pkg_refs_to_project
12
12
  add_spm_products_to_targets
@@ -20,7 +20,7 @@ module Pod
20
20
  end
21
21
 
22
22
  def add_spm_pkg_refs_to_project
23
- @spm_pkg_refs = @spm_analyzer.spm_pkgs.to_h do |pkg|
23
+ @spm_pkg_refs = @spm_resolver.result.spm_pkgs.to_h do |pkg|
24
24
  pkg_ref = pkg.create_pkg_ref(pods_project)
25
25
  pods_project.root_object.package_references << pkg_ref
26
26
  [pkg.name, pkg_ref]
@@ -33,17 +33,13 @@ module Pod
33
33
 
34
34
  def add_spm_products_to_targets
35
35
  pods_project.targets.each do |target|
36
- @spm_analyzer.spm_dependencies_by_target[target.name].to_a.each do |dep|
36
+ @spm_resolver.result.spm_dependencies_by_target[target.name].to_a.each do |dep|
37
37
  pkg_ref = spm_pkg_refs[dep.pkg.name]
38
38
  target_dep_ref = pkg_ref.create_target_dependency_ref(dep.product)
39
39
  target.dependencies << target_dep_ref
40
40
  end
41
41
  end
42
42
  end
43
-
44
- def podfile
45
- Pod::Config.instance.podfile
46
- end
47
43
  end
48
44
  end
49
45
  end
@@ -6,15 +6,16 @@ module Pod
6
6
  class Hook
7
7
  class UpdateSettings < Hook
8
8
  def run
9
- update_other_swift_flags
9
+ update_macro_plugin_flags
10
+ update_modulemap_flags
10
11
  update_swift_include_paths
11
12
  update_linker_flags
12
13
  end
13
14
 
14
15
  private
15
16
 
16
- def other_swift_flags_by_config
17
- @other_swift_flags_by_config ||= begin
17
+ def macro_plugin_flag_by_config
18
+ @macro_plugin_flag_by_config ||= begin
18
19
  hash = user_build_configurations.keys.to_h do |config|
19
20
  flags = macro_pods.keys.map do |name|
20
21
  metadata = Metadata.for_pod(name)
@@ -31,19 +32,29 @@ module Pod
31
32
  end
32
33
  end
33
34
 
34
- def update_other_swift_flags
35
+ def update_macro_plugin_flags
35
36
  return if spm_config.all_macros.empty?
36
37
 
37
- # For prebuilt macros
38
38
  perform_settings_update(
39
39
  update_targets: lambda do |_, _, config|
40
- { "OTHER_SWIFT_FLAGS" => other_swift_flags_by_config[config] }
40
+ { "OTHER_SWIFT_FLAGS" => macro_plugin_flag_by_config[config] }
41
+ end
42
+ )
43
+ end
44
+
45
+ def update_modulemap_flags
46
+ perform_settings_update(
47
+ update_targets: lambda do |target, _, _|
48
+ {
49
+ "OTHER_SWIFT_FLAGS" => modulemap_args_for_target(target, prefix: "-Xcc"),
50
+ "OTHER_CFLAGS" => modulemap_args_for_target(target)
51
+ }
41
52
  end
42
53
  )
43
54
  end
44
55
 
45
56
  def update_linker_flags
46
- return if @spm_analyzer.spm_pkgs.empty?
57
+ return if @spm_resolver.result.spm_pkgs.empty?
47
58
 
48
59
  # For packages to work in the main target
49
60
  perform_settings_update(
@@ -58,22 +69,32 @@ module Pod
58
69
  end
59
70
 
60
71
  def linker_flags_for(target)
61
- spm_deps = @spm_analyzer.spm_dependencies_by_target[target.to_s].to_a
62
- framework_flags = spm_deps.select(&:dynamic?).map { |d| "-framework \"#{d.product}\"" }
63
- library_flags = spm_deps.reject(&:dynamic?).map { |d| "-l\"#{d.product}.o\"" }
64
- framework_flags + library_flags
72
+ return [] if !target.is_a?(Pod::AggregateTarget) && target.build_as_static?
73
+
74
+ @spm_resolver.result.spm_products_for(target).map do |p|
75
+ p.dynamic? ? "-framework \"#{p.name}\"" : "-l\"#{p.name}.o\""
76
+ end
65
77
  end
66
78
 
67
79
  def update_swift_include_paths
68
- return if @spm_analyzer.spm_pkgs.empty?
80
+ return if @spm_resolver.result.spm_pkgs.empty? && spm_config.all_macros.empty?
69
81
 
70
- # For macro packages
71
82
  perform_settings_update(
72
83
  update_targets: lambda do |_, _, _|
73
84
  { "SWIFT_INCLUDE_PATHS" => "$(PODS_CONFIGURATION_BUILD_DIR)" }
74
85
  end
75
86
  )
76
87
  end
88
+
89
+ def modulemap_args_for_target(target, prefix: nil)
90
+ @spm_resolver
91
+ .result
92
+ .spm_products_for(target)
93
+ .reject { |p| p.headers_path.nil? }
94
+ .map { |p| "-fmodule-map-file=\"${GENERATED_MODULEMAP_DIR}/#{p.name}.modulemap\"" }
95
+ .map { |v| prefix.nil? ? v : "#{prefix} #{v}" }
96
+ .join(" ")
97
+ end
77
98
  end
78
99
  end
79
100
  end
@@ -18,12 +18,8 @@ module Pod
18
18
  private
19
19
 
20
20
  def framework_paths_for(target)
21
- @dynamic_deps_by_target ||=
22
- @spm_analyzer
23
- .spm_dependencies_by_target
24
- .transform_values { |deps| deps.select(&:dynamic?) }
25
- @dynamic_deps_by_target[target.to_s].map do |d|
26
- "${BUILT_PRODUCTS_DIR}/PackageFrameworks/#{d.product}.framework"
21
+ @spm_resolver.result.spm_products_for(target).select(&:dynamic?).map do |p|
22
+ "${BUILT_PRODUCTS_DIR}/PackageFrameworks/#{p.name}.framework"
27
23
  end
28
24
  end
29
25
 
@@ -37,13 +37,9 @@ module Pod
37
37
  raise "Package.swift not exist in #{macro_downloaded_dir}" \
38
38
  unless (macro_downloaded_dir / "Package.swift").exist?
39
39
 
40
- UI.message "Generating metadata at: #{metadata_path}" do
41
- raw = Dir.chdir(macro_downloaded_dir) do
42
- swift! ["package", "dump-package"]
43
- end
44
- metadata_path.write(raw)
45
- @metadata = Metadata.from_s(raw)
46
- end
40
+ raw = Dir.chdir(macro_downloaded_dir) { `swift package dump-package` }
41
+ metadata_path.write(raw)
42
+ @metadata = Metadata.from_s(raw)
47
43
  end
48
44
 
49
45
  def prebuild_macro_impl
@@ -21,10 +21,23 @@ module Pod
21
21
  from_file(Config.instance.macro_root_dir / name / "metadata.json")
22
22
  end
23
23
 
24
+ def [](key)
25
+ raw[key]
26
+ end
27
+
24
28
  def targets
25
29
  raw["targets"]
26
30
  end
27
31
 
32
+ def products
33
+ raw["products"]
34
+ end
35
+
36
+ def product_names_of_target(name)
37
+ names = products.select { |h| h["targets"].include?(name) }.map { |h| h["name"] }
38
+ names.empty? ? [name] : names
39
+ end
40
+
28
41
  def targets_of_type(type)
29
42
  targets.select { |t| t["type"] == type }
30
43
  end
@@ -7,7 +7,7 @@ module Pod
7
7
  end
8
8
 
9
9
  def includes_dynamic_spm_dependencies?
10
- podfile.spm_analyzer.spm_dependencies_for(self).any?(&:dynamic?)
10
+ podfile.spm_resolver.result.spm_products_for(self).any?(&:dynamic?)
11
11
  end
12
12
  end
13
13
  end
@@ -1,4 +1,4 @@
1
- require "cocoapods-spm/installer/analyzer"
1
+ require "cocoapods-spm/resolver"
2
2
  require "cocoapods-spm/macro/pod_installer"
3
3
  require "cocoapods-spm/hooks/base"
4
4
 
@@ -39,7 +39,7 @@ module Pod
39
39
 
40
40
  def hook_options
41
41
  {
42
- :spm_analyzer => @spm_analyzer,
42
+ :spm_resolver => @spm_resolver,
43
43
  :analysis_result => @analysis_result
44
44
  }
45
45
  end
@@ -55,10 +55,10 @@ module Pod
55
55
  end
56
56
 
57
57
  def resolve_spm_dependencies
58
- UI.section "Analyzing SPM dependencies" do
59
- @spm_analyzer ||= Pod::Installer::SPMAnalyzer.new(podfile, aggregate_targets)
60
- @spm_analyzer.analyze
61
- podfile.spm_analyzer = @spm_analyzer
58
+ UI.section "Resolving SPM dependencies" do
59
+ @spm_resolver ||= SPM::Resolver.new(podfile, aggregate_targets)
60
+ @spm_resolver.resolve
61
+ podfile.spm_resolver = @spm_resolver
62
62
  end
63
63
  end
64
64
  end
@@ -0,0 +1,24 @@
1
+ module Pod
2
+ module SPM
3
+ class Resolver
4
+ class Product
5
+ attr_reader :pkg, :name, :linkage, :headers_path
6
+
7
+ def initialize(options = {})
8
+ @pkg = options[:pkg]
9
+ @name = options[:name]
10
+ @linkage = options.fetch(:linkage, :static)
11
+ @headers_path = options[:headers_path]
12
+ end
13
+
14
+ def inspect
15
+ "#<#{self.class} #{pkg}/#{name}>"
16
+ end
17
+
18
+ def dynamic?
19
+ @linkage == :dynamic
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,125 @@
1
+ module Pod
2
+ module SPM
3
+ class Resolver
4
+ class ProductDependencyResolver
5
+ require "cocoapods-spm/resolver/product"
6
+
7
+ include Config::Mixin
8
+
9
+ def initialize(podfile, result)
10
+ @podfile = podfile
11
+ @result = result
12
+ end
13
+
14
+ def resolve
15
+ generate_metadata
16
+ resolve_dynamic_products
17
+ resolve_headers_path_by_target
18
+ resolve_product_deps
19
+ end
20
+
21
+ private
22
+
23
+ def generate_metadata
24
+ spm_config.pkg_checkouts_dir.glob("*").each do |dir|
25
+ next if dir.glob("Package*.swift").empty?
26
+
27
+ raw = Dir.chdir(dir) { `swift package dump-package` }
28
+ metadata = Metadata.from_s(raw)
29
+ write_metadata = lambda do |name|
30
+ (spm_config.pkg_metadata_dir / "#{name}.json").write(raw)
31
+ @result.metadata_cache[name] = metadata
32
+ end
33
+
34
+ pkg_name = metadata["name"]
35
+ pkg_slug = dir.basename.to_s
36
+ write_metadata.call(pkg_name)
37
+ write_metadata.call(pkg_slug) unless pkg_name == pkg_slug
38
+ end
39
+ end
40
+
41
+ def resolve_dynamic_products
42
+ @dynamic_products ||= Set.new
43
+ @result.metadata_cache.each_value do |metadata|
44
+ metadata.products.each do |h|
45
+ library_types = h.fetch("type", {}).fetch("library", [])
46
+ @dynamic_products << h["name"] if library_types.include?("dynamic")
47
+ end
48
+ end
49
+ end
50
+
51
+ def resolve_headers_path_by_target
52
+ @headers_path_by_product ||= {}
53
+ @result.metadata_cache.each_value do |metadata|
54
+ metadata.targets.each do |h|
55
+ next unless h.key?("publicHeadersPath")
56
+
57
+ metadata.product_names_of_target(h["name"]).each do |name|
58
+ @headers_path_by_product[name] = h["publicHeadersPath"]
59
+ end
60
+ end
61
+ end
62
+ end
63
+
64
+ def resolve_product_deps
65
+ @result.spm_dependencies_by_target.values.flatten.uniq(&:name).each do |dep|
66
+ verify_product_exists_in_pkg(dep.pkg.name, dep.product)
67
+ product = create_product(dep.pkg.name, dep.product)
68
+ recursive_products_of(product)
69
+ end
70
+ end
71
+
72
+ def verify_product_exists_in_pkg(pkg, name)
73
+ return unless @result.metadata_of(pkg).products.find { |h| h["name"] == name }.nil?
74
+
75
+ raise Informative, "Package `#{pkg}` does not contain product named `#{name}`"
76
+ end
77
+
78
+ def recursive_products_of(product)
79
+ products = [product] + direct_products_of(product).flat_map do |child|
80
+ [child] + recursive_products_of(child)
81
+ end
82
+ @result.spm_products[product.name] = products
83
+ products
84
+ end
85
+
86
+ def direct_products_of(product)
87
+ metadata = @result.metadata_of(product.pkg)
88
+ metadata
89
+ .products
90
+ .find { |h| h["name"] == product.name }
91
+ .to_h
92
+ .fetch("targets", [product.name])
93
+ .flat_map do |t|
94
+ metadata
95
+ .targets
96
+ .find { |h| h["name"] == t }
97
+ .fetch("dependencies", [])
98
+ .map { |h| product_from_hash(h, metadata) }
99
+ end
100
+ end
101
+
102
+ def product_from_hash(hash, metadata)
103
+ if hash.key?("byName")
104
+ name = hash["byName"][0]
105
+ pkg = metadata["name"]
106
+ elsif hash.key?("product")
107
+ name, pkg = hash["product"]
108
+ elsif hash.key?("target")
109
+ # TODO: Handle this
110
+ end
111
+ create_product(pkg, name)
112
+ end
113
+
114
+ def create_product(pkg, name)
115
+ Product.new(
116
+ pkg: pkg,
117
+ name: name,
118
+ linkage: @dynamic_products.include?(name) ? :dynamic : :static,
119
+ headers_path: @headers_path_by_product[name]
120
+ )
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,43 @@
1
+ module Pod
2
+ module SPM
3
+ class Resolver
4
+ class Result
5
+ class WritableResult < Result
6
+ attr_accessor :spm_pkgs, :spm_dependencies_by_target, :spm_products, :metadata_cache
7
+
8
+ def to_read_only
9
+ Result.new(
10
+ spm_pkgs: spm_pkgs,
11
+ spm_dependencies_by_target: spm_dependencies_by_target,
12
+ spm_products: spm_products,
13
+ metadata_cache: metadata_cache
14
+ )
15
+ end
16
+ end
17
+
18
+ attr_reader :spm_pkgs, :spm_dependencies_by_target, :spm_products, :metadata_cache
19
+
20
+ def initialize(options = {})
21
+ @spm_pkgs = options[:spm_pkgs] || []
22
+ @spm_dependencies_by_target = options[:spm_dependencies_by_target] || {}
23
+ @spm_products = options[:spm_products] || {}
24
+ @metadata_cache = options[:metadata_cache] || {}
25
+ end
26
+
27
+ def metadata_of(name)
28
+ return @metadata_cache[name] if @metadata_cache.key?(name)
29
+
30
+ raise Informative, "Metadata of `#{name}` does not exist"
31
+ end
32
+
33
+ def spm_dependencies_for(target)
34
+ @spm_dependencies_by_target[target.to_s]
35
+ end
36
+
37
+ def spm_products_for(target)
38
+ spm_dependencies_for(target).flat_map { |d| @spm_products[d.product] }.uniq(&:name)
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,64 @@
1
+ module Pod
2
+ module SPM
3
+ class Resolver
4
+ class TargetDependencyResolver
5
+ def initialize(podfile, aggregate_targets, result)
6
+ @podfile = podfile
7
+ @aggregate_targets = aggregate_targets
8
+ @result = result
9
+ end
10
+
11
+ def resolve
12
+ resolve_spm_pkgs
13
+ resolve_spm_dependencies_by_target
14
+ end
15
+
16
+ private
17
+
18
+ def resolve_spm_pkgs
19
+ @result.spm_pkgs = @podfile.target_definition_list.flat_map(&:spm_pkgs).uniq
20
+ end
21
+
22
+ def resolve_spm_dependencies_by_target
23
+ resolve_dependencies_for_targets
24
+ resolve_dependencies_for_aggregate_targets
25
+ @result.spm_dependencies_by_target.values.flatten.each { |d| d.pkg = spm_pkg_for(d.name) }
26
+ end
27
+
28
+ def resolve_dependencies_for_targets
29
+ specs = @aggregate_targets.flat_map(&:specs).uniq
30
+ specs.each do |spec|
31
+ @result.spm_dependencies_by_target[spec.name] = spec.spm_dependencies
32
+ end
33
+ end
34
+
35
+ def resolve_dependencies_for_aggregate_targets
36
+ @aggregate_targets.each do |target|
37
+ spm_dependencies = target.specs.flat_map(&:spm_dependencies)
38
+ @result.spm_dependencies_by_target[target.to_s] = merge_spm_dependencies(spm_dependencies)
39
+ end
40
+
41
+ @podfile.spm_pkgs_by_aggregate_target.each do |target, pkgs|
42
+ existing = @result.spm_dependencies_by_target[target].to_a
43
+ spm_dependencies = pkgs.flat_map(&:to_dependencies)
44
+ @result.spm_dependencies_by_target[target] = merge_spm_dependencies(existing + spm_dependencies)
45
+ end
46
+ end
47
+
48
+ def merge_spm_dependencies(deps)
49
+ deps_by_name = Hash.new { |h, k| h[k] = [] }
50
+ deps.each { |d| deps_by_name[d.name] << d }
51
+ deps_by_name.each do |name, ds|
52
+ deps_by_name[name] = ds.uniq { |d| [d.name, d.product] }
53
+ end
54
+ deps_by_name.values.flatten
55
+ end
56
+
57
+ def spm_pkg_for(name)
58
+ @_spm_pkgs_by_name ||= @result.spm_pkgs.to_h { |pkg| [pkg.name, pkg] }
59
+ @_spm_pkgs_by_name[name]
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,67 @@
1
+ module Pod
2
+ module SPM
3
+ class UmbrellaPackage
4
+ include Config::Mixin
5
+
6
+ def initialize(podfile)
7
+ @podfile = podfile
8
+ @spm_pkgs = @podfile.target_definition_list.flat_map(&:spm_pkgs).uniq
9
+ end
10
+
11
+ def prepare
12
+ generate_pkg_swift
13
+ swift_pkg_resolve
14
+ create_symlinks_to_local_pkgs
15
+ self
16
+ end
17
+
18
+ private
19
+
20
+ def generate_pkg_swift
21
+ swift_tools_version = "5.7"
22
+ dependencies = @spm_pkgs.map do |pkg|
23
+ # https://developer.apple.com/documentation/packagedescription/package/dependency
24
+ next ".package(path: \"#{pkg.absolute_path}\")" if pkg.local?
25
+
26
+ tail = case pkg.requirement[:kind]
27
+ when "exactVersion"
28
+ "exact: \"#{pkg.requirement[:version]}\""
29
+ when "branch"
30
+ "branch: \"#{pkg.requirement[:branch]}\""
31
+ when "revision"
32
+ "revision: \"#{pkg.requirement[:revision]}\""
33
+ else
34
+ # TODO: Handle this
35
+ "todo: \"handle this\""
36
+ end
37
+ ".package(url: \"#{pkg.url}\", #{tail})"
38
+ end
39
+
40
+ package_content = <<~HEREDOC
41
+ // swift-tools-version:#{swift_tools_version}
42
+ import PackageDescription
43
+
44
+ let package = Package(
45
+ name: "_umbrella_",
46
+ dependencies: [
47
+ #{dependencies.join(",\n ")}
48
+ ]
49
+ )
50
+ HEREDOC
51
+ (spm_config.pkg_umbrella_dir / "Package.swift").write(package_content)
52
+ end
53
+
54
+ def swift_pkg_resolve
55
+ Dir.chdir(spm_config.pkg_umbrella_dir) { `swift package resolve` }
56
+ end
57
+
58
+ def create_symlinks_to_local_pkgs
59
+ @spm_pkgs.select(&:local?).each do |pkg|
60
+ dst_dir = spm_config.pkg_checkouts_dir / pkg.slug
61
+ dst_dir.delete if dst_dir.exist?
62
+ File.symlink(pkg.absolute_path, dst_dir)
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -1,10 +1,10 @@
1
1
  module Pod
2
- class Installer
3
- class SPMValidator
4
- def initialize(aggregate_targets, spm_pkgs, spm_dependencies_by_target)
2
+ module SPM
3
+ class Validator
4
+ def initialize(aggregate_targets, result)
5
5
  @aggregate_targets = aggregate_targets
6
- @spm_pkgs = spm_pkgs
7
- @spm_dependencies_by_target = spm_dependencies_by_target
6
+ @spm_pkgs = result.spm_pkgs
7
+ @spm_dependencies_by_target = result.spm_dependencies_by_target
8
8
  end
9
9
 
10
10
  def validate!
@@ -0,0 +1,45 @@
1
+ require "cocoapods-spm/resolver/validator"
2
+ require "cocoapods-spm/resolver/umbrella_package"
3
+
4
+ module Pod
5
+ module SPM
6
+ class Resolver
7
+ require "cocoapods-spm/resolver/result"
8
+ require "cocoapods-spm/resolver/target_dep_resolver"
9
+ require "cocoapods-spm/resolver/product_dep_resolver"
10
+
11
+ def initialize(podfile, aggregate_targets)
12
+ @_result = Result::WritableResult.new
13
+ @podfile = podfile
14
+ @aggregate_targets = aggregate_targets
15
+ @umbrella_pkg = nil
16
+ @target_dep_resolver = TargetDependencyResolver.new(podfile, aggregate_targets, @_result)
17
+ @product_dep_resolver = ProductDependencyResolver.new(podfile, @_result)
18
+ end
19
+
20
+ def resolve
21
+ generate_umbrella_pkg
22
+ resolvers.each(&:resolve)
23
+ validate!
24
+ end
25
+
26
+ def result
27
+ @result ||= @_result.to_read_only
28
+ end
29
+
30
+ private
31
+
32
+ def resolvers
33
+ [@target_dep_resolver, @product_dep_resolver]
34
+ end
35
+
36
+ def generate_umbrella_pkg
37
+ @umbrella_pkg = Pod::SPM::UmbrellaPackage.new(@podfile).prepare
38
+ end
39
+
40
+ def validate!
41
+ Validator.new(@aggregate_targets, result).validate!
42
+ end
43
+ end
44
+ end
45
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cocoapods-spm
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.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: 2024-03-05 00:00:00.000000000 Z
11
+ date: 2024-04-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj
@@ -36,6 +36,9 @@ files:
36
36
  - lib/cocoapods-spm/command/prebuild.rb
37
37
  - lib/cocoapods-spm/command/spm.rb
38
38
  - lib/cocoapods-spm/config.rb
39
+ - lib/cocoapods-spm/config/pod.rb
40
+ - lib/cocoapods-spm/config/project.rb
41
+ - lib/cocoapods-spm/config/spm.rb
39
42
  - lib/cocoapods-spm/def/podfile.rb
40
43
  - lib/cocoapods-spm/def/spec.rb
41
44
  - lib/cocoapods-spm/def/spm_dependency.rb
@@ -44,11 +47,9 @@ files:
44
47
  - lib/cocoapods-spm/def/xcodeproj.rb
45
48
  - lib/cocoapods-spm/executables.rb
46
49
  - lib/cocoapods-spm/hooks/base.rb
47
- - lib/cocoapods-spm/hooks/post_integrate/add_spm_pkgs.rb
48
- - lib/cocoapods-spm/hooks/post_integrate/update_embed_frameworks_script.rb
49
- - lib/cocoapods-spm/hooks/post_integrate/update_settings.rb
50
- - lib/cocoapods-spm/installer/analyzer.rb
51
- - lib/cocoapods-spm/installer/validator.rb
50
+ - lib/cocoapods-spm/hooks/post_integrate/1.add_spm_pkgs.rb
51
+ - lib/cocoapods-spm/hooks/post_integrate/5.update_settings.rb
52
+ - lib/cocoapods-spm/hooks/post_integrate/6.update_embed_frameworks_script.rb
52
53
  - lib/cocoapods-spm/macro/fetcher.rb
53
54
  - lib/cocoapods-spm/macro/pod_installer.rb
54
55
  - lib/cocoapods-spm/macro/prebuilder.rb
@@ -56,6 +57,13 @@ files:
56
57
  - lib/cocoapods-spm/metadata.rb
57
58
  - lib/cocoapods-spm/patch/aggregate_target.rb
58
59
  - lib/cocoapods-spm/patch/installer.rb
60
+ - lib/cocoapods-spm/resolver.rb
61
+ - lib/cocoapods-spm/resolver/product.rb
62
+ - lib/cocoapods-spm/resolver/product_dep_resolver.rb
63
+ - lib/cocoapods-spm/resolver/result.rb
64
+ - lib/cocoapods-spm/resolver/target_dep_resolver.rb
65
+ - lib/cocoapods-spm/resolver/umbrella_package.rb
66
+ - lib/cocoapods-spm/resolver/validator.rb
59
67
  - lib/cocoapods_plugin.rb
60
68
  homepage: https://github.com/trinhngocthuyen/cocoapods-spm
61
69
  licenses:
@@ -1,77 +0,0 @@
1
- require "cocoapods-spm/installer/validator"
2
-
3
- module Pod
4
- class Installer
5
- class SPMAnalyzer
6
- attr_reader :spm_pkgs, :spm_dependencies_by_target
7
-
8
- def initialize(podfile, aggregate_targets)
9
- @podfile = podfile
10
- @aggregate_targets = aggregate_targets
11
- @spm_pkgs = []
12
- @spm_dependencies_by_target = {}
13
- end
14
-
15
- def analyze
16
- analyze_spm_pkgs
17
- analyze_spm_dependencies_by_target
18
- validate!
19
- end
20
-
21
- def spm_dependencies_for(target)
22
- @spm_dependencies_by_target[target.to_s]
23
- end
24
-
25
- private
26
-
27
- def analyze_spm_pkgs
28
- @spm_pkgs = @podfile.target_definition_list.flat_map(&:spm_pkgs).uniq
29
- end
30
-
31
- def analyze_spm_dependencies_by_target
32
- analyze_dependencies_for_targets
33
- analyze_dependencies_for_aggregate_targets
34
- @spm_dependencies_by_target.values.flatten.each { |d| d.pkg = spm_pkg_for(d.name) }
35
- end
36
-
37
- def analyze_dependencies_for_targets
38
- specs = @aggregate_targets.flat_map(&:specs).uniq
39
- specs.each do |spec|
40
- @spm_dependencies_by_target[spec.name] = spec.spm_dependencies
41
- end
42
- end
43
-
44
- def analyze_dependencies_for_aggregate_targets
45
- @aggregate_targets.each do |target|
46
- spm_dependencies = target.specs.flat_map(&:spm_dependencies)
47
- @spm_dependencies_by_target[target.to_s] = merge_spm_dependencies(spm_dependencies)
48
- end
49
-
50
- @podfile.spm_pkgs_by_aggregate_target.each do |target, pkgs|
51
- existing = @spm_dependencies_by_target[target].to_a
52
- spm_dependencies = pkgs.flat_map(&:to_dependencies)
53
- @spm_dependencies_by_target[target] = merge_spm_dependencies(existing + spm_dependencies)
54
- end
55
- end
56
-
57
- def merge_spm_dependencies(deps)
58
- deps_by_name = Hash.new { |h, k| h[k] = [] }
59
- deps.each { |d| deps_by_name[d.name] << d }
60
- deps_by_name.each do |name, ds|
61
- deps_by_name[name] = ds.uniq { |d| [d.name, d.product] }
62
- end
63
- deps_by_name.values.flatten
64
- end
65
-
66
- def spm_pkg_for(name)
67
- @_spm_pkgs_by_name ||= @spm_pkgs.to_h { |pkg| [pkg.name, pkg] }
68
- @_spm_pkgs_by_name[name]
69
- end
70
-
71
- def validate!
72
- validator = SPMValidator.new(@aggregate_targets, @spm_pkgs, @spm_dependencies_by_target)
73
- validator.validate!
74
- end
75
- end
76
- end
77
- end