cocoapods-spm 0.1.3 → 0.1.4

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: e61ad227d509165fab0c8f3e832aa06d05524fa7c2cbfd4d7cc8f393252fc60f
4
- data.tar.gz: 66f6bf9e254c7a99edc55f304fcf34ea60867fbbb9f138a6473eb200b6fa9f32
3
+ metadata.gz: 922b55ffd54350ec1e1be78c273b0078acfcdf7bca7f29c87281367507ffcf13
4
+ data.tar.gz: 9e0d2e7202e2d5486d92e039aae84b0caeb690b7c6e8c73a3b57110177ec8b14
5
5
  SHA512:
6
- metadata.gz: e48c19f9a2ed81601a69cca75ceda44b9353bf76f996458dc3398dad8e7b0ed2fa6fff8ce03cad91122cdcf6f7603a5cc1070b9944dfab98a0d1ff5081f82740
7
- data.tar.gz: d26d1674591412b761b92e51154142b5e76f7515464b0e462d5b26a06caeadd3162df96308d2ff34b1cb3d27c554eb33715d2248b7e66e2e58e1d56ceb4b1214
6
+ metadata.gz: c02a69fa12d098b6103d3eccb6dbf5b19ba50473b8c23913b6e5f17c9fd067c7fac3539c9a84264ba9a614c20771c4f641c0640a6c63a862aa2c5d7fc6e35154
7
+ data.tar.gz: 5bafa557cfb91f192eaf0923e5e86503a490442104f102abd69a5b1e458395fcb1980394e0d4a65a567dd80f93bff1034ea118f37e09d2cf038dd8e83eaa4597
@@ -16,7 +16,7 @@ module Pod
16
16
  def initialize
17
17
  @dsl_config = {
18
18
  :dont_prebuild_macros => false,
19
- :dont_prebuild_macros_if_exist => true
19
+ :dont_prebuild_macros_if_exist => true,
20
20
  }
21
21
  @cli_config = {}
22
22
  end
@@ -77,6 +77,10 @@ module Pod
77
77
  pkg_umbrella_dir / ".build" / "checkouts"
78
78
  end
79
79
 
80
+ def pkg_artifacts_dir
81
+ pkg_umbrella_dir / ".build" / "artifacts"
82
+ end
83
+
80
84
  def pkg_metadata_dir
81
85
  @pkg_metadata_dir ||= prepare_dir(pkg_root_dir / "metadata")
82
86
  end
@@ -1,10 +1,11 @@
1
1
  require "cocoapods-spm/config"
2
+ require "cocoapods-spm/helpers/patch"
2
3
 
3
4
  module Pod
4
5
  class Podfile
6
+ include Mixin::PatchingBehavior
5
7
  attr_accessor :spm_resolver
6
8
 
7
- alias origin_pod pod
8
9
  def config_cocoapods_spm(options)
9
10
  SPM::Config.instance.dsl_config = options
10
11
  end
@@ -13,7 +14,7 @@ module Pod
13
14
  @macro_pods ||= {}
14
15
  end
15
16
 
16
- def pod(name = nil, *requirements)
17
+ patch_method :pod do |name = nil, *requirements|
17
18
  macro = requirements[0].delete(:macro) if requirements.first.is_a?(Hash)
18
19
  macro ||= {}
19
20
  unless macro.empty?
@@ -27,6 +28,10 @@ module Pod
27
28
  current_target_definition.store_spm_pkg(name, options)
28
29
  end
29
30
 
31
+ def spm_pkgs
32
+ spm_pkgs_by_aggregate_target.values.flatten.uniq(&:name)
33
+ end
34
+
30
35
  def spm_pkgs_for(target)
31
36
  spm_pkgs_by_aggregate_target[target.to_s]
32
37
  end
@@ -15,8 +15,10 @@ module Pod
15
15
  end
16
16
 
17
17
  def inspect
18
- "#<#{self.class} name=#{name} product=#{product} pkg=#{pkg}>"
18
+ "#<#{self.class} #{name}/#{product} pkg=#{pkg}>"
19
19
  end
20
+
21
+ alias to_s inspect
20
22
  end
21
23
  end
22
24
  end
@@ -42,9 +42,11 @@ module Pod
42
42
  end
43
43
 
44
44
  def inspect
45
- "#<#{self.class} name=#{name}>"
45
+ "#<#{self.class} #{name}>"
46
46
  end
47
47
 
48
+ alias to_s inspect
49
+
48
50
  def local?
49
51
  @relative_path != nil
50
52
  end
