class Pod::Command::Jsource::Add

Public Class Methods

new(argv) click to toggle source
Calls superclass method
# File lib/cocoapods-jsource/command/jsource/add.rb, line 20
def initialize(argv)
  @namesString = argv.shift_argument
  @names = @namesString.split(',') unless @namesString.nil?
  @cache_dict = cache_object
  @manager = XcodeManager.new(argv)
  @remote = argv.flag?('remote')
  @index = -1
  super
end
options() click to toggle source
Calls superclass method
# File lib/cocoapods-jsource/command/jsource/add.rb, line 30
def self.options
  [
      ['--remote', 'add components from internet'],
  ].concat(super)
end

Public Instance Methods

component_cache(component_name) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 218
def component_cache(component_name)
  if @cache_dict.has_key? component_name
    component_cache_dict = @cache_dict[component_name]
  end
  component_cache_dict
end
component_info(component_name) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 304
def component_info(component_name)
  return unless File.exist? config.lockfile_path
  version=""
  lockfile = Lockfile.from_file config.lockfile_path
  dependencies = lockfile.internal_data["DEPENDENCIES"]
  subspecs = []
  dependencies.each do |dependency|
    next unless dependency.start_with? component_name
    if !dependency.include? "(="
      UI.puts "podfile中 #{component_name} 可能没有指定版本,需要指定确定的版本才能使用。"
      exit 1
    end
    list = dependency.split(" (")
    name = list[0]
    if name.include? "/"
      name_list = name.split("/")
      subspec = name.gsub(/\//,"")
      name = name_list[0]
    end
    next unless name == component_name
    version = list[-1].split("/")[0].sub(")", "").sub("=", "").sub(" ", "") if version == ""
    subspecs << subspec if subspec
    spec = spec_with_name component_name, version
    spec.default_subspecs.each do |subspec_spec|
      subspecs = subspecs | ["#{component_name}#{subspec_spec}"]
    end
  end
  return version, subspecs
end
create_working_directory(source_path) click to toggle source

创建源码的存放的目录,可能需要root权限

# File lib/cocoapods-jsource/command/jsource/add.rb, line 386
def create_working_directory(source_path)
  # parent = File.dirname(source_path)
  if not source_path.include? "/binary/"
    UI.puts "旧版本的二进制不在支持,请通过keones重新打包"
    exit 1
  end
  parent = source_path.split("/binary/")[0] + "/binary/"
  return unless parent.length > 0
  return if Dir.exist? parent
  UI.puts "检测到没有源码目录,即将创建#{parent}目录"
  `sudo -S mkdir -p #{parent}`
  user = `whoami`.strip
  `sudo -S chown #{user}:staff #{parent}`
end
download_component_to_path(component_name, version, source_path_hash={}) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 78
def download_component_to_path(component_name, version, source_path_hash={})
  source_path_hash.each do |binary_name, source_path|
    if source_path.include?("Pods")
      sandbox_path = source_path.split("Pods")[0] + "Pods"
    else
      sandbox_path = source_path.gsub(/\/#{component_name}$/,"")
    end

    sandbox_component_path = "#{sandbox_path}/#{component_name}"
    binary_path = "#{sandbox_path}/#{binary_name}"
    if File.exist? sandbox_component_path
      UI.puts "using #{binary_name} #{version}"
      UI.puts "\t#{source_path.to_s}"
      FileUtils.copy_entry(sandbox_component_path, binary_path) unless File.exist? binary_path
    else
      UI.puts "downloading #{binary_name} #{version}"
      UI.puts "\t #{source_path.to_s}"
      create_working_directory(sandbox_path)
      FileUtils.mkdir_p [binary_path] unless File.exist? binary_path
      sandbox = Sandbox.new(sandbox_path)
      spec = spec_with_name(component_name, version)
      specs = { :ios => [spec] }
      installer = Installer::PodSourceInstaller.new(sandbox, config.podfile, specs, :can_cache => true)
      installer.install!
      #installer.clean!
      # TODO validtarget
      # 改名
      # 去掉framework
      framework_path = "#{binary_path}/#{component_name}/Framework"
      if File.directory?(framework_path)
        UI.puts "正在清理无用资源:#{framework_path}"
        `rm -rf #{framework_path}`
      end
      if binary_name != component_name and File.exist? sandbox_component_path
        FileUtils.copy_entry(sandbox_component_path, binary_path) unless File.exist? binary_name
      end
    end
  end
end
file_path(source_path, component_name) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 202
def file_path(source_path, component_name)
  tmp_list = source_path.split("#{component_name}/")
  # if tmp_list.length == 4 and tmp_list[1] != "/"
  #   path = "#{tmp_list[0]}#{binary_name}#{tmp_list[1]}#{binary_name}"
  # end
  # if tmp_list.length == 5 and tmp_list[2] == "_binary/"
  #   path = source_paths[0].split(binary_name)[0] + "#{binary_name}/#{binary_name}"
  # end
  if tmp_list.length < 3
    UI.puts "旧版本的不支持,请重新打二级制"
    exit 1
  end
  path = source_path.gsub("#{component_name}/#{tmp_list[-1]}", "")
  path
end
get_file_list(path) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 136
def get_file_list(path)
  list = []
  Dir.entries(path).each do |sub|
    if sub != '.' && sub != '..'
      if File.directory?("#{path}/#{sub}")
        list << "#{path}/#{sub}"
        list = list + get_file_list("#{path}/#{sub}")
      else
        list << "#{path}/#{sub}"
      end
    end
  end
  list
end
have_cached(component_name, version, subspecs) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 44
def have_cached(component_name, version, subspecs)
  return false unless @cache_dict.has_key? component_name
  pod_cache_dict = @cache_dict[component_name]
  return false unless pod_cache_dict.has_key? version
  return false unless pod_cache_dict[version].has_key? :source_paths
  source_path_hash = pod_cache_dict[version][:source_paths]
  return false unless source_path_hash.length > 0
  if subspecs.length > 0
    tem_list = subspecs & (source_path_hash.keys - [component_name])
    return false unless tem_list == subspecs
    subspecs.each do |binary_name|
      return false unless source_path_hash.keys.include? binary_name
      dir_path = source_path_hash[binary_name]
      return false unless File.exist? dir_path
    end
  else
    source_path_hash.each do |binary_name, dir_path|
      return false unless File.exist? dir_path
    end
  end
  return true
end
local_component_to_path(component_name, version, source_paths_hash) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 151
def local_component_to_path(component_name, version, source_paths_hash)
  path = "Pods/#{component_name}"
  # TODO 没有源码状态
  if !File.exist? path
    # copy files to source_paths
    UI.puts "本地目录不存在,请执行pod install/update 或者输入远程仓库地址"
    exit 1
  end
  #file_list = get_file_list path
  source_paths_hash.each do |binary_name, source_path_list|
    if source_path_list.length > 0
      if source_path_list[0].include?("Pods")
        dest_file_path = source_path_list[0].split("Pods")[0] + "Pods/#{binary_name}"
      else
        dest_file_path = file_path(source_path_list[0], component_name)
      end
      UI.puts "copying #{binary_name} to #{dest_file_path}"
    end
    source_path_list.each do |dest_file_path|
      if dest_file_path.include?("/Pods/")
        origin_file = dest_file_path.split("Pods/#{binary_name}")[-1]
        origin_file_path = path + origin_file
      else
        tmp_path = file_path dest_file_path, component_name
        origin_file = dest_file_path.gsub(tmp_path, "")
        origin_file_path = path + "/#{origin_file}"
      end
      if !File.exist? origin_file_path
        UI.warn "本地不存在#{origin_file_path}, 可能使用了虚拟subspec或者本地源码缓存有问题。推荐加上 --remote 参数"
        exit 1
      end
      if File.directory? origin_file_path
        # FileUtils.mkdir_p [dest_file_path], :mode => 0700 unless File.exist? dest_file_path
        create_working_directory dest_file_path
      else
        create_working_directory dest_file_path
        parent_dir = File.dirname dest_file_path
        FileUtils.mkdir_p [parent_dir], :mode => 0700 unless File.exist? parent_dir
        FileUtils.copy origin_file_path, dest_file_path unless File.exist? dest_file_path
        h_origin_file_path = origin_file_path.gsub(/(mm|m|c)$/, "h")
        h_dest_file_path = dest_file_path.gsub(/(mm|m|c)$/, "h")
        parent_dir = File.dirname h_dest_file_path
        create_working_directory parent_dir
        FileUtils.mkdir_p [parent_dir], :mode => 0700 unless File.exist? parent_dir
        FileUtils.copy h_origin_file_path, h_dest_file_path unless File.exist? h_dest_file_path
      end
    end
  end

end
local_have_source_files(component_name) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 118
def local_have_source_files(component_name)
  files = Dir::glob "Pods/#{component_name}/**/*.m"
  if files and files.length > 0
    return true
  end
  return false
end
local_source_paths(component_name, subspecs, source_paths_hash) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 226
def local_source_paths(component_name, subspecs, source_paths_hash)
  local_hash = {}
  source_paths_hash.each do |binary_name, source_paths|
    need_add = false
    if binary_name != component_name
      if subspecs.include? binary_name
        need_add = true
      end
      if subspecs.length == 0
        need_add = true
      end
    else
      need_add = true
    end
    local_hash[binary_name] = source_paths if need_add
  end
  local_hash
end
run() click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 254
def run
  # 在Pods 目录下创建Debug.xcodeproj 文件。
  debug_xcodeproj = @manager.generate_debug_xcodeproj

  # 获取源码,并添加到工程里。
  @names.each do |component_name|
    @index = @index + 1
    version, subspecs = component_info component_name
    if version.length == 0
      UI.puts "#{component_name} 找不到对应的版本信息,不做任何处理"
      next
    end
    source_path_hash = {}
    if have_cached component_name, version, subspecs
      UI.puts "Using #{component_name} #{version} in #{@cache_dict[component_name][version][:source_paths]}"
      source_path_hash = @cache_dict[component_name][version][:source_paths]
    else
      source_paths_hash = source_paths_from_binary(component_name)
      if source_paths_hash.length == 0
        UI.puts "#{component_name} 找不到对应的二进制,不做任何处理"
        next
      end
      source_paths_hash = local_source_paths component_name, subspecs, source_paths_hash
      source_path_hash = unite_source_paths_hash source_paths_hash, component_name
      if @remote
        # 需要把值合并。
        download_component_to_path component_name, version, source_path_hash
      else
        local_component_to_path component_name, version, source_paths_hash
      end

    end

    # add_component_to_debug
    ENV["IS_SOURCE"] = "1"
    spec = spec_with_name component_name, version
    @manager.add_component_to_debug component_name, source_path_hash, debug_xcodeproj, spec
    # add_component_to_cache
    pod_cache_dict = {}
    pod_cache_dict[version] = {"source_paths":source_path_hash, "version":version}
    #if @use_remote
    #  pod_cache_dict[version]["git"] = @gits[@index]
    #end
    @cache_dict[component_name] = pod_cache_dict
    UI.puts "#{component_name} 源码创建成功,目录为 #{source_path_hash.to_s}"
  end
  @manager.add_debug_to_workspace
  dump_to_yaml @cache_dict
end
source_files(component_name) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 126
def source_files(component_name)
  return nil unless local_have_source_files component_name
  souces = []
  Dir::foreach "Pods/#{component_name}" do |path|
    next if path.include? "Frameworks"
    souces << path
  end
  souces
end
source_paths_from_binary(component_name) click to toggle source

根据组件名获取组件的源码调试地址

# File lib/cocoapods-jsource/command/jsource/add.rb, line 335
def source_paths_from_binary(component_name)
  source_path_hash = {}
  component_pod_path = config.sandbox_root + component_name
  binary_path_list = `find #{component_pod_path} -name "#{component_name}*" -type l`.strip.split("\n").sort
  binary_hash = {}
  for path in binary_path_list
    name = path.to_s.strip.split("/")[-1]
    if name.to_s.include? ".a" or not name.to_s.include? "."
      binary_hash[name]=path unless binary_hash.has_key? name
    end
  end
  if binary_hash.length == 0
    UI.puts "#{component_name} 找不到二进制组件或者找不到对应的版本信息,不做任何处理"
    exit 1
  end

  binary_hash.each do |binary_name, binary_path|
    libbinary_file_name = "lib#{component_name}.a"
    at_name_list = []
    if binary_name.to_s.end_with? libbinary_file_name
      # .a 文件
      at_name_list = `dwarfdump -arch x86_64 #{binary_path} | grep 'DW_AT_decl_file'`.strip.split("\n").sort
    else
      # framework 文件
      at_name_list = `dwarfdump -arch x86_64 #{binary_path} | grep 'DW_AT_decl_file'`.strip.split("\n").sort
    end
    #if source_file.length == 0
    #  UI.puts "在#{binary_path} 里没有找到合适的调试信息~"
    #  next
    #end
    source_list = []
    at_name_list.each do |tmp_source_path|
      source_path = tmp_source_path.strip.split("(\"")[-1].split("\")")[0]
      next if source_path.to_s.start_with?("/Applications/Xcode.app/Contents/Developer/Platforms/")
      source_path = tmp_source_path.strip.split("(\"")[-1].split("\")")[0]
      next unless source_path.to_s.include?("/../../")
      source_path = File.expand_path(source_path)
      source_list << source_path if source_path.to_s.length > 0 and not source_list.include?(source_path)
    end
    if source_list.length == 0
      UI.puts "#{component_name} 没有找到调试信息, 可能是早期打的组件。建议这个组件重新生成。"
      exit 1
    else
      source_path_hash[binary_name] = source_list.sort
    end
  end
  source_path_hash
end
spec_with_name(name, version) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 67
def spec_with_name(name, version)
  set = config.sources_manager.search(Dependency.new(name, version))
  if set
    path = set.specification_paths_for_version(Version.new(version)).first
    spec = Specification.from_file(path)
    spec.root
  else
    raise Informative, "Unable to find a specification for `#{name}`"
  end
end
unite_source_paths_hash(source_paths_hash, component_name) click to toggle source
# File lib/cocoapods-jsource/command/jsource/add.rb, line 246
def unite_source_paths_hash(source_paths_hash, component_name)
  source_path_hash = {}
  source_paths_hash.each do |binary_name, source_paths|
    source_path_hash[binary_name] = file_path(source_paths[0], component_name)
  end
  source_path_hash
end
validate!() click to toggle source
Calls superclass method
# File lib/cocoapods-jsource/command/jsource/add.rb, line 36
def validate!
  super
  help! 'component name is required.' if @namesString.nil?
  #help! 'component git url is required.' unless @gits.length > 0
  #help! 'names number must be equal to gits number' unless @names.length == @gits.length
  help! 'podfile.lock file is required. you need pod install/update' unless File.exist? config.lockfile_path
end