Class: Pod::Command::Jsource::Add

Inherits:
Pod::Command::Jsource show all
Defined in:
lib/cocoapods-jsource/command/jsource/add.rb

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(argv) ⇒ Add

Returns a new instance of Add.



20
21
22
23
24
25
26
27
28
# 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

Class Method Details

.optionsObject



30
31
32
33
34
# File 'lib/cocoapods-jsource/command/jsource/add.rb', line 30

def self.options
  [
      ['--remote', 'add components from internet'],
  ].concat(super)
end

Instance Method Details

#component_cache(component_name) ⇒ Object



218
219
220
221
222
223
# 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) ⇒ Object



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# 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) ⇒ Object

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



386
387
388
389
390
391
392
393
394
395
396
397
398
399
# 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 = {}) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# 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) ⇒ Object



202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
# 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) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
149
# 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) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# 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) ⇒ Object



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# 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) ⇒ Object



118
119
120
121
122
123
124
# 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) ⇒ Object



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# 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

#runObject



254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
# 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) ⇒ Object



126
127
128
129
130
131
132
133
134
# 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) ⇒ Object

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



335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
# 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) ⇒ Object



67
68
69
70
71
72
73
74
75
76
# 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) ⇒ Object



246
247
248
249
250
251
252
# 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!Object



36
37
38
39
40
41
42
# 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