@@ -0,0 +1,14 @@
1
+ module Mixin
2
+ module PatchingBehavior
3
+ def patch_method(method_name, &block)
4
+ raw_method_name = "origin_#{method_name}"
5
+ alias_method raw_method_name, method_name
6
+ define_method(method_name, &block)
7
+ private raw_method_name
8
+ end
9
+
10
+ def self.included(base)
11
+ base.extend(self)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,61 @@
1
+ require "cocoapods-spm/hooks/base"
2
+
3
+ module Pod
4
+ module SPM
5
+ module UpdateScript
6
+ module Mixin
7
+ def update_script(options = {})
8
+ script_name = options[:name]
9
+ content_by_target = options[:content_by_target]
10
+
11
+ aggregate_targets.each do |target|
12
+ lines, input_paths, output_paths = content_by_target.call(target)
13
+ next if input_paths.empty?
14
+
15
+ update_script_content(
16
+ path: target.send("#{script_name}_path"),
17
+ before: options[:insert_before],
18
+ insert: lines.join("\n")
19
+ )
20
+
21
+ # Update input/output files
22
+ user_build_configurations.each_key do |config|
23
+ append_contents = lambda do |method_name, contents|
24
+ target.send(method_name, config).open("a") do |f|
25
+ contents.each { |p| f << "\n" << p }
26
+ end
27
+ end
28
+ append_contents.call("#{script_name}_input_files_path", input_paths)
29
+ append_contents.call("#{script_name}_output_files_path", output_paths)
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def update_script_content(options = {})
37
+ match_content = options[:before]
38
+ insert_content = <<~SH
39
+ # --------------------------------------------------------
40
+ # Added by `cocoapods-spm`
41
+ # --------------------------------------------------------
42
+ #{options[:insert]}
43
+ # --------------------------------------------------------
44
+ SH
45
+ options[:path].open("r+") do |f|
46
+ content = f.read
47
+ offset = content.index(match_content) unless match_content.nil?
48
+ if offset.nil?
49
+ f << "\n" << insert_content
50
+ else
51
+ f.seek(offset)
52
+ after_content = f.read
53
+ f.seek(offset)
54
+ f << "\n" << insert_content << after_content
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -1,5 +1,5 @@
1
1
  require "cocoapods-spm/hooks/base"
2
- require "cocoapods-spm/metadata"
2
+ require "cocoapods-spm/macro/metadata"
3
3
 
4
4
  module Pod
5
5
  module SPM
@@ -18,7 +18,7 @@ module Pod
18
18
  @macro_plugin_flag_by_config ||= begin
19
19
  hash = user_build_configurations.keys.to_h do |config|
20
20
  flags = macro_pods.keys.map do |name|
21
- metadata = Metadata.for_pod(name)
21
+ metadata = MacroMetadata.for_pod(name)
22
22
  impl_module_name = metadata.macro_impl_name
23
23
  plugin_executable_path =
24
24
  "${PODS_ROOT}/../.spm.pods/#{name}/.prebuilt/#{config.to_s.downcase}/" \
@@ -47,7 +47,7 @@ module Pod
47
47
  update_targets: lambda do |target, _, _|
48
48
  {
49
49
  "OTHER_SWIFT_FLAGS" => modulemap_args_for_target(target, prefix: "-Xcc"),
50
- "OTHER_CFLAGS" => modulemap_args_for_target(target)
50
+ "OTHER_CFLAGS" => modulemap_args_for_target(target),
51
51
  }
52
52
  end
53
53
  )
@@ -62,7 +62,7 @@ module Pod
62
62
  {
63
63
  "OTHER_LDFLAGS" => linker_flags_for(target),
64
64
  "FRAMEWORK_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}/PackageFrameworks\"",
65
- "LIBRARY_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}\""
65
+ "LIBRARY_SEARCH_PATHS" => "\"${PODS_CONFIGURATION_BUILD_DIR}\"",
66
66
  }
67
67
  end
68
68
  )
@@ -87,9 +87,8 @@ module Pod
87
87
  def modulemap_args_for_target(target, prefix: nil)
88
88
  @spm_resolver
89
89
  .result
90
- .spm_products_for(target)
91
- .reject { |p| p.headers_path.nil? }
92
- .map { |p| "-fmodule-map-file=\"${GENERATED_MODULEMAP_DIR}/#{p.name}.modulemap\"" }
90
+ .spm_targets_for(target)
91
+ .filter_map(&:clang_modulemap_arg)
93
92
  .map { |v| prefix.nil? ? v : "#{prefix} #{v}" }
94
93
  .join(" ")
95
94
  end
@@ -1,52 +1,30 @@
1
1
  require "cocoapods-spm/hooks/base"
2
+ require "cocoapods-spm/hooks/helpers/update_script"
2
3
 
3
4
  module Pod
4
5
  module SPM
5
6
  class Hook
6
7
  class UpdateEmbedFrameworksScript < Hook
7
- def run
8
- aggregate_targets.each do |target|
9
- next if framework_paths_for(target).empty?
8
+ include UpdateScript::Mixin
10
9
 
11
- update_embed_frameworks_script(target)
12
- user_build_configurations.each_key do |config|
13
- update_embed_frameworks_script_files_path(target, config)
10
+ def run
11
+ update_script(
12
+ name: :embed_frameworks_script,
13
+ content_by_target: lambda do |target|
14
+ input_paths = framework_paths_for(target)
15
+ output_paths = input_paths.map do |p|
16
+ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{File.basename(p)}"
17
+ end
18
+ lines = input_paths.map { |p| "install_framework \"#{p}\"" }
19
+ [lines, input_paths, output_paths]
14
20
  end
15
- end
21
+ )
16
22
  end
