class Pod::Command::Package

Public Class Methods

new(argv) click to toggle source
Calls superclass method
# File lib/pod/command/package.rb, line 42
def initialize(argv)
  @embedded = argv.flag?('embedded')
  @library = argv.flag?('library')
  @dynamic = argv.flag?('dynamic')
  @local = argv.flag?('local', false)
  @output_dsym = argv.flag?('output-dsym', true)
  @package_type = if @embedded
                    :static_framework
                  elsif @dynamic
                    :dynamic_framework
                  elsif @library
                    :static_library
                  else
                    :static_framework
                  end
  @force = argv.flag?('force')
  @mangle = argv.flag?('mangle', true)
  @bundle_identifier = argv.option('bundle-identifier', nil)
  @include_deps = argv.flag?('include-deps', false)
  @exclude_deps = argv.flag?('exclude-deps', !@include_deps)
  @auto_fix_conflict = argv.flag?('auto-fix-conflict', true)
  @disable_force_load = argv.flag?('disable-force-load', false)
  @force_enable_module = argv.flag?('force-enable-module', false)
  @name = argv.shift_argument
  @source = argv.shift_argument
  @spec_sources = argv.option('spec-sources', 'https://github.com/CocoaPods/Specs.git').split(',')
  @local_sources = argv.option('local-sources', '').split(',')
  @no_repos = argv.flag?('no-repos', false)
  @repo_update = argv.flag?('repo-update', false)
  @work_dir = argv.option('work-dir', Dir.tmpdir)
  @git_source = argv.option('git-source', nil)
  @xcconfig_path = argv.option('xcconfig-path', nil)
  subspecs = argv.option('subspecs')
  @subspecs = subspecs.split(',') unless subspecs.nil?

  @config = argv.option('configuration', 'Release')

  @source_dir = Dir.pwd
  @is_spec_from_path = false
  @spec = spec_with_path(@name)
  @is_spec_from_path = true if @spec
  @spec ||= spec_with_name(@name)
  
  @source = "{ :git => \"#{@git_source}\", :tag => s.version.to_s }" unless @git_source.nil?

  super
end
options() click to toggle source
# File lib/pod/command/package.rb, line 13
def self.options
  [
    ['--force',     'Overwrite existing files.'],
    ['--no-mangle', 'Do not mangle symbols of depedendant Pods.'],
    ['--embedded',  'Generate embedded frameworks.'],
    ['--library',   'Generate static libraries.'],
    ['--dynamic',   'Generate dynamic framework.'],
    ['--local',     'Use local state rather than published versions.'],
    ['--bundle-identifier', 'Bundle identifier for dynamic framework'],
    ['--exclude-deps', 'Exclude symbols from dependencies. default true'],
    ['--include-deps', 'Include symbols from dependencies. default false'],
    ['--configuration', 'Build the specified configuration (e.g. Debug). Defaults to Release'],
    ['--subspecs', 'Only include the given subspecs'],
    ['--spec-sources=private,https://github.com/CocoaPods/Specs.git', 'The sources to pull dependent ' \
      'pods from (defaults to https://github.com/CocoaPods/Specs.git)'],
    ['--auto-fix-conflict',   'fix cocoapods conflict .a or .framework , default is true'],
    ['--local-sources=./', '相对 podspec 路径,Paths from which to find local podspecs for transitive dependencies. Multiple local-sources must be comma-delimited.' \
      'pods from local'],
    ['--no-repos', '不自动添加 pod repo list 显示出的 source'],
    ['--repo-update', 'update repo'],
    ['--work-dir', 'the dir when build '],
    ['--git-source', 'framework podspec s.source= '],
    ['--output-dsym', 'generate dSYM file'],
    ['--xcconfig-path', 'xcode build xcconfig path'],
    ['--disable-force-load', 'do not add -force_load flag in spec file xcconfig , default is false'],
    ['--force-enable-module', 'force create module map file in framework, default if public headers contains \#{spec.name}.h will create umbrella header and module map'],
  ]
end

Public Instance Methods

