cocoapods 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (37) hide show
  1. data/CHANGELOG.md +42 -9
  2. data/bin/pod +4 -0
  3. data/lib/cocoapods.rb +2 -2
  4. data/lib/cocoapods/command.rb +2 -25
  5. data/lib/cocoapods/command/install.rb +1 -2
  6. data/lib/cocoapods/command/linter.rb +24 -4
  7. data/lib/cocoapods/command/list.rb +16 -11
  8. data/lib/cocoapods/command/outdated.rb +2 -4
  9. data/lib/cocoapods/command/push.rb +10 -10
  10. data/lib/cocoapods/command/repo.rb +22 -20
  11. data/lib/cocoapods/command/search.rb +6 -4
  12. data/lib/cocoapods/command/setup.rb +15 -14
  13. data/lib/cocoapods/command/spec.rb +17 -14
  14. data/lib/cocoapods/command/update.rb +9 -1
  15. data/lib/cocoapods/config.rb +12 -4
  16. data/lib/cocoapods/dependency.rb +18 -15
  17. data/lib/cocoapods/downloader/git.rb +41 -28
  18. data/lib/cocoapods/downloader/http.rb +10 -3
  19. data/lib/cocoapods/downloader/mercurial.rb +6 -4
  20. data/lib/cocoapods/downloader/subversion.rb +6 -2
  21. data/lib/cocoapods/executable.rb +6 -6
  22. data/lib/cocoapods/generator/acknowledgements/markdown.rb +1 -0
  23. data/lib/cocoapods/installer.rb +73 -57
  24. data/lib/cocoapods/installer/target_installer.rb +15 -11
  25. data/lib/cocoapods/installer/user_project_integrator.rb +25 -16
  26. data/lib/cocoapods/local_pod.rb +34 -12
  27. data/lib/cocoapods/podfile.rb +15 -0
  28. data/lib/cocoapods/resolver.rb +33 -39
  29. data/lib/cocoapods/source.rb +172 -48
  30. data/lib/cocoapods/specification.rb +48 -32
  31. data/lib/cocoapods/specification/set.rb +102 -34
  32. data/lib/cocoapods/specification/statistics.rb +1 -1
  33. data/lib/cocoapods/user_interface.rb +215 -0
  34. data/lib/cocoapods/user_interface/ui_pod.rb +130 -0
  35. metadata +7 -7
  36. data/lib/cocoapods/command/presenter.rb +0 -61
  37. data/lib/cocoapods/command/presenter/cocoa_pod.rb +0 -118
@@ -12,20 +12,22 @@ module Pod
12
12
  end
13
13
 
14
14
  def self.options
15
- [["--full", "Search by name, summary, and description"]].concat(Presenter.options).concat(super)
15
+ [[
16
+ "--full", "Search by name, summary, and description",
17
+ "--stats", "Show additional stats (like GitHub watchers and forks)"
18
+ ]].concat(super)
16
19
  end
17
20
 
18
21
  def initialize(argv)
19
22
  @full_text_search = argv.option('--full')
20
- @presenter = Presenter.new(argv)
23
+ @stats = argv.option('--stats')
21
24
  @query = argv.shift_argument
22
25
  super unless argv.empty? && @query
23
26
  end
24
27
 
25
28
  def run
26
29
  sets = Source.search_by_name(@query.strip, @full_text_search)
27
- sets.each {|s| puts @presenter.describe(s)}
28
- puts
30
+ sets.each { |set| UI.pod(set, (@stats ? :stats : :normal)) }
29
31
  end
30
32
  end
31
33
  end
@@ -89,21 +89,22 @@ module Pod
89
89
  end
90
90
 
91
91
  def run
92
- print_title "Setting up CocoaPods master repo"
93
- if dir.exist?
94
- set_master_repo_url
95
- set_master_repo_branch
96
- update_master_repo
97
- else
98
- add_master_repo
99
- end
100
- # Mainly so the specs run with submodule repos
101
- if (dir + '.git/hooks').exist?
102
- hook = dir + '.git/hooks/pre-commit'
103
- hook.open('w') { |f| f << "#!/bin/sh\nrake lint" }
104
- `chmod +x '#{hook}'`
92
+ UI.section "Setting up CocoaPods master repo" do
93
+ if dir.exist?
94
+ set_master_repo_url
95
+ set_master_repo_branch
96
+ update_master_repo
97
+ else
98
+ add_master_repo
99
+ end
100
+ # Mainly so the specs run with submodule repos
101
+ if (dir + '.git/hooks').exist?
102
+ hook = dir + '.git/hooks/pre-commit'
103
+ hook.open('w') { |f| f << "#!/bin/sh\nrake lint" }
104
+ `chmod +x '#{hook}'`
105
+ end
105
106
  end