17
23
 
18
24
  private
19
25
 
20
26
  def framework_paths_for(target)
21
- @spm_resolver.result.spm_products_for(target).select(&:dynamic?).map do |p|
22
- "${BUILT_PRODUCTS_DIR}/PackageFrameworks/#{p.name}.framework"
23
- end
24
- end
25
-
26
- def update_embed_frameworks_script(target)
27
- lines = framework_paths_for(target).map { |p| "install_framework \"#{p}\"" }
28
- target.embed_frameworks_script_path.open("a") do |f|
29
- f << "\n" << <<~SH
30
- # --------------------------------------------------------
31
- # Added by `cocoapods-spm` to embed SPM package frameworks
32
- # --------------------------------------------------------
33
- #{lines.join("\n")}
34
- # --------------------------------------------------------
35
- SH
36
- end
37
- end
38
-
39
- def update_embed_frameworks_script_files_path(target, config)
40
- input_paths = framework_paths_for(target)
41
- output_paths = input_paths.map do |p|
42
- "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/#{File.basename(p)}"
43
- end
44
- target.embed_frameworks_script_input_files_path(config).open("a") do |f|
45
- input_paths.each { |p| f << "\n" << p }
46
- end
47
- target.embed_frameworks_script_output_files_path(config).open("a") do |f|
48
- output_paths.each { |p| f << "\n" << p }
49
- end
27
+ @spm_resolver.result.spm_targets_for(target).select(&:dynamic?).map(&:built_framework_path).uniq
50
28
  end
51
29
  end
52
30
  end
@@ -0,0 +1,33 @@
1
+ require "cocoapods-spm/hooks/base"
2
+ require "cocoapods-spm/hooks/helpers/update_script"
3
+
4
+ module Pod
5
+ module SPM
6
+ class Hook
7
+ class UpdateCopyResourcesScript < Hook
8
+ include UpdateScript::Mixin
9
+
10
+ def run
11
+ update_script(
12
+ name: :copy_resources_script,
13
+ insert_before: Generator::CopyResourcesScript::RSYNC_CALL,
14
+ content_by_target: lambda do |target|
15
+ input_paths = resource_paths_for(target)
16
+ output_paths = input_paths.map do |p|
17
+ "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/#{File.basename(p)}"
18
+ end
19
+ lines = input_paths.map { |p| "install_resource \"#{p}\"" }
20
+ [lines, input_paths, output_paths]
21
+ end
22
+ )
23
+ end
24
+
25
+ private
26
+
27
+ def resource_paths_for(target)
28
+ @spm_resolver.result.spm_targets_for(target).flat_map(&:resources).map(&:built_resource_path).uniq
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,11 @@
1
+ require "cocoapods-spm/swift/package/description"
2
+
3
+ module Pod
4
+ module SPM
5
+ class MacroMetadata < Swift::PackageDescription
6
+ def self.for_pod(name)
7
+ from_file(Config.instance.macro_root_dir / name / "metadata.json")
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,4 +1,4 @@
1
- require "cocoapods-spm/metadata"
1
+ require "cocoapods-spm/macro/metadata"
2
2
 
3
3
  module Pod
4
4
  module SPM
@@ -39,7 +39,7 @@ module Pod
39
39
 
40
40
  raw = Dir.chdir(macro_downloaded_dir) { `swift package dump-package` }
41
41
  metadata_path.write(raw)
42
- @metadata = Metadata.from_s(raw)
42
+ @metadata = MacroMetadata.from_s(raw)
43
43
  end
44
44
 
45
45
  def prebuild_macro_impl
@@ -1,5 +1,4 @@
1
1
  require "cocoapods-spm/config"
2
- require "cocoapods-spm/metadata"
3
2
  require "cocoapods-spm/executables"
4
3
  require "cocoapods-spm/def/target_definition"
5
4
  require "cocoapods-spm/def/podfile"
@@ -1,13 +1,25 @@
1
+ require "cocoapods-spm/helpers/patch"
2
+
1
3
  module Pod
2
4
  class AggregateTarget
3
- alias origin_includes_frameworks? includes_frameworks?
5
+ include Mixin::PatchingBehavior
6
+
7
+ private
4
8
 
5
- def includes_frameworks?
9
+ patch_method :includes_frameworks? do
6
10
  origin_includes_frameworks? || includes_dynamic_spm_dependencies?
7
11
  end
8
12
 
13
+ patch_method :includes_resources? do
14
+ origin_includes_resources? || includes_spm_resouces?
15
+ end
16
+
9
17
  def includes_dynamic_spm_dependencies?
10
- podfile.spm_resolver.result.spm_products_for(self).any?(&:dynamic?)
18
+ podfile.spm_resolver.result.spm_targets_for(self).any?(&:dynamic?)
19
+ end
20
+
21
+ def includes_spm_resouces?
22
+ !podfile.spm_resolver.result.spm_targets_for(self).all? { |t| t.resources.empty? }
11
23
  end
12
24
  end
13
25
  end