recursive_subspecs_dependencies(spec) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 99
def recursive_subspecs_dependencies(spec)

  dependencies = [@spec, *@spec.recursive_subspecs].flat_map do |all_spec|
    all_spec.dependencies.flat_map do |depency|
      depency if ! "#{depency}".include? "#{spec.name}"
    end
  end.compact.uniq
  # puts dependencies

  # dependencies = spec.dependencies || []
  # spec.recursive_subspecs.each do |subspec|
  #   subspec.dependencies.each do |depency|
  #     if ! "#{depency}".include? "#{spec.name}"
  #       dependencies << depency
  #     end
  #   end
  # end
  dependencies
end
run() click to toggle source
# File lib/pod/command/package.rb, line 99
def run
  if @spec.nil?
    help! "Unable to find a podspec with path or name `#{@name}`."
    return
  end

  if !@no_repos
    if @spec_sources.nil?
      @spec_sources = []
    end
    config.sources_manager.all.each do |s|
      @spec_sources << s.url
    end
  end
  
  if @repo_update
    update_sources
  end

  target_dir, work_dir = create_working_directory
  return if target_dir.nil?
  build_package

  `mv "#{work_dir}" "#{target_dir}"`
  Dir.chdir(@source_dir)
end
transitive_local_dependencies(spec, paths) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 119
def transitive_local_dependencies(spec, paths)
  dependencies = recursive_subspecs_dependencies(spec)
  return_list = []
  dependencies.each do |dependency|
    found_podspec_file = nil
    name = dependency.name.split('/')[0]
    paths.each do |path|
      # 展开目录
      if path[0] != '/'
          path = File.expand_path(path, @source_dir)
      end
      podspec_file = path + '/' + name + '.podspec'
      next unless File.file?(podspec_file)
      found_podspec_file = podspec_file
      break
    end
    next unless found_podspec_file
    return_list << [dependency, found_podspec_file]
    dep_spec = Pod::Specification.from_file(found_podspec_file)
    dep_spec.dependencies.each do |d_dep|
      dependencies << d_dep unless dependencies.include? d_dep
    end
  end
  return_list
end
update_sources() click to toggle source
# File lib/pod/command/package.rb, line 126
def update_sources
  UI.title 'Updating specs repos' do
    @spec_sources.each do |source|
      source = config.sources_manager.source_with_name_or_url(source)
      UI.titled_section "Updating spec repo `#{source.name}`" do
        source.update(config.verbose?)
        source.verify_compatibility!
      end
    end
  end
end
validate!() click to toggle source
Calls superclass method
# File lib/pod/command/package.rb, line 90
def validate!
  super
  help! 'A podspec name or path is required.' unless @spec
  help! 'podspec has binary-only depedencies, mangling not possible.' if @mangle && binary_only?(@spec)
  help! '--bundle-identifier option can only be used for dynamic frameworks' if @bundle_identifier && !@dynamic
  help! '--exclude-deps option can only be used for static libraries' if @exclude_deps && @dynamic
  help! '--local option can only be used when a local `.podspec` path is given.' if @local && !@is_spec_from_path
end

Private Instance Methods

binary_only?(spec) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 146
def binary_only?(spec)
  deps = spec.dependencies.map { |dep| spec_with_name(dep.name) }
  [spec, *deps].each do |specification|
    %w(vendored_frameworks vendored_libraries).each do |attrib|
      if !specification.nil? && specification.attributes_hash[attrib]
        return true
      end
    end
  end

  false
end
build_dynamic_sandbox(_static_sandbox, _static_installer) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 193
def build_dynamic_sandbox(_static_sandbox, _static_installer)
  dynamic_sandbox_root = Pathname.new(config.sandbox_root + '/Dynamic')
  dynamic_sandbox = Sandbox.new(dynamic_sandbox_root)

  dynamic_sandbox
end
build_dynamic_target(dynamic_sandbox, static_installer, platform) click to toggle source

@param [Pod::Installer] static_installer

@return [Pod::PodTarget]

