class Motion::Pods

Constants

PODS_ROOT
PODS_ROOT_MATCHER
PUBLIC_HEADERS_ROOT
SUPPORT_FILES
TARGET_NAME
VERSION

Attributes

podfile[RW]

Public Class Methods

new(config, vendor_options) click to toggle source
# File lib/motion/pods/main.rb, line 35
def initialize(config, vendor_options)
  @config = config
  @vendor_options = vendor_options

  platform =
    case @config.deploy_platform
    when 'MacOSX' then :osx
    when 'iPhoneOS' then :ios
    when 'AppleTVOS' then :tvos
    when 'WatchOS' then :watchos
    else App.fail "Unknown CocoaPods platform: #{@config.deploy_platform}"
    end

  @podfile = Pod::Podfile.new(Pathname.new(Rake.original_dir) + 'Rakefile') {}
  @podfile.platform(platform, config.deployment_target)
  @podfile.target(TARGET_NAME)
  cocoapods_config.podfile = @podfile
  cocoapods_config.skip_repo_update = true
  cocoapods_config.installation_root = Pathname.new(File.expand_path(config.project_dir)) + 'vendor'

  if cocoapods_config.verbose = !!ENV["COCOAPODS_VERBOSE"]
    require 'claide'
  end

  configure_project
end

Public Instance Methods

analyzer() click to toggle source
# File lib/motion/pods/main.rb, line 170
def analyzer
  Pod::Installer::Analyzer.new(
    cocoapods_config.sandbox,
    @podfile,
    cocoapods_config.lockfile
  )
end
cocoapods_config() click to toggle source
# File lib/motion/pods/main.rb, line 166
def cocoapods_config
  Pod::Config.instance
end
configure_project() click to toggle source

Adds the Pods project to the RubyMotion config as a vendored project and

# File lib/motion/pods/main.rb, line 64
def configure_project
  @config.resources_dirs << resources_dir.to_s

  # TODO: replace this all once Xcodeproj has the proper xcconfig parser.
  return unless xcconfig_hash && ldflags
  configure_xcconfig
end
copy_cocoapods_env_and_prefix_headers() click to toggle source
# File lib/motion/pods/main.rb, line 132
def copy_cocoapods_env_and_prefix_headers
  headers = Dir.glob([
    "#{PODS_ROOT}/*.h",
    "#{PODS_ROOT}/*.pch",
    "#{PODS_ROOT}/Target Support Files/**/*.h",
    "#{PODS_ROOT}/Target Support Files/**/*.pch"
  ])

  headers.each do |header|
    src = File.basename(header)
    dst = src.sub(/\.pch$/, ".h")
    dst_path = File.join(PUBLIC_HEADERS_ROOT, "____#{dst}")

    next if File.exist?(dst_path)

    FileUtils.mkdir_p(PUBLIC_HEADERS_ROOT)
    FileUtils.cp(header, dst_path)
  end
end
dependency(*name_and_version_requirements, &block) click to toggle source

Deprecated.

# File lib/motion/pods/main.rb, line 84
def dependency(*name_and_version_requirements, &block)
  @podfile.dependency(*name_and_version_requirements, &block)
end
inspect() click to toggle source