@@ -1,19 +1,19 @@
1
+ require "cocoapods-spm/helpers/patch"
1
2
  require "cocoapods-spm/resolver"
2
3
  require "cocoapods-spm/macro/pod_installer"
3
4
  require "cocoapods-spm/hooks/base"
4
5
 
5
6
  module Pod
6
7
  class Installer
8
+ include Mixin::PatchingBehavior
7
9
  include SPM::Config::Mixin
8
10
 
9
- alias origin_resolve_dependencies resolve_dependencies
10
- def resolve_dependencies
11
+ patch_method :resolve_dependencies do
11
12
  origin_resolve_dependencies
12
13
  resolve_spm_dependencies
13
14
  end
14
15
 
15
- alias origin_create_pod_installer create_pod_installer
16
- def create_pod_installer(pod_name)
16
+ patch_method :create_pod_installer do |pod_name|
17
17
  if macro_pods.include?(pod_name)
18
18
  macro_pod_installer = MacroPodInstaller.new(
19
19
  sandbox,
@@ -28,8 +28,7 @@ module Pod
28
28
  end
29
29
  end
30
30
 
31
- alias origin_integrate integrate
32
- def integrate
31
+ patch_method :integrate do
33
32
  run_spm_pre_integrate_hooks
34
33
  origin_integrate
35
34
  run_spm_post_integrate_hooks
@@ -40,7 +39,7 @@ module Pod
40
39
  def hook_options
41
40
  {
42
41
  :spm_resolver => @spm_resolver,
43
- :analysis_result => @analysis_result
42
+ :analysis_result => @analysis_result,
44
43
  }
45
44
  end
46
45
 
@@ -0,0 +1,37 @@
1
+ module Pod
2
+ module SPM
3
+ class Resolver
4
+ class RecursiveTargetResolver
5
+ require "cocoapods-spm/swift/package/project_packages"
6
+
7
+ include Config::Mixin
8
+
9
+ def initialize(podfile, result)
10
+ @podfile = podfile
11
+ @result = result
12
+ end
13
+
14
+ def resolve
15
+ resolve_recursive_targets
16
+ end
17
+
18
+ private
19
+
20
+ def project_pkgs
21
+ @result.project_pkgs ||= Swift::ProjectPackages.new(
22
+ src_dir: spm_config.pkg_checkouts_dir,
23
+ write_json_to_dir: spm_config.pkg_metadata_dir
24
+ )
25
+ end
26
+
27
+ def resolve_recursive_targets
28
+ @result.spm_dependencies_by_target.values.flatten.uniq(&:product).each do |dep|
29
+ next if dep.pkg.use_default_xcode_linking?
30
+
31
+ project_pkgs.resolve_recursive_targets_of(dep.pkg.name, dep.product)
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -2,48 +2,52 @@ module Pod
2
2
  module SPM
3
3
  class Resolver
4
4
  class Result
5
+ include Config::Mixin
6
+
7
+ ATTRS = {
8
+ :spm_pkgs => [],
9
+ :spm_dependencies_by_target => {},
10
+ :project_pkgs => nil,
11
+ }.freeze
12
+
5
13
  class WritableResult < Result
6
- attr_accessor :spm_pkgs, :spm_dependencies_by_target, :spm_products, :metadata_cache
14
+ ATTRS.each_key { |x| attr_accessor x }
7
15
 
8
16
  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
- )
17
+ Result.new(ATTRS.to_h { |x| [x, instance_variable_get("@#{x}")] })
15
18
  end
16
19
  end
17
20
 
18
- attr_reader :spm_pkgs, :spm_dependencies_by_target, :spm_products, :metadata_cache
21
+ ATTRS.each_key { |x| attr_reader x }
19
22
 
20
23
  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] || {}
24
+ ATTRS.each do |k, v|
25
+ instance_variable_set("@#{k}", options[k] || v)
26
+ end
25
27
  end
26
28
 
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"
29
+ def spm_pkgs_for(target)
30
+ spm_dependencies_for(target).map(&:pkg).uniq(&:name)
31
31
  end
32
32
 
33
33
  def spm_dependencies_for(target)
34
34
  @spm_dependencies_by_target[target.to_s].to_a
35
35
  end
36
36
 
37
- def spm_products_for(target)
38
- spm_dependencies_for(target).flat_map { |d| @spm_products[d.product].to_a }.uniq(&:name)
37
+ def spm_targets_for(target, exclude_default_xcode_linking: true)
38
+ targets = spm_dependencies_for(target).flat_map do |d|
39
+ project_pkgs.resolve_recursive_targets_of(d.pkg.name, d.product)
40
+ end.uniq(&:name)
41
+ return targets.reject(&:use_default_xcode_linking?) if exclude_default_xcode_linking
42
+
43
+ targets
39
44
  end
40
45
 
41
46
  def linker_flags_for(target)
