cocoapods-spm 0.1.3 → 0.1.4

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: 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