This is the output that gets shown in ‘rake config`, so it should be short and sweet.

# File lib/motion/pods/main.rb, line 158
def inspect
  cocoapods_config
    .lockfile
    .to_hash["PODS"]
    .map { |pod| pod.is_a?(Hash) ? pod.keys.first : pod }
    .inspect
end
install!(update) click to toggle source

Performs a CocoaPods Installation.

For now we only support one Pods target, this will have to be expanded once we work on more spec support.

Let RubyMotion re-generate the BridgeSupport file whenever the list of installed pods changes.

# File lib/motion/pods/main.rb, line 111
def install!(update)
  pods_installer.update = update
  pods_installer.installation_options.integrate_targets = false
  pods_installer.install!
  install_resources
  copy_cocoapods_env_and_prefix_headers
end
install_resource(file, resources_dir) click to toggle source
# File lib/motion/pods/main.rb, line 126
def install_resource(file, resources_dir)
  FileUtils.cp_r(file, resources_dir) if file.exist?
rescue ArgumentError => exc
  raise unless exc.message =~ /same file/
end
install_resources() click to toggle source

TODO: this probably breaks in cases like resource bundles etc, need to test.

# File lib/motion/pods/main.rb, line 120
def install_resources
  FileUtils.rm_rf(resources_dir)
  FileUtils.mkdir_p(resources_dir)
  resources.each { |file| install_resource(file, resources_dir) }
end
pod(*name_and_version_requirements, &block) click to toggle source
# File lib/motion/pods/main.rb, line 79
def pod(*name_and_version_requirements, &block)
  @podfile.pod(*name_and_version_requirements, &block)
end
pods_installer() click to toggle source

Installation

# File lib/motion/pods/main.rb, line 95
def pods_installer
  @installer ||= Pod::Installer.new(
    cocoapods_config.sandbox,
    @podfile,
    cocoapods_config.lockfile
  )
end
pods_xcconfig() click to toggle source
# File lib/motion/pods/main.rb, line 178
def pods_xcconfig
  path =
    Pathname.new(@config.project_dir) +
    SUPPORT_FILES +
    "Pods-#{TARGET_NAME}.release.xcconfig"
  Xcodeproj::Config.new(path) if path.exist?
end
post_install(&block) click to toggle source
# File lib/motion/pods/main.rb, line 88
def post_install(&block)
  @podfile.post_install(&block)
end
resources() click to toggle source

Do not copy ‘.framework` bundles, these should be handled through RM’s ‘embedded_frameworks` config attribute.

# File lib/motion/pods/main.rb, line 195
def resources
  resources = []
  resource_path =
    Pathname.new(@config.project_dir) +
    SUPPORT_FILES +
    "Pods-#{TARGET_NAME}-resources.sh"

  File.open(resource_path) { |f|
    f.each_line do |line|
      matched = line.match(/install_resource\s+(.*)/)

      next unless matched

      path = (matched[1].strip)[1..-2]

      path.sub!("${BUILD_DIR}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}", ".build")

      next if File.extname(path) == ".framework"

      resources << Pathname.new(@config.project_dir) + PODS_ROOT + path
    end
  }
  resources.uniq
end
resources_dir() click to toggle source
# File lib/motion/pods/main.rb, line 220
def resources_dir
  Pathname.new(@config.project_dir) + PODS_ROOT + "Resources"
end
source(source) click to toggle source

DSL

# File lib/motion/pods/main.rb, line 75
def source(source)
  @podfile.source(source)
end
xcconfig_hash() click to toggle source
# File lib/motion/pods/main.rb, line 186
def xcconfig_hash
  return unless pods_xcconfig

  @xcconfig_hash ||= pods_xcconfig.to_hash
end

Private Instance Methods

categorize_libs(lib_search_path_flags) click to toggle source
# File lib/motion/pods/main.rb, line 260
def categorize_libs(lib_search_path_flags)
  pods_libs = []
  libs_to_compile = []

  linked_libraries.each do |library|
    path = parsed_library_path(library, lib_search_path_flags)

    case path
    when String then libs_to_compile << path
    when :pod then pods_libs << library
    end
  end

  [pods_libs.flatten, libs_to_compile]
end
configure_for_iphone(framework_search_paths) click to toggle source
# File lib/motion/pods/main.rb, line 276
def configure_for_iphone(framework_search_paths)
  pods_root = cocoapods_config.installation_root + "Pods"
  # If we would really specify these as ‘frameworks’ then the linker
  # would not link the archive into the application, because it does not
  # see any references to any of the symbols in the archive. Treating it
  # as a static library (which it is) with `-ObjC` fixes this.
  #
  framework_search_paths.each do |framework_search_path|
    frameworks.reject! do |framework|
      path = File.join(framework_search_path, "#{framework}.framework")
      if File.exist?(path)
        @config.libs << "-ObjC '#{File.join(path, framework)}'"
        # This is needed until (and if) CocoaPods links framework
        # headers into `Headers/Public` by default:
        #
        #   https://github.com/CocoaPods/CocoaPods/pull/2722
        #
        header_dir = Pathname.new(path) + "Headers"
        @header_dirs << header_dir.realpath.relative_path_from(pods_root).to_s
        true
      else
        false
      end
    end
  end
end
configure_for_osx(framework_search_paths) click to toggle source
# File lib/motion/pods/main.rb, line 303
def configure_for_osx(framework_search_paths)
  @config.framework_search_paths.concat(framework_search_paths)
  @config.framework_search_paths.uniq!

  framework_search_paths.each do |framework_search_path|
    frameworks.reject! do |framework|
      path = File.join(framework_search_path, "#{framework}.framework")
      if File.exist?(path)
        @config.embedded_frameworks << path
        true
      else
        false
      end
    end
  end
end
configure_xcconfig() click to toggle source
# File lib/motion/pods/main.rb, line 226
def configure_xcconfig
  lib_search_paths, lib_search_path_flags = parse_search_paths_and_flags

  # Get the name of all static libraries that come pre-built with pods
  @pre_built_static_libs =
    lib_search_paths.map { |path| static_libraries_in_path(path) }.flatten

  # Collect the Pod products
  pods_libs, libs_to_compile = categorize_libs(lib_search_path_flags)

  @config.libs.concat(libs_to_compile.compact)
  @config.libs.uniq!

  @header_dirs = ["Headers/Public"]

  case @config.deploy_platform
  when "MacOSX" then configure_for_osx(framework_search_paths)
  when "iPhoneOS" then configure_for_iphone(framework_search_paths)
  end

  @config.frameworks.concat(frameworks)
  @config.frameworks.uniq!

  @config.weak_frameworks.concat(weak_frameworks)
  @config.weak_frameworks.uniq!

  @config.vendor_project(PODS_ROOT, :xcode, {
    :target => "Pods-#{TARGET_NAME}",
    :headers_dir => "{#{@header_dirs.join(',')}}",
    :products => pods_libs.map { |lib_name| "lib#{lib_name}.a" },
    :allow_empty_products => (pods_libs.empty? ? true : false),
  }.merge(@vendor_options))
end
framework_search_paths() click to toggle source
# File lib/motion/pods/main.rb, line 324
def framework_search_paths
  search_paths = xcconfig_hash["FRAMEWORK_SEARCH_PATHS"]

  return [] unless search_paths

  search_paths.strip!

  return [] if search_paths.empty?

  framework_search_paths = []

  search_paths.scan(/"([^"]+)"/) do |search_path|
    path = search_path.first.gsub!(PODS_ROOT_MATCHER, "#{@config.project_dir}/#{PODS_ROOT}")
    framework_search_paths << path if path
  end

  # If we couldn't parse any search paths, then presumably nothing was properly quoted, so
  # fallback to just assuming the whole value is one path.
  if framework_search_paths.empty?
    path = search_paths.gsub!(PODS_ROOT_MATCHER, "#{@config.project_dir}/#{PODS_ROOT}")
    framework_search_paths << path if path
  end

  framework_search_paths
end
frameworks() click to toggle source
# File lib/motion/pods/main.rb, line 320
def frameworks
  ldflags.scan(/-framework\s+"?([^\s"]+)"?/).map { |match| match[0] }
end
ldflags() click to toggle source
# File lib/motion/pods/main.rb, line 350
def ldflags
  xcconfig_hash["OTHER_LDFLAGS"]
end
linked_libraries() click to toggle source
# File lib/motion/pods/main.rb, line 354
def linked_libraries
  ldflags.scan(/-l"?([^\s"]+)"?/)
end
parse_search_paths_and_flags() click to toggle source
# File lib/motion/pods/main.rb, line 358
def parse_search_paths_and_flags
  flags = xcconfig_hash["LIBRARY_SEARCH_PATHS"] || ""

  search_paths = []

  flags = flags.split(/\s/).map do |path|
    next if path =~ /(\$\(inherited\))|(\$\{inherited\})/

    path.gsub!(
      /(\$\(PODS_ROOT\))|(\$\{PODS_ROOT\})/,
      File.join(@config.project_dir, PODS_ROOT)
    )

    search_paths << path.delete('"')

    '-L ' << path
  end

  [search_paths, flags.compact.join(' ')]
end
parsed_library_path(library, lib_search_path_flags) click to toggle source
# File lib/motion/pods/main.rb, line 379
def parsed_library_path(library, lib_search_path_flags)
  lib_name = library[0]

  return unless lib_name

  # For CocoaPods 0.37.x or below. This block is marked as deprecated.
  if lib_name.start_with?('Pods-')
    :pod
  elsif @pre_built_static_libs.include?("lib#{lib_name}.a")
    "#{lib_search_path_flags} -ObjC -l#{lib_name}"
  elsif File.exist?("/usr/lib/lib#{lib_name}.dylib")
    "/usr/lib/lib#{lib_name}.dylib"
  else
    :pod
  end
end
static_libraries_in_path(path) click to toggle source
# File lib/motion/pods/main.rb, line 396
def static_libraries_in_path(path)
  Dir[File.join(path, "**/*.a")].map { |f| File.basename(f) }
end
weak_frameworks() click to toggle source
# File lib/motion/pods/main.rb, line 400
def weak_frameworks
  ldflags.scan(/-weak_framework\s+([^\s]+)/).map { |match| match[0] }
end