42
- flags = spm_dependencies_for(target).flat_map { |d| d.pkg.linker_flags }
43
- flags += spm_products_for(target).map do |p|
44
- p.linked_as_framework? ? "-framework \"#{p.name}\"" : "-l\"#{p.name}.o\""
45
- end
46
- flags.uniq
47
+ (
48
+ spm_targets_for(target).flat_map(&:linker_flags) +
49
+ spm_pkgs_for(target).flat_map(&:linker_flags)
50
+ ).uniq
47
51
  end
48
52
  end
49
53
  end
@@ -6,20 +6,22 @@ module Pod
6
6
  class Resolver
7
7
  require "cocoapods-spm/resolver/result"
8
8
  require "cocoapods-spm/resolver/target_dep_resolver"
9
- require "cocoapods-spm/resolver/product_dep_resolver"
9
+ require "cocoapods-spm/resolver/recursive_target_resolver"
10
10
 
11
11
  def initialize(podfile, aggregate_targets)
12
12
  @_result = Result::WritableResult.new
13
13
  @podfile = podfile
14
14
  @aggregate_targets = aggregate_targets
15
15
  @umbrella_pkg = nil
16
- @target_dep_resolver = TargetDependencyResolver.new(podfile, aggregate_targets, @_result)
17
- @product_dep_resolver = ProductDependencyResolver.new(podfile, @_result)
16
+ @resolvers = [
17
+ TargetDependencyResolver.new(podfile, aggregate_targets, @_result),
18
+ RecursiveTargetResolver.new(podfile, @_result),
19
+ ]
18
20
  end
19
21
 
20
22
  def resolve
21
23
  generate_umbrella_pkg
22
- resolvers.each(&:resolve)
24
+ @resolvers.each(&:resolve)
23
25
  validate!
24
26
  end
25
27
 
@@ -29,10 +31,6 @@ module Pod
29
31
 
30
32
  private
31
33
 
32
- def resolvers
33
- [@target_dep_resolver, @product_dep_resolver]
34
- end
35
-
36
34
  def generate_umbrella_pkg
37
35
  @umbrella_pkg = Pod::SPM::UmbrellaPackage.new(@podfile).prepare
38
36
  end