106
- print_subtitle "Setup completed (#{push? ? "push" : "read-only"} access)"
107
+ UI.puts "Setup completed (#{push? ? "push" : "read-only"} access)".green
107
108
  end
108
109
  end
109
110
  end
@@ -20,6 +20,7 @@ module Pod
20
20
 
21
21
  def self.options
22
22
  [ ["--quick", "Lint skips checks that would require to download and build the spec"],
23
+ ["--local", "Lint a podspec against the local files contained in its directory"],
23
24
  ["--only-errors", "Lint validates even if warnings are present"],
24
25
  ["--no-clean", "Lint leaves the build directory intact for inspection"] ].concat(super)
25
26
  end
@@ -32,9 +33,10 @@ module Pod
32
33
  super if @name_or_url.nil?
33
34
  super unless argv.empty?
34
35
  elsif @action == 'lint'
35
- @quick = argv.option('--quick')
36
- @only_errors = argv.option('--only-errors')
37
- @no_clean = argv.option('--no-clean')
36
+ @quick = argv.option('--quick')
37
+ @local = argv.option('--local')
38
+ @only_errors = argv.option('--only-errors')
39
+ @no_clean = argv.option('--no-clean')
38
40
  @podspecs_paths = argv
39
41
  else
40
42
  super
@@ -59,21 +61,22 @@ module Pod
59
61
  repo_id = repo_id_match[1]
60
62
  data = github_data_for_template(repo_id)
61
63
  data[:name] = @name_or_url if @url
62
- puts semantic_versioning_notice(repo_id, data[:name]) if data[:version] == '0.0.1'
64
+ UI.puts semantic_versioning_notice(repo_id, data[:name]) if data[:version] == '0.0.1'
63
65
  else
64
66
  data = default_data_for_template(@name_or_url)
65
67
  end
66
68
  spec = spec_template(data)
67
69
  (Pathname.pwd + "#{data[:name]}.podspec").open('w') { |f| f << spec }
68
- puts "\nSpecification created at #{data[:name]}.podspec".green
70
+ UI.puts "\nSpecification created at #{data[:name]}.podspec".green
69
71
  end
70
72
 
71
73
  def lint
72
- puts
74
+ UI.puts
73
75
  invalid_count = 0
74
76
  podspecs_to_lint.each do |podspec|
75
- linter = Linter.new(podspec)
76
- linter.quick = @quick
77
+ linter = Linter.new(podspec)
78
+ linter.quick = @quick
79
+ linter.local = @local
77
80
  linter.no_clean = @no_clean
78
81
 
79
82
  # Show immediatly which pod is being processed.
@@ -93,19 +96,19 @@ module Pod
93
96
  end
94
97
 
95
98
  # This overwrites the previously printed text
96
- puts " -> ".send(color) << linter.spec_name unless config.silent?
99
+ UI.puts " -> ".send(color) << linter.spec_name unless config.silent?
97
100
  print_messages('ERROR', linter.errors)
98
101
  print_messages('WARN', linter.warnings)
99
102
  print_messages('NOTE', linter.notes)
100
103
 
101
- puts unless config.silent?
104
+ UI.puts unless config.silent?
102
105
  end
103
106
 
104
- puts "Analyzed #{podspecs_to_lint.count} podspecs files.\n\n" unless config.silent?
107
+ UI.puts "Analyzed #{podspecs_to_lint.count} podspecs files.\n\n" unless config.silent?
105
108
  count = podspecs_to_lint.count
106
109
  if invalid_count == 0
107
110
  lint_passed_message = count == 1 ? "#{podspecs_to_lint.first.basename} passed validation." : "All the specs passed validation."
108
- puts lint_passed_message.green << "\n\n" unless config.silent?
111
+ UI.puts lint_passed_message.green << "\n\n" unless config.silent?
109
112
  else
110
113
  raise Informative, count == 1 ? "The spec did not pass validation." : "#{invalid_count} out of #{count} specs failed validation."
111
114
  end
@@ -116,7 +119,7 @@ module Pod
116
119
 
117
120
  def print_messages(type, messages)
118
121
  return if config.silent?
119
- messages.each {|msg| puts " - #{type.ljust(5)} | #{msg}"}
122
+ messages.each {|msg| UI.puts " - #{type.ljust(5)} | #{msg}"}
120
123
  end