# File lib/cocoapods-packager/pod_utils.rb, line 232
def build_dynamic_target(dynamic_sandbox, static_installer, platform)
  spec_targets = static_installer.pod_targets.select do |target|
    target.name == @spec.name
  end
  static_target = spec_targets[0]

  file_accessors = create_file_accessors(static_target, dynamic_sandbox)

  archs = []
  dynamic_target = Pod::PodTarget.new(dynamic_sandbox, true, static_target.user_build_configurations, archs, platform, static_target.specs, static_target.target_definitions, file_accessors)
  dynamic_target
end
build_in_sandbox(platform) click to toggle source
# File lib/pod/command/package.rb, line 140
def build_in_sandbox(platform)
  config.installation_root  = Pathname.new(Dir.pwd)
  config.sandbox_root       = 'Pods'

  static_sandbox = build_static_sandbox(@dynamic)
  static_installer = install_pod(platform.name, static_sandbox)

  if @dynamic
    dynamic_sandbox = build_dynamic_sandbox(static_sandbox, static_installer)
    install_dynamic_pod(dynamic_sandbox, static_sandbox, static_installer, platform)
  end

  begin
    perform_build(platform, static_sandbox, dynamic_sandbox, static_installer)
  ensure # in case the build fails; see Builder#xcodebuild.
    Pathname.new(config.sandbox_root).rmtree
    FileUtils.rm_f('Podfile.lock')
  end
end
build_package() click to toggle source
# File lib/pod/command/package.rb, line 160
def build_package
  builder = SpecBuilder.new(@spec, @source, @embedded, @dynamic, !@disable_force_load)
  newspec = builder.spec_metadata

  @spec.available_platforms.each do |platform|
    build_in_sandbox(platform)

    newspec += builder.spec_platform(platform)
  end

  newspec += builder.spec_close
  File.open(@spec.name + '.podspec', 'w') { |file| file.write(newspec) }
end
build_static_sandbox(dynamic) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 6
def build_static_sandbox(dynamic)
  static_sandbox_root = if dynamic
                          Pathname.new(config.sandbox_root + '/Static')
                        else
                          Pathname.new(config.sandbox_root)
                        end
  Sandbox.new(static_sandbox_root)
end
copy_dynamic_target(static_sandbox, _dynamic_target, dynamic_sandbox) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 268
def copy_dynamic_target(static_sandbox, _dynamic_target, dynamic_sandbox)
  command = "cp -a #{static_sandbox.root}/#{@spec.name} #{dynamic_sandbox.root}"
  `#{command}`
end
create_file_accessors(target, dynamic_sandbox) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 273
def create_file_accessors(target, dynamic_sandbox)
  pod_root = dynamic_sandbox.pod_dir(target.root_spec.name)

  path_list = Sandbox::PathList.new(pod_root)
  target.specs.map do |spec|
    Sandbox::FileAccessor.new(path_list, spec.consumer(target.platform))
  end
end
create_target_directory() click to toggle source
# File lib/pod/command/package.rb, line 174
def create_target_directory
  target_dir = "#{@source_dir}/#{@spec.name}-#{@spec.version}"
  if File.exist? target_dir
    if @force
      Pathname.new(target_dir).rmtree
    else
      UI.puts "Target directory '#{target_dir}' already exists."
      return nil
    end
  end
  target_dir
end
create_working_directory() click to toggle source
# File lib/pod/command/package.rb, line 187
def create_working_directory
  target_dir = create_target_directory
  return if target_dir.nil?
  rootDir = @work_dir
  if rootDir[0] != '/'
    rootDir = File.expand_path(rootDir,@source_dir)
  end
  if rootDir.nil?
    rootDir = Dir.tmpdir
  end
  
  # work_dir = rootDir + '/cocoapods-' + Array.new(8) { rand(36).to_s(36) }.join
  work_dir = rootDir + '/cocoapods-packager-build'
  if File.exist?(work_dir)
    FileUtils.rm_rf(work_dir)
  end
  # Pathname.new(work_dir).mkdir
  FileUtils.mkdir_p(work_dir)
  Dir.chdir(work_dir)

  [target_dir, work_dir]
end
install_dynamic_pod(dynamic_sandbox, static_sandbox, static_installer, platform) click to toggle source

@param [Pod::Sandbox] dynamic_sandbox

@param [Pod::Sandbox] static_sandbox

@param [Pod::Installer] static_installer