@@ -0,0 +1,54 @@
1
+ require "json"
2
+
3
+ module Pod
4
+ module Swift
5
+ class PackageDescriptionBaseObject
6
+ attr_reader :raw, :parent
7
+
8
+ def initialize(raw, parent: nil)
9
+ @raw = raw
10
+ @parent = parent
11
+ end
12
+
13
+ def root
14
+ @root ||= begin
15
+ node = self
16
+ node = node.parent until node.parent.nil?
17
+ node
18
+ end
19
+ end
20
+
21
+ def pkg_name
22
+ root.name
23
+ end
24
+
25
+ def self.from_s(str)
26
+ new(JSON.parse(str))
27
+ end
28
+
29
+ def self.from_file(path)
30
+ from_s(File.read(path))
31
+ end
32
+
33
+ def inspect
34
+ "#<#{self.class} #{name}>"
35
+ end
36
+
37
+ alias to_s inspect
38
+
39
+ def [](key)
40
+ raw[key]
41
+ end
42
+
43
+ def name
44
+ raw["name"]
45
+ end
46
+
47
+ def dup_with_attrs(options = {})
48
+ copy = dup
49
+ options.each { |key, value| copy.instance_variable_set("@#{key}", value) }
50
+ copy
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,56 @@
1
+ require "cocoapods-spm/swift/package/base"
2
+
3
+ module Pod
4
+ module Swift
5
+ class PackageDescription < PackageDescriptionBaseObject
6
+ include SPM::Config::Mixin
7
+ autoload :Target, "cocoapods-spm/swift/package/target"
8
+ autoload :Product, "cocoapods-spm/swift/package/product"
9
+
10
+ def src_dir
11
+ @src_dir ||= begin
12
+ path = raw.fetch("packageKind", {}).fetch("root", [])[0]
13
+ Pathname.new(path) unless path.nil?
14
+ end
15
+ end
16
+
17
+ def artifacts_dir
18
+ spm_config.pkg_artifacts_dir / slug
19
+ end
20
+
21
+ def slug
22
+ src_dir.nil? ? name : src_dir.basename.to_s
23
+ end
24
+
25
+ def targets
26
+ @targets ||= raw.fetch("targets", []).flat_map { |h| Target.new(h, parent: self) }
27
+ end
28
+
29
+ def products
30
+ @products ||= raw.fetch("products", []).flat_map { |h| Product.new(h, parent: nil) }
31
+ end
32
+
33
+ def targets_of_product(name)
34
+ matched_products = products.select { |p| p.name == name }
35
+ dynamic = matched_products.any?(&:dynamic?)
36
+ matched_products
37
+ .flat_map do |p|
38
+ targets.select { |t| p.target_names.include?(t.name) }.map do |t|
39
+ t.dup_with_attrs(dynamic: dynamic, product_name: name)
40
+ end
41
+ end
42
+ end
43
+
44
+ def macro_impl_name
45
+ targets.find(&:macro?)&.name
46
+ end
47
+
48
+ def use_default_xcode_linking?
49
+ return @use_default_xcode_linking unless @use_default_xcode_linking.nil?
50
+
51
+ pkg = pod_config.podfile.spm_pkgs.find { |t| t.name == name }
52
+ @use_default_xcode_linking = pkg&.use_default_xcode_linking?
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ require "cocoapods-spm/swift/package/base"
2
+
3
+ module Pod
4
+ module Swift
5
+ class PackageDescription
6
+ class Product < PackageDescriptionBaseObject
7
+ def dynamic?
8
+ @dynamic ||= raw.fetch("type", {}).fetch("library", []).include?("dynamic")
9
+ end
10
+
11
+ def target_names
12
+ raw["targets"]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ require "cocoapods-spm/swift/package/description"
2
+
3
+ module Pod
4
+ module Swift
5
+ class ProjectPackages
6
+ def initialize(options = {})
7
+ @src_dir = options[:src_dir]
8
+ raise Informative, "src_dir must not be nil" if @src_dir.nil?
9
+
10
+ @json_dir = options[:write_json_to_dir]
11
+ @pkg_desc_cache = {}
12
+ load
13
+ end
14
+
15
+ def resolve_recursive_targets_of(pkg_name, product_name)
16
+ @recursive_targets_cache ||= {}
17
+ return @recursive_targets_cache[product_name] if @recursive_targets_cache.key(product_name)
18
+
19
+ res = []
20
+ to_visit = pkg_desc_of(pkg_name).targets_of_product(product_name)
21
+ until to_visit.empty?
22
+ target = to_visit.pop
23
+ res << target
24
+ to_visit += target.resolve_dependencies(@pkg_desc_cache)
25
+ end
26
+ @recursive_targets_cache[product_name] = res.uniq(&:name)
27
+ end
28
+
29
+ def pkg_desc_of(name)
30
+ return @pkg_desc_cache[name] if @pkg_desc_cache.key?(name)
31
+
32
+ raise Informative, "Package description of `#{name}` does not exist!"
33
+ end
34
+
35
+ private
36
+
37
+ def load
38
+ @src_dir.glob("*").each do |dir|
39
+ next if dir.glob("Package*.swift").empty?
40
+
41
+ raw = Dir.chdir(dir) { `swift package dump-package` }
42
+ pkg_desc = PackageDescription.from_s(raw)
43
+ write_data = lambda do |name|
44
+ @pkg_desc_cache[name] = pkg_desc
45
+ (@json_dir / "#{name}.json").write(raw) unless @json_dir.nil?
46
+ end
47
+
48
+ pkg_name = pkg_desc.name
49
+ pkg_slug = dir.basename.to_s
50
+ write_data.call(pkg_name)
51
+ write_data.call(pkg_slug) unless pkg_name == pkg_slug
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,17 @@
1
+ require "cocoapods-spm/swift/package/base"
2
+
3
+ module Pod
4
+ module Swift
5
+ class PackageDescription
6
+ class Resources < PackageDescriptionBaseObject
7
+ def name
8
+ "#{pkg_name}_#{parent.name}"
9
+ end
10
+
11
+ def built_resource_path
12
+ "${PODS_CONFIGURATION_BUILD_DIR}/#{name}.bundle"
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,96 @@
1
+ require "cocoapods-spm/swift/package/base"
2
+
3
+ module Pod
4
+ module Swift
5
+ class PackageDescription
6
+ autoload :Resources, "cocoapods-spm/swift/package/resources"
7
+
8
+ class Target < PackageDescriptionBaseObject
9
+ def type
10
+ raw["type"]
11
+ end
12
+
13
+ def macro?
14
+ type == "macro"
15
+ end
16
+
17
+ def binary?
18
+ return @binary unless @binary.nil?
19
+
20
+ @binary = type == "binary"
21
+ end
22
+
23
+ def dynamic?
24
+ @dynamic
25
+ end
26
+
27
+ def framework_name
28
+ @product_name || name
29
+ end
30
+
31
+ def public_headers_path
32
+ raw["publicHeadersPath"]
33
+ end
34
+
35
+ def clang_modulemap_arg
36
+ return nil if public_headers_path.nil?
37
+
38
+ "-fmodule-map-file=\"${GENERATED_MODULEMAP_DIR}/#{name}.modulemap\""
39
+ end
40
+
41
+ def resources
42
+ raw.fetch("resources", []).flat_map { |h| Resources.new(h, parent: self) }
43
+ end
44
+
45
+ def linker_flags
46
+ return ["-framework \"#{framework_name}\""] if dynamic?
47
+ return ["-l\"#{name}.o\""] unless binary?
48
+
49
+ case binary_basename
50
+ when /(\S+)\.framework/ then ["-framework \"#{$1}\""]
51
+ when /lib(\S+)\.a/ then ["-library \"#{$1}\""]
52
+ when /(\S+\.a)/ then ["\"${PODS_CONFIGURATION_BUILD_DIR}/#{$1}\""]
53
+ else []
54
+ end
55
+ end
56
+
57
+ def resolve_dependencies(pkg_desc_cache)
58
+ raw.fetch("dependencies", []).flat_map do |hash|
59
+ type = ["byName", "target", "product"].find { |k| hash.key?(k) }
60
+ if type.nil?
61
+ raise Informative, "Unexpected dependency type. Must be either `byName`, `target`, or `product`."
62
+ end
63
+
64
+ name = hash[type][0]
65
+ pkg_name = hash.key?("product") ? hash["product"][1] : self.pkg_name
66
+ pkg_desc = pkg_desc_cache[pkg_name]
67
+ find_by_target = -> { pkg_desc.targets.select { |t| t.name == name } }
68
+ find_by_product = -> { pkg_desc.targets_of_product(name) }
69
+ next find_by_target.call if hash.key?("target")
70
+ next find_by_product.call if hash.key?("product")
71
+
72
+ # byName, could be either a target or a product
73
+ next find_by_target.call || find_by_product.call
74
+ end
75
+ end
76
+
77
+ def built_framework_path
78
+ "${BUILT_PRODUCTS_DIR}/PackageFrameworks/#{framework_name}.framework"
79
+ end
80
+
81
+ def binary_basename
82
+ return nil unless binary?
83
+
84
+ @binary_basename ||= begin
85
+ paths = (root.artifacts_dir / name).glob("*.xcframework/*/*.{a,framework}")
86
+ paths[0].basename.to_s unless paths.empty?
87
+ end
88
+ end
89
+
90
+ def use_default_xcode_linking?
91
+ root.use_default_xcode_linking?
92
+ end
93
+ end
94
+ end
95
+ end
96
+ 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.3
4
+ version: 0.1.4
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-04-20 00:00:00.000000000 Z
11
+ date: 2024-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: xcodeproj
@@ -46,24 +46,32 @@ files:
46
46
  - lib/cocoapods-spm/def/target_definition.rb