121
124
 
122
125
  def podspecs_to_lint
@@ -171,7 +174,7 @@ module Pod
171
174
  data = {}
172
175
 
173
176
  data[:name] = repo['name']
174
- data[:summary] = repo['description'].gsub(/["]/, '\"')
177
+ data[:summary] = (repo['description'] || '').gsub(/["]/, '\"')
175
178
  data[:homepage] = (repo['homepage'] && !repo['homepage'].empty? ) ? repo['homepage'] : repo['html_url']
176
179
  data[:author_name] = user['name'] || user['login']
177
180
  data[:author_email] = user['email'] || 'email@address.com'
@@ -9,10 +9,18 @@ module Pod
9
9
  Updates all dependencies.}
10
10
  end
11
11
 
12
+ def self.options
13
+ [["--no-update", "Skip running `pod repo update` before install"]].concat(super)
14
+ end
15
+
16
+ def initialize(argv)
17
+ config.skip_repo_update = argv.option('--no-update')
18
+ super unless argv.empty?
19
+ end
20
+
12
21
  def run
13
22
  verify_podfile_exists!
14
23
  verify_lockfile_exists!
15
- update_spec_repos_if_necessary!
16
24
  run_install_with_update(true)
17
25
  end
18
26
  end
@@ -14,7 +14,7 @@ module Pod
14
14
  attr_accessor :clean, :verbose, :silent
15
15
  attr_accessor :generate_docs, :doc_install
16
16
  attr_accessor :integrate_targets
17
- attr_accessor :git_cache_size
17
+ attr_accessor :new_version_message, :skip_repo_update
18
18
 
19
19
  alias_method :clean?, :clean
20
20
  alias_method :verbose?, :verbose
@@ -22,11 +22,13 @@ module Pod
22
22
  alias_method :generate_docs?, :generate_docs
23
23
  alias_method :doc_install?, :doc_install
24
24
  alias_method :integrate_targets?, :integrate_targets
25
+ alias_method :skip_repo_update?, :skip_repo_update
26
+ alias_method :new_version_message?, :new_version_message
25
27
 
26
28
  def initialize
27
29
  @repos_dir = Pathname.new(File.expand_path("~/.cocoapods"))
28
- @verbose = @silent = false
29
- @clean = @generate_docs = @doc_install = @integrate_targets = true
30
+ @verbose = @silent = @skip_repo_update = false
31
+ @clean = @generate_docs = @doc_install = @integrate_targets = @new_version_message = true
30
32
  end
31
33
 
32
34
  def project_root
@@ -38,7 +40,13 @@ module Pod
38
40
  end
39
41
 
40
42
  def project_podfile
41
- @project_podfile ||= project_root + 'Podfile'
43
+ unless @project_podfile
44
+ @project_podfile = project_root + 'CocoaPods.podfile'
45
+ unless @project_podfile.exist?
46
+ @project_podfile = project_root + 'Podfile'
47
+ end
48
+ end
49
+ @project_podfile
42
50
  end
43
51
 
44
52
  def project_lockfile
@@ -177,10 +177,10 @@ module Pod
177
177
  output_path = sandbox.root + "Local Podspecs/#{name}.podspec"
178
178
  output_path.dirname.mkpath
179
179
  if podspec.is_a?(String)
180
- raise Informative, "No podspec found for `#{name}' in `#{description}'" unless podspec.include?('Spec.new')
180
+ raise Informative, "No podspec found for `#{name}' in #{description}" unless podspec.include?('Spec.new')
181
181
  output_path.open('w') { |f| f.puts(podspec) }
182
182
  else
183
- raise Informative, "No podspec found for `#{name}' in `#{description}'" unless podspec.exist?
183
+ raise Informative, "No podspec found for `#{name}' in #{description}" unless podspec.exist?
184
184
  FileUtils.copy(podspec, output_path)
185
185
  end
186
186
  end
@@ -193,14 +193,15 @@ module Pod
193
193
 
194
194
  class GitSource < AbstractExternalSource
195
195
  def copy_external_source_into_sandbox(sandbox, platform)
196
- puts "-> Pre-downloading: '#{name}'" unless config.silent?
197
- target = sandbox.root + name
198
- target.rmtree if target.exist?
199
- downloader = Downloader.for_target(sandbox.root + name, @params)
200
- downloader.download
201
- store_podspec(sandbox, target + "#{name}.podspec")
202
- if local_pod = sandbox.installed_pod_named(name, platform)
203
- local_pod.downloaded = true
196
+ UI.info("->".green + " Pre-downloading: '#{name}'") do
197
+ target = sandbox.root + name
198
+ target.rmtree if target.exist?
199
+ downloader = Downloader.for_target(sandbox.root + name, @params)
200
+ downloader.download
201
+ store_podspec(sandbox, target + "#{name}.podspec")
202
+ if local_pod = sandbox.installed_pod_named(name, platform)
203
+ local_pod.downloaded = true
204
+ end
204
205
  end
205
206
  end
206
207
 
@@ -216,10 +217,11 @@ module Pod
216
217
  # can be http, file, etc
217
218
  class PodspecSource < AbstractExternalSource
218
219
  def copy_external_source_into_sandbox(sandbox, _)
219
- puts "-> Fetching podspec for `#{name}' from: #{@params[:podspec]}" unless config.silent?
220
- path = @params[:podspec]
221
- path = Pathname.new(path).expand_path if path.start_with?("~")
222
- open(path) { |io| store_podspec(sandbox, io.read) }
220
+ UI.info("->".green + " Fetching podspec for `#{name}' from: #{@params[:podspec]}") do
221
+ path = @params[:podspec]
222
+ path = Pathname.new(path).expand_path if path.start_with?("~")
223
+ open(path) { |io| store_podspec(sandbox, io.read) }
224
+ end
223
225
  end
224
226
 
225
227
  def description
@@ -229,7 +231,8 @@ module Pod
229
231
 
230
232
  class LocalSource < AbstractExternalSource
231
233
  def pod_spec_path
232
- path = Pathname.new(@params[:local]).expand_path + "#{name}.podspec"
234
+ path = Pathname.new(@params[:local]).expand_path
235
+ path += "#{name}.podspec"# unless path.to_s.include?("#{name}.podspec")
233
236
  raise Informative, "No podspec found for `#{name}' in `#{@params[:local]}'" unless path.exist?
234
237
  path
235
238
  end
@@ -7,33 +7,34 @@ module Pod
7
7
  class Downloader
8
8
  class Git < Downloader
9
9
  include Config::Mixin
10
+
10
11
  executable :git
11
12
 
12
13
  MAX_CACHE_SIZE = 500
13
14
 
14
15
  def download
15
16
  create_cache unless cache_exist?
16
- puts '-> Cloning git repo' if config.verbose?
17
-
18
- if options[:tag]
19
- download_tag
20
- elsif options[:branch]
21
- download_branch
22
- elsif options[:commit]
23
- download_commit
24
- else
25
- download_head
17
+ UI.section(' > Cloning git repo', '', 1) do
18
+ if options[:tag]
19
+ download_tag
20
+ elsif options[:branch]
21
+ download_branch
22
+ elsif options[:commit]
23
+ download_commit
24
+ else
25
+ download_head
26
+ end
27
+ Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
26
28
  end
27
-
28
- Dir.chdir(target_path) { git! "submodule update --init" } if options[:submodules]
29
29
  prune_cache
30
30
  end
31
31
 
32
32
  def create_cache
33
- puts "-> Creating cache git repo (#{cache_path})" if config.verbose?
34
- cache_path.rmtree if cache_path.exist?
35
- cache_path.mkpath
36
- clone(url, cache_path)
33
+ UI.section(" > Creating cache git repo (#{cache_path})",'',1) do
34
+ cache_path.rmtree if cache_path.exist?
35
+ cache_path.mkpath
36
+ git! %Q|clone --mirror "#{url}" "#{cache_path}"|
37
+ end
37
38
  end
38
39
 
39
40
  def prune_cache
@@ -42,7 +43,7 @@ module Pod
42
43
  repos = Pathname.new(caches_dir).children.select { |c| c.directory? }.sort_by(&:ctime)
43
44
  while caches_size >= MAX_CACHE_SIZE && !repos.empty?
44
45
  dir = repos.shift
45
- puts '->'.yellow << " Removing git cache for `#{origin_url(dir)}'" if config.verbose?
46
+ UI.message "#{'->'.yellow} Removing git cache for `#{origin_url(dir)}'"
46
47
  dir.rmtree
47
48
  end
48
49
  end
@@ -74,12 +75,17 @@ module Pod
74
75
  end
75
76
 
76
77
  def update_cache
77
- puts "-> Updating cache git repo (#{cache_path})" if config.verbose?
78
- Dir.chdir(cache_path) do
79
- git! "reset --hard HEAD"
80
- git! "clean -d -x -f"
81
- git! "pull origin master"
82
- git! "fetch --tags"
78
+ UI.section(" > Updating cache git repo (#{cache_path})",'',1) do
79
+ Dir.chdir(cache_path) do
80
+ if git("config core.bare").chomp == "true"
81
+ git! "remote update"
82
+ else
83
+ git! "reset --hard HEAD"
84
+ git! "clean -d -x -f"
85
+ git! "pull origin master"
86
+ git! "fetch --tags"
87
+ end
88
+ end
83
89
  end
84
90
  end
85
91
 
@@ -95,10 +101,15 @@ module Pod
95
101
  raise Informative, "[!] Cache unable to find git reference `#{ref}' for `#{url}'.".red unless ref_exists?(ref)
96
102
  end
97
103
 
104
+ def branch_exists?(branch)
105
+ Dir.chdir(cache_path) { git "branch --all | grep #{branch}$" } # check for remote branch and do suffix matching ($ anchor)
106
+ $? == 0
107
+ end
108
+
98
109
  def ensure_remote_branch_exists(branch)
99
- Dir.chdir(cache_path) { git "branch -r | grep #{branch}$" } # check for remote branch and do suffix matching ($ anchor)
100
- return if $? == 0
101
- raise Informative, "[!] Cache unable to find git reference `#{branch}' for `#{url}' (#{$?}).".red
110
+ return if branch_exists?(branch)
111
+ update_cache
112
+ raise Informative, "[!] Cache unable to find git reference `#{branch}' for `#{url}' (#{$?}).".red unless branch_exists?(branch)
102
113
  end
103
114
 
104
115
  def download_head
@@ -138,12 +149,14 @@ module Pod
138
149
  git! "remote add upstream '#{@url}'" # we need to add the original url, not the cache url
139
150
  git! "fetch -q upstream" # refresh the branches
140
151
  git! "checkout --track -b activated-pod-commit upstream/#{options[:branch]}" # create a new tracking branch
141
- puts "Just downloaded and checked out branch: #{options[:branch]} from upstream #{clone_url}" if config.verbose?
152
+ UI.message("Just downloaded and checked out branch: #{options[:branch]} from upstream #{clone_url}")
142
153
  end
143
154
  end
144
155
 
145
156
  def clone(from, to)
146
- git! %Q|clone "#{from}" "#{to}"|
157
+ UI.section(" > Cloning to Pods folder",'',1) do
158
+ git! %Q|clone "#{from}" "#{to}"|
159
+ end
147
160
  end
148
161
  end
149
162
 
@@ -16,9 +16,10 @@ module Pod
16
16
  def download
17
17
  @filename = filename_with_type type
18
18
  @download_path = target_path + @filename
19
-
20
- download_file @download_path
21
- extract_with_type @download_path, type
19
+ UI.section(' > Downloading from HTTP', '', 3) do
20
+ download_file @download_path
21
+ extract_with_type @download_path, type
22
+ end
22
23
  end
23
24
 
24
25
  def type
@@ -33,6 +34,8 @@ module Pod
33
34
  :tgz
34
35
  elsif url =~ /.tar$/
35
36
  :tar
37
+ elsif url =~ /.(tbz|tar\.bz2)$/
38
+ :tbz
36
39
  else
37
40
  nil
38
41
  end
@@ -46,6 +49,8 @@ module Pod
46
49
  "file.tgz"
47
50
  when :tar
48
51
  "file.tar"
52
+ when :tbz
53
+ "file.tbz"
49
54
  else
50
55
  raise UnsupportedFileTypeError.new "Unsupported file type: #{type}"
51
56
  end
@@ -63,6 +68,8 @@ module Pod
63
68
  tar! "xfz '#{full_filename}' -C '#{target_path}'"
64
69
  when :tar
65
70
  tar! "xf '#{full_filename}' -C '#{target_path}'"
71
+ when :tbz
72
+ tar! "xfj '#{full_filename}' -C '#{target_path}'"
66
73
  else
67
74
  raise UnsupportedFileTypeError.new "Unsupported file type: #{type}"
68
75
  end
@@ -4,10 +4,12 @@ module Pod
4
4
  executable :hg
5
5
 
6
6
  def download
7
- if options[:revision]
8
- download_revision
9
- else
10
- download_head
7
+ UI.section(' > Cloning mercurial repo', '', 3) do
8
+ if options[:revision]
9
+ download_revision
10
+ else
11
+ download_head
12
+ end
11
13
  end
12
14
  end
13
15