@param [Pod::Platform] platform

# File lib/cocoapods-packager/pod_utils.rb, line 208
def install_dynamic_pod(dynamic_sandbox, static_sandbox, static_installer, platform)
  # 1 Create a dynamic target for only the spec pod.
  dynamic_target = build_dynamic_target(dynamic_sandbox, static_installer, platform)

  # 2. Build a new xcodeproj in the dynamic_sandbox with only the spec pod as a target.
  project = prepare_pods_project(dynamic_sandbox, dynamic_target.name, static_installer)

  # 3. Copy the source directory for the dynamic framework from the static sandbox.
  copy_dynamic_target(static_sandbox, dynamic_target, dynamic_sandbox)

  # 4. Create the file references.
  install_file_references(dynamic_sandbox, [dynamic_target], project)

  # 5. Install the target.
  install_library(dynamic_sandbox, dynamic_target, project)

  # 6. Write the actual .xcodeproj to the dynamic sandbox.
  write_pod_project(project, dynamic_sandbox)
end
install_file_references(dynamic_sandbox, pod_targets, pods_project) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 282
def install_file_references(dynamic_sandbox, pod_targets, pods_project)
  installer = Pod::Installer::Xcode::PodsProjectGenerator::FileReferencesInstaller.new(dynamic_sandbox, pod_targets, pods_project)
  installer.install!
end
install_library(dynamic_sandbox, dynamic_target, project) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 287
def install_library(dynamic_sandbox, dynamic_target, project)
  return if dynamic_target.target_definitions.flat_map(&:dependencies).empty?
  target_installer = Pod::Installer::Xcode::PodsProjectGenerator::PodTargetInstaller.new(dynamic_sandbox, project, dynamic_target)
  result = target_installer.install!
  native_target = result.native_target

  # Installs System Frameworks
  if dynamic_target.should_build?
    dynamic_target.file_accessors.each do |file_accessor|
      file_accessor.spec_consumer.frameworks.each do |framework|
        native_target.add_system_framework(framework)
      end
      file_accessor.spec_consumer.libraries.each do |library|
        native_target.add_system_library(library)
      end
    end
  end
end
install_pod(platform_name, sandbox) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 15
def install_pod(platform_name, sandbox)
  podfile = podfile_from_spec(
    @path,
    @spec.name,
    platform_name,
    @spec.deployment_target(platform_name),
    @subspecs,
    @spec_sources,
    @local_sources
  )

  static_installer = TalInstaller.new(sandbox, podfile, @auto_fix_conflict)
  static_installer.install!

  unless static_installer.nil?
    static_installer.pods_project.targets.each do |target|
      target.build_configurations.each do |config|
        config.build_settings['CLANG_MODULES_AUTOLINK'] = 'NO'
        config.build_settings['GCC_GENERATE_DEBUGGING_SYMBOLS'] = 'NO'
      end
    end
    static_installer.pods_project.save
  end

  static_installer
end
perform_build(platform, static_sandbox, dynamic_sandbox, static_installer) click to toggle source
# File lib/pod/command/package.rb, line 210
def perform_build(platform, static_sandbox, dynamic_sandbox, static_installer)
  static_sandbox_root = config.sandbox_root.to_s

  if @dynamic
    static_sandbox_root = "#{static_sandbox_root}/#{static_sandbox.root.to_s.split('/').last}"
    dynamic_sandbox_root = "#{config.sandbox_root}/#{dynamic_sandbox.root.to_s.split('/').last}"
  end

  builder = Pod::Builder.new(
    platform,
    static_installer,
    @source_dir,
    static_sandbox_root,
    dynamic_sandbox_root,
    static_sandbox.public_headers.root,
    @spec,
    @embedded,
    @mangle,
    @dynamic,
    @config,
    @bundle_identifier,
    @exclude_deps,
    @xcconfig_path,
    @force_enable_module
  )

  builder.build(@package_type)

  return unless @embedded
  builder.link_embedded_resources