47
47
  - lib/cocoapods-spm/def/xcodeproj.rb
48
48
  - lib/cocoapods-spm/executables.rb
49
+ - lib/cocoapods-spm/helpers/patch.rb
49
50
  - lib/cocoapods-spm/hooks/base.rb
51
+ - lib/cocoapods-spm/hooks/helpers/update_script.rb
50
52
  - lib/cocoapods-spm/hooks/post_integrate/1.add_spm_pkgs.rb
51
53
  - lib/cocoapods-spm/hooks/post_integrate/5.update_settings.rb
52
54
  - lib/cocoapods-spm/hooks/post_integrate/6.update_embed_frameworks_script.rb
55
+ - lib/cocoapods-spm/hooks/post_integrate/7.update_copy_resources_script.rb
53
56
  - lib/cocoapods-spm/macro/fetcher.rb
57
+ - lib/cocoapods-spm/macro/metadata.rb
54
58
  - lib/cocoapods-spm/macro/pod_installer.rb
55
59
  - lib/cocoapods-spm/macro/prebuilder.rb
56
60
  - lib/cocoapods-spm/main.rb
57
- - lib/cocoapods-spm/metadata.rb
58
61
  - lib/cocoapods-spm/patch/aggregate_target.rb
59
62
  - lib/cocoapods-spm/patch/installer.rb
60
63
  - lib/cocoapods-spm/resolver.rb
61
- - lib/cocoapods-spm/resolver/product.rb
62
- - lib/cocoapods-spm/resolver/product_dep_resolver.rb
64
+ - lib/cocoapods-spm/resolver/recursive_target_resolver.rb
63
65
  - lib/cocoapods-spm/resolver/result.rb
64
66
  - lib/cocoapods-spm/resolver/target_dep_resolver.rb
65
67
  - lib/cocoapods-spm/resolver/umbrella_package.rb
66
68
  - lib/cocoapods-spm/resolver/validator.rb
69
+ - lib/cocoapods-spm/swift/package/base.rb
70
+ - lib/cocoapods-spm/swift/package/description.rb
71
+ - lib/cocoapods-spm/swift/package/product.rb
72
+ - lib/cocoapods-spm/swift/package/project_packages.rb
73
+ - lib/cocoapods-spm/swift/package/resources.rb
74
+ - lib/cocoapods-spm/swift/package/target.rb
67
75
  - lib/cocoapods_plugin.rb
68
76
  homepage: https://github.com/trinhngocthuyen/cocoapods-spm
69
77
  licenses:
