cocoapods-spm 0.1.1 → 0.1.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: 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