end
podfile_from_spec(path, spec_name, platform_name, deployment_target, subspecs, sources, local_sources) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 42
def podfile_from_spec(path, spec_name, platform_name, deployment_target, subspecs, sources, local_sources)
  options = {}
  if path
    if @local
      options[:path] = path
    else
      options[:podspec] = path
    end
  end
  options[:subspecs] = subspecs if subspecs
  generator = self
  spec_file = @spec
  source_dir = @source_dir

  Pod::Podfile.new do
    sources.each { |s| source s }
    platform(platform_name, deployment_target)
    # 此处会自动增加非本地依赖项
    pod(spec_name, options)
    # plugin('cocoapods-packager', {})
    # plugin 查看 cocoapods_plugin.rb 文件内定义

    # 增加本地 local  source
    generator.transitive_local_dependencies(spec_file, local_sources).each do |dependency, podspec_file|
      pod_options = {}
      pod_options[:path] = if podspec_file[0] == '/' # absolute path
                              Pathname.new(podspec_file)
                           else
                              expand_path = File.expand_path(podspec_file,source_dir)
                              Pathname.new(expand_path)
                           end
      pod dependency.name, **pod_options
    end

    install!('cocoapods',
             :integrate_targets => false,
             :deterministic_uuids => false)

    target('packager') do
      inherit! :complete
    end

    post_install do |installer|
      #设置build setting
      installer.pods_project.targets.each do |target|
        target.build_configurations.each do |config|
          config.build_settings['CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES'] = 'YES'
          config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -ObjC'
        end
      end
    end
    
  end
end
prepare_pods_project(dynamic_sandbox, spec_name, installer) click to toggle source

@param [Pod::Sandbox] dynamic_sandbox

@param [String] spec_name

@param [Pod::Installer] installer

# File lib/cocoapods-packager/pod_utils.rb, line 251
def prepare_pods_project(dynamic_sandbox, spec_name, installer)
  # Create a new pods project
  pods_project = Pod::Project.new(dynamic_sandbox.project_path)

  # Update build configurations
  installer.analysis_result.all_user_build_configurations.each do |name, type|
    pods_project.add_build_configuration(name, type)
  end

  # Add the pod group for only the dynamic framework
  local = dynamic_sandbox.local?(spec_name)
  path = dynamic_sandbox.pod_dir(spec_name)
  was_absolute = dynamic_sandbox.local_path_was_absolute?(spec_name)
  pods_project.add_pod_group(spec_name, path, local, was_absolute)
  pods_project
end
spec_with_name(name) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 159
def spec_with_name(name)
  return if name.nil?

  set = Pod::Config.instance.sources_manager.search(Dependency.new(name))
  return nil if set.nil?

  set.specification.root
end
spec_with_path(path) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 168
def spec_with_path(path)
  return if path.nil?
  path = Pathname.new(path)
  path = Pathname.new(Dir.pwd).join(path) unless path.absolute?
  return unless path.exist?

  @path = path.expand_path

  if @path.directory?
    help! @path + ': is a directory.'
    return
  end

  unless ['.podspec', '.json'].include? @path.extname
    help! @path + ': is not a podspec.'
    return
  end

  Specification.from_file(@path)
end
write_pod_project(dynamic_project, dynamic_sandbox) click to toggle source
# File lib/cocoapods-packager/pod_utils.rb, line 306
def write_pod_project(dynamic_project, dynamic_sandbox)
  UI.message "- Writing Xcode project file to #{UI.path dynamic_sandbox.project_path}" do
    dynamic_project.pods.remove_from_project if dynamic_project.pods.empty?
    dynamic_project.development_pods.remove_from_project if dynamic_project.development_pods.empty?
    dynamic_project.sort(:groups_position => :below)
    dynamic_project.recreate_user_schemes(false)

    # Edit search paths so that we can find our dependency headers
    dynamic_project.targets.first.build_configuration_list.build_configurations.each do |config|
      config.build_settings['HEADER_SEARCH_PATHS'] = "$(inherited) #{Dir.pwd}/Pods/Static/Headers/**"
      config.build_settings['USER_HEADER_SEARCH_PATHS'] = "$(inherited) #{Dir.pwd}/Pods/Static/Headers/**"
      config.build_settings['OTHER_LDFLAGS'] = '$(inherited) -ObjC'
    end
    dynamic_project.save
  end
end