@@ -1,50 +0,0 @@
1
- require "json"
2
-
3
- module Pod
4
- module SPM
5
- class Metadata
6
- attr_reader :raw
7
-
8
- def initialize(raw)
9
- @raw = raw
10
- end
11
-
12
- def self.from_s(str)
13
- new(JSON.parse(str))
14
- end
15
-
16
- def self.from_file(path)
17
- from_s(File.read(path))
18
- end
19
-
20
- def self.for_pod(name)
21
- from_file(Config.instance.macro_root_dir / name / "metadata.json")
22
- end
23
-
24
- def [](key)
25
- raw[key]
26
- end
27
-
28
- def targets
29
- raw["targets"]
30
- end
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
-
41
- def targets_of_type(type)
42
- targets.select { |t| t["type"] == type }
43
- end
44
-
45
- def macro_impl_name
46
- targets_of_type("macro").first&.fetch("name")
47
- end
48
- end
49
- end
50
- end
@@ -1,31 +0,0 @@
1
- module Pod
2
- module SPM
3
- class Resolver
4
- class Product
5
- attr_reader :pkg, :name, :linkage, :headers_path, :binary
6
-
7
- alias binary? binary
8
-
9
- def initialize(options = {})
10
- @pkg = options[:pkg]
11
- @name = options[:name]
12
- @linkage = options.fetch(:linkage, :static)
13
- @headers_path = options[:headers_path]
14
- @binary = options[:binary]
15
- end
16
-
17
- def inspect
18
- "#<#{self.class} #{pkg}/#{name}>"
19
- end
20
-
21
- def dynamic?
22
- @linkage == :dynamic
23
- end
24
-
25
- def linked_as_framework?
26
- dynamic? || binary?
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,134 +0,0 @@
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_binary_targets
18
- resolve_headers_path_by_target
19
- resolve_product_deps
20
- end
21
-
22
- private
23
-
24
- def generate_metadata
25
- spm_config.pkg_checkouts_dir.glob("*").each do |dir|
26
- next if dir.glob("Package*.swift").empty?
27
-
28
- raw = Dir.chdir(dir) { `swift package dump-package` }
29
- metadata = Metadata.from_s(raw)
30
- write_metadata = lambda do |name|
31
- (spm_config.pkg_metadata_dir / "#{name}.json").write(raw)
32
- @result.metadata_cache[name] = metadata
33
- end
34
-
35
- pkg_name = metadata["name"]
36
- pkg_slug = dir.basename.to_s
37
- write_metadata.call(pkg_name)
38
- write_metadata.call(pkg_slug) unless pkg_name == pkg_slug
39
- end
40
- end
41
-
42
- def resolve_dynamic_products
43
- @dynamic_products ||= Set.new
44
- @result.metadata_cache.each_value do |metadata|
45
- metadata.products.each do |h|
46
- library_types = h.fetch("type", {}).fetch("library", [])
47
- @dynamic_products << h["name"] if library_types.include?("dynamic")
48
- end
49
- end
50
- end
51
-
52
- def resolve_binary_targets
53
- @binary_targets ||= Set.new
54
- @result.metadata_cache.each_value do |metadata|
55
- metadata.targets.each do |h|
56
- @binary_targets << h["name"] if h["type"] == "binary"
57
- end
58
- end
59
- end
60
-
61
- def resolve_headers_path_by_target
62
- @headers_path_by_product ||= {}
63
- @result.metadata_cache.each_value do |metadata|
64
- metadata.targets.each do |h|
65
- next unless h.key?("publicHeadersPath")
66
-
67
- metadata.product_names_of_target(h["name"]).each do |name|
68
- @headers_path_by_product[name] = h["publicHeadersPath"]
69
- end
70
- end
71
- end
72
- end
73
-
74
- def resolve_product_deps
75
- @result.spm_dependencies_by_target.values.flatten.uniq(&:product).each do |dep|
76
- next if dep.pkg.use_default_xcode_linking?
77
-
78
- verify_product_exists_in_pkg(dep.pkg.name, dep.product)
79
- product = create_product(dep.pkg.name, dep.product)
80
- recursive_products_of(product)
81
- end
82
- end
83
-
84
- def verify_product_exists_in_pkg(pkg, name)
85
- return unless @result.metadata_of(pkg).products.find { |h| h["name"] == name }.nil?
86
-
87
- raise Informative, "Package `#{pkg}` does not contain product named `#{name}`"
88
- end
89
-
90
- def recursive_products_of(product)
91
- products = [product] + direct_products_of(product).flat_map do |child|
92
- [child] + recursive_products_of(child)
93
- end.uniq(&:name)
94
- @result.spm_products[product.name] = products
95
- products
96
- end
97
-
98
- def direct_products_of(product)
99
- metadata = @result.metadata_of(product.pkg)
100
- metadata
101
- .products
102
- .find { |h| h["name"] == product.name }
103
- .to_h
104
- .fetch("targets", [product.name])
105
- .flat_map do |t|
106
- metadata
107
- .targets
108
- .find { |h| h["name"] == t }
109
- .fetch("dependencies", [])
110
- .map { |h| product_from_hash(h, metadata) }
111
- end
112
- end
113
-
114
- def product_from_hash(hash, metadata)
115
- type = ["byName", "target", "product"].find { |k| hash.key?(k) }
116
- name = hash[type][0] unless type.nil?
117
- pkg = metadata["name"]
118
- pkg = hash["product"][1] if hash.key?("product")
119
- create_product(pkg, name)
120
- end
121
-
122
- def create_product(pkg, name)
123
- Product.new(
124
- pkg: pkg,
125
- name: name,
126
- linkage: @dynamic_products.include?(name) ? :dynamic : :static,
127
- headers_path: @headers_path_by_product[name],
128
- binary: @binary_targets.include?(name)
129
- )
130
- end
131
- end
132
- end
133
- end
134
- end