cocoapods 0.16.4 → 0.17.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +108 -0
  3. data/README.md +3 -3
  4. data/bin/pod +1 -1
  5. data/lib/cocoapods.rb +31 -31
  6. data/lib/cocoapods/command.rb +62 -107
  7. data/lib/cocoapods/command/inter_process_communication.rb +103 -0
  8. data/lib/cocoapods/command/list.rb +45 -44
  9. data/lib/cocoapods/command/outdated.rb +28 -25
  10. data/lib/cocoapods/command/project.rb +90 -0
  11. data/lib/cocoapods/command/push.rb +50 -32
  12. data/lib/cocoapods/command/repo.rb +125 -155
  13. data/lib/cocoapods/command/search.rb +23 -12
  14. data/lib/cocoapods/command/setup.rb +103 -64
  15. data/lib/cocoapods/command/spec.rb +329 -90
  16. data/lib/cocoapods/config.rb +197 -44
  17. data/lib/cocoapods/downloader.rb +47 -34
  18. data/lib/cocoapods/executable.rb +98 -41
  19. data/lib/cocoapods/external_sources.rb +325 -0
  20. data/lib/cocoapods/file_list.rb +8 -1
  21. data/lib/cocoapods/gem_version.rb +7 -0
  22. data/lib/cocoapods/generator/acknowledgements.rb +71 -7
  23. data/lib/cocoapods/generator/acknowledgements/markdown.rb +10 -9
  24. data/lib/cocoapods/generator/acknowledgements/plist.rb +9 -8
  25. data/lib/cocoapods/generator/copy_resources_script.rb +2 -2
  26. data/lib/cocoapods/generator/documentation.rb +153 -37
  27. data/lib/cocoapods/generator/prefix_header.rb +82 -0
  28. data/lib/cocoapods/generator/target_header.rb +58 -0
  29. data/lib/cocoapods/generator/xcconfig.rb +130 -0
  30. data/lib/cocoapods/hooks/installer_representation.rb +123 -0
  31. data/lib/cocoapods/hooks/library_representation.rb +79 -0
  32. data/lib/cocoapods/hooks/pod_representation.rb +74 -0
  33. data/lib/cocoapods/installer.rb +398 -147
  34. data/lib/cocoapods/installer/analyzer.rb +556 -0
  35. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +253 -0
  36. data/lib/cocoapods/installer/file_references_installer.rb +179 -0
  37. data/lib/cocoapods/installer/pod_source_installer.rb +289 -0
  38. data/lib/cocoapods/installer/target_installer.rb +307 -112
  39. data/lib/cocoapods/installer/user_project_integrator.rb +140 -176
  40. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +193 -0
  41. data/lib/cocoapods/library.rb +195 -0
  42. data/lib/cocoapods/open_uri.rb +16 -14
  43. data/lib/cocoapods/project.rb +175 -52
  44. data/lib/cocoapods/resolver.rb +151 -164
  45. data/lib/cocoapods/sandbox.rb +276 -54
  46. data/lib/cocoapods/sandbox/file_accessor.rb +210 -0
  47. data/lib/cocoapods/sandbox/headers_store.rb +96 -0
  48. data/lib/cocoapods/sandbox/path_list.rb +178 -0
  49. data/lib/cocoapods/sources_manager.rb +218 -0
  50. data/lib/cocoapods/user_interface.rb +82 -18
  51. data/lib/cocoapods/{command → user_interface}/error_report.rb +5 -5
  52. data/lib/cocoapods/validator.rb +379 -0
  53. metadata +74 -55
  54. data/lib/cocoapods/command/install.rb +0 -55
  55. data/lib/cocoapods/command/linter.rb +0 -317
  56. data/lib/cocoapods/command/update.rb +0 -25
  57. data/lib/cocoapods/dependency.rb +0 -285
  58. data/lib/cocoapods/downloader/git.rb +0 -276
  59. data/lib/cocoapods/downloader/http.rb +0 -99
  60. data/lib/cocoapods/downloader/mercurial.rb +0 -26
  61. data/lib/cocoapods/downloader/subversion.rb +0 -42
  62. data/lib/cocoapods/local_pod.rb +0 -620
  63. data/lib/cocoapods/lockfile.rb +0 -274
  64. data/lib/cocoapods/platform.rb +0 -127
  65. data/lib/cocoapods/podfile.rb +0 -551
  66. data/lib/cocoapods/source.rb +0 -223
  67. data/lib/cocoapods/specification.rb +0 -579
  68. data/lib/cocoapods/specification/set.rb +0 -175
  69. data/lib/cocoapods/specification/statistics.rb +0 -112
  70. data/lib/cocoapods/user_interface/ui_pod.rb +0 -130
  71. data/lib/cocoapods/version.rb +0 -26
@@ -1,15 +1,15 @@
1
1
  module Pod
2
2
  class Command
3
3
  class Search < Command
4
- def self.banner
5
- %{Search pods:
4
+ self.summary = 'Search pods'
6
5
 
7
- $ pod search [QUERY]
6
+ self.description = <<-DESC
7
+ Searches for pods, ignoring case, whose name matches `QUERY'. If the
8
+ `--full' option is specified, this will also search in the summary and
9
+ description of the pods.
10
+ DESC
8
11
 
9
- Searches for pods, ignoring case, whose name matches `QUERY'. If the
10
- `--full' option is specified, this will also search in the summary and
11
- description of the pods.}
12
- end
12
+ self.arguments = '[QUERY]'
13
13
 
14
14
  def self.options
15
15
  [[
@@ -19,15 +19,26 @@ module Pod
19
19
  end
20
20
 
21
21
  def initialize(argv)
22
- @full_text_search = argv.option('--full')
23
- @stats = argv.option('--stats')
22
+ @full_text_search = argv.flag?('full')
23
+ @stats = argv.flag?('stats')
24
24
  @query = argv.shift_argument
25
- super unless argv.empty? && @query
25
+ super
26
+ end
27
+
28
+ def validate!
29
+ super
30
+ help! "A search query is required." unless @query
26
31
  end
27
32
 
28
33
  def run
29
- sets = Source.search_by_name(@query.strip, @full_text_search)
30
- sets.each { |set| UI.pod(set, (@stats ? :stats : :normal)) }
34
+ sets = SourcesManager.search_by_name(@query.strip, @full_text_search)
35
+ sets.each do |set|
36
+ begin
37
+ UI.pod(set, (@stats ? :stats : :normal))
38
+ rescue DSLError => e
39
+ UI.warn "Skipping `#{set.name}` because the podspec contains errors."
40
+ end
41
+ end
31
42
  end
32
43
  end
33
44
  end
@@ -1,18 +1,16 @@
1
1
  module Pod
2
2
  class Command
3
3
  class Setup < Command
4
- def self.banner
5
- %{Setup CocoaPods environment:
4
+ self.summary = 'Setup the CocoaPods environment'
6
5
 
7
- $ pod setup
6
+ self.description = <<-DESC
7
+ Creates a directory at `~/.cocoapods` which will hold your spec-repos.
8
+ This is where it will create a clone of the public `master` spec-repo from:
8
9
 
9
- Creates a directory at `~/.cocoapods' which will hold your spec-repos.
10
- This is where it will create a clone of the public `master' spec-repo from:
10
+ https://github.com/CocoaPods/Specs
11
11
 
12
- https://github.com/CocoaPods/Specs
13
-
14
- If the clone already exists, it will ensure that it is up-to-date.}
15
- end
12
+ If the clone already exists, it will ensure that it is up-to-date.
13
+ DESC
16
14
 
17
15
  def self.options
18
16
  [["--push", "Use this option to enable push access once granted"]].concat(super)
@@ -22,89 +20,130 @@ module Pod
22
20
  executable :git
23
21
 
24
22
  def initialize(argv)
25
- @push_option = argv.option('--push')
26
- super unless argv.empty?
23
+ @push_option = argv.flag?('push')
24
+ super
27
25
  end
28
26
 
29
- def dir
30
- config.repos_dir + 'master'
31
- end
27
+ def run
28
+ UI.section "Setting up CocoaPods master repo" do
29
+ if master_repo_dir.exist?
30
+ set_master_repo_url
31
+ set_master_repo_branch
32
+ update_master_repo
33
+ else
34
+ add_master_repo
35
+ end
36
+ enable_pre_commit_hooks
37
+ end
32
38
 
33
- def read_only_url
34
- 'https://github.com/CocoaPods/Specs.git'
39
+ access_type = push? ? "push" : "read-only"
40
+ UI.puts "Setup completed (#{access_type} access)".green
35
41
  end
36
42
 
37
- def read_write_url
38
- 'git@github.com:CocoaPods/Specs.git'
39
- end
43
+ #--------------------------------------#
40
44
 
41
- def url
42
- if push?
43
- read_write_url
44
- else
45
- read_only_url
46
- end
47
- end
45
+ # @!group Setup steps
48
46
 
49
- def origin_url_read_only?
50
- read_master_repo_url.chomp == read_only_url
47
+ # Sets the url of the master repo according to whether it is push.
48
+ #
49
+ # @return [void]
50
+ #
51
+ def set_master_repo_url
52
+ Dir.chdir(master_repo_dir) do
53
+ git("remote set-url origin '#{url}'")
54
+ end
51
55
  end
52
56
 
53
- def origin_url_push?
54
- read_master_repo_url.chomp == read_write_url
57
+ # Adds the master repo from the remote.
58
+ #
59
+ # @return [void]
60
+ #
61
+ def add_master_repo
62
+ @command ||= Repo::Add.parse(['master', url, 'master']).run
55
63
  end
56
64
 
57
- def push?
58
- @push_option || (dir.exist? && origin_url_push?)
65
+ # Updates the master repo against the remote.
66
+ #
67
+ # @return [void]
68
+ #
69
+ def update_master_repo
70
+ SourcesManager.update('master', true)
59
71
  end
60
72
 
61
- def read_master_repo_url
62
- Dir.chdir(dir) do
63
- origin_url = git('config --get remote.origin.url')
73
+ # Sets the repo to the master branch.
74
+ #
75
+ # @note This is not needed anymore as it was used for CocoaPods 0.6
76
+ # release candidates.
77
+ #
78
+ # @return [void]
79
+ #
80
+ def set_master_repo_branch
81
+ Dir.chdir(master_repo_dir) do
82
+ git("checkout master")
64
83
  end
65
84
  end
66
85
 
67
- def set_master_repo_url
68
- Dir.chdir(dir) do
69
- git("remote set-url origin '#{url}'")
86
+ # Enables the pre-commit hook of the master repo.
87
+ #
88
+ # @note The hook is enabled in this way because the specs run with the
89
+ # master repo as a submodule.
90
+ #
91
+ # @return [void]
92
+ #
93
+ def enable_pre_commit_hooks
94
+ if (master_repo_dir + '.git/hooks').exist?
95
+ hook = master_repo_dir + '.git/hooks/pre-commit'
96
+ hook.open('w') { |f| f << "#!/bin/sh\nrake lint" }
97
+ `chmod +x '#{hook}'`
70
98
  end
71
99
  end
72
100
 
73
- def add_master_repo
74
- @command ||= Repo.new(ARGV.new(['add', 'master', url, 'master'])).run
101
+ #--------------------------------------#
102
+
103
+ # @!group Private helpers
104
+
105
+ # @return [String] the url to use according to whether push mode should
106
+ # be enabled.
107
+ #
108
+ def url
109
+ url = (push?) ? read_write_url : read_only_url
75
110
  end
76
111
 
77
- def update_master_repo
78
- Repo.new(ARGV.new(['update', 'master'])).run
112
+ # @return [String] the read only url of the master repo.
113
+ #
114
+ def read_only_url
115
+ 'https://github.com/CocoaPods/Specs.git'
79
116
  end
80
117
 
81
- def set_master_repo_branch
82
- Dir.chdir(dir) do
83
- git("checkout master")
84
- end
118
+ # @return [String] the read-write url of the master repo.
119
+ #
120
+ def read_write_url
121
+ 'git@github.com:CocoaPods/Specs.git'
85
122
  end
86
123
 
87
- def run_if_needed
88
- run unless dir.exist? && Repo.compatible?('master')
124
+ # Checks if the user asked to setup the master repo in push mode or if
125
+ # the repo was already in push mode.
126
+ #
127
+ # @return [String] whether the master repo should be set up in push mode.
128
+ #
129
+ def push?
130
+ @push ||= (@push_option || master_repo_is_push?)
89
131
  end
90
132
 
91
- def run
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
133
+ # @return [Bool] if the master repo is already configured in push mode.
134
+ #
135
+ def master_repo_is_push?
136
+ return false unless master_repo_dir.exist?
137
+ Dir.chdir(master_repo_dir) do
138
+ url = git('config --get remote.origin.url')
139
+ url.chomp == read_write_url
106
140
  end
107
- UI.puts "Setup completed (#{push? ? "push" : "read-only"} access)".green
141
+ end
142
+
143
+ # @return [Pathname] the directory of the master repo.
144
+ #
145
+ def master_repo_dir
146
+ SourcesManager.master_repo_dir
108
147
  end
109
148
  end
110
149
  end
@@ -5,123 +5,356 @@ require 'active_support/core_ext/string/inflections'
5
5
  module Pod
6
6
  class Command
7
7
  class Spec < Command
8
- def self.banner
9
- %{Managing PodSpec files:
8
+ self.abstract_command = true
9
+ self.summary = 'Manage pod specs'
10
10
 
11
- $ pod spec create [ NAME | https://github.com/USER/REPO ]
11
+ #-----------------------------------------------------------------------#
12
12
 
13
- Creates a PodSpec, in the current working dir, called `NAME.podspec'.
14
- If a GitHub url is passed the spec is prepopulated.
13
+ class Create < Spec
14
+ self.summary = 'Create spec file stub.'
15
15
 
16
- $ pod spec lint [ NAME.podspec | DIRECTORY | http://PATH/NAME.podspec, ... ]
16
+ self.description = <<-DESC
17
+ Creates a PodSpec, in the current working dir, called `NAME.podspec'.
18
+ If a GitHub url is passed the spec is prepopulated.
19
+ DESC
17
20
 
18
- Validates `NAME.podspec'. If a directory is provided it validates
19
- the podspec files found, including subfolders. In case
20
- the argument is omitted, it defaults to the current working dir.}
21
- end
21
+ self.arguments = '[ NAME | https://github.com/USER/REPO ]'
22
+
23
+ def initialize(argv)
24
+ @name_or_url, @url = argv.shift_argument, argv.shift_argument
25
+ super
26
+ end
27
+
28
+ def validate!
29
+ super
30
+ help! "A pod name or repo URL is required." unless @name_or_url
31
+ end
22
32
 
23
- def self.options
24
- [ ["--quick", "Lint skips checks that would require to download and build the spec"],
25
- ["--local", "Lint a podspec against the local files contained in its directory"],
26
- ["--only-errors", "Lint validates even if warnings are present"],
27
- ["--no-clean", "Lint leaves the build directory intact for inspection"] ].concat(super)
33
+ def run
34
+ if repo_id_match = (@url || @name_or_url).match(/github.com\/([^\/\.]*\/[^\/\.]*)\.*/)
35
+ # This is to make sure Faraday doesn't warn the user about the `system_timer` gem missing.
36
+ old_warn, $-w = $-w, nil
37
+ begin
38
+ require 'faraday'
39
+ ensure
40
+ $-w = old_warn
41
+ end
42
+ require 'octokit'
43
+
44
+ repo_id = repo_id_match[1]
45
+ data = github_data_for_template(repo_id)
46
+ data[:name] = @name_or_url if @url
47
+ UI.puts semantic_versioning_notice(repo_id, data[:name]) if data[:version] == '0.0.1'
48
+ else
49
+ data = default_data_for_template(@name_or_url)
50
+ end
51
+ spec = spec_template(data)
52
+ (Pathname.pwd + "#{data[:name]}.podspec").open('w') { |f| f << spec }
53
+ UI.puts "\nSpecification created at #{data[:name]}.podspec".green
54
+ end
28
55
  end
29
56
 
30
- def initialize(argv)
31
- @action = argv.shift_argument
32
- if @action == 'create'
33
- @name_or_url = argv.shift_argument
34
- @url = argv.shift_argument
35
- super if @name_or_url.nil?
36
- super unless argv.empty?
37
- elsif @action == 'lint'
38
- @quick = argv.option('--quick')
39
- @local = argv.option('--local')
40
- @only_errors = argv.option('--only-errors')
41
- @no_clean = argv.option('--no-clean')
42
- @podspecs_paths = argv
43
- else
57
+ #-----------------------------------------------------------------------#
58
+
59
+ class Lint < Spec
60
+ self.summary = 'Validates a spec file.'
61
+
62
+ self.description = <<-DESC
63
+ Validates `NAME.podspec'. If a directory is provided it validates
64
+ the podspec files found, including subfolders. In case
65
+ the argument is omitted, it defaults to the current working dir.
66
+ DESC
67
+
68
+ self.arguments = '[ NAME.podspec | DIRECTORY | http://PATH/NAME.podspec, ... ]'
69
+
70
+ def self.options
71
+ [ ["--quick", "Lint skips checks that would require to download and build the spec"],
72
+ ["--local", "Lint a podspec against the local files contained in its directory"],
73
+ ["--only-errors", "Lint validates even if warnings are present"],
74
+ ["--no-clean", "Lint leaves the build directory intact for inspection"] ].concat(super)
75
+ end
76
+
77
+ def initialize(argv)
78
+ @quick = argv.flag?('quick')
79
+ @local = argv.flag?('local')
80
+ @only_errors = argv.flag?('only-errors')
81
+ @clean = argv.flag?('clean', true)
82
+ @podspecs_paths = argv.arguments!
44
83
  super
45
84
  end
85
+
86
+ def run
87
+ UI.puts
88
+ invalid_count = 0
89
+ podspecs_to_lint.each do |podspec|
90
+ validator = Validator.new(podspec)
91
+ validator.quick = @quick
92
+ validator.local = @local
93
+ validator.no_clean = !@clean
94
+ validator.only_errors = @only_errors
95
+ validator.validate
96
+ invalid_count += 1 unless validator.validated?
97
+
98
+ unless @clean
99
+ UI.puts "Pods project available at `#{validator.validation_dir}/Pods/Pods.xcodeproj` for inspection."
100
+ UI.puts
101
+ end
102
+ end
103
+
104
+ count = podspecs_to_lint.count
105
+ UI.puts "Analyzed #{count} #{'podspec'.pluralize(count)}.\n\n"
106
+ if invalid_count == 0
107
+ lint_passed_message = count == 1 ? "#{podspecs_to_lint.first.basename} passed validation." : "All the specs passed validation."
108
+ UI.puts lint_passed_message.green << "\n\n"
109
+ else
110
+ raise Informative, count == 1 ? "The spec did not pass validation." : "#{invalid_count} out of #{count} specs failed validation."
111
+ end
112
+ podspecs_tmp_dir.rmtree if podspecs_tmp_dir.exist?
113
+ end
46
114
  end
47
115
 
48
- def run
49
- send @action
116
+ #-----------------------------------------------------------------------#
117
+
118
+ class Which < Spec
119
+ self.summary = 'Prints the path of the given spec.'
120
+
121
+ self.description = <<-DESC
122
+ Prints the path of 'NAME.podspec'
123
+ DESC
124
+
125
+ self.arguments = '[ NAME ]'
126
+
127
+ def self.options
128
+ [["--show-all", "Print all versions of the given podspec"]].concat(super)
129
+ end
130
+
131
+ def initialize(argv)
132
+ @show_all = argv.flag?('show-all')
133
+ @spec = argv.shift_argument
134
+ @spec = @spec.gsub('.podspec', '') unless @spec.nil?
135
+ super
136
+ end
137
+
138
+ def validate!
139
+ super
140
+ help! "A podspec name is required." unless @spec
141
+ end
142
+
143
+ def run
144
+ UI.puts get_path_of_spec(@spec, @show_all)
145
+ end
50
146
  end
51
147
 
52
- def create
53
- if repo_id_match = (@url || @name_or_url).match(/github.com\/([^\/\.]*\/[^\/\.]*)\.*/)
54
- # This is to make sure Faraday doesn't warn the user about the `system_timer` gem missing.
55
- old_warn, $-w = $-w, nil
56
- begin
57
- require 'faraday'
58
- ensure
59
- $-w = old_warn
148
+ #-----------------------------------------------------------------------#
149
+
150
+ class Cat < Spec
151
+ self.summary = 'Prints a spec file.'
152
+
153
+ self.description = <<-DESC
154
+ Prints 'NAME.podspec' to standard output.
155
+ DESC
156
+
157
+ self.arguments = '[ NAME ]'
158
+
159
+ def self.options
160
+ [["--show-all", "Pick from all versions of the given podspec"]].concat(super)
161
+ end
162
+
163
+ def initialize(argv)
164
+ @show_all = argv.flag?('show-all')
165
+ @spec = argv.shift_argument
166
+ @spec = @spec.gsub('.podspec', '') unless @spec.nil?
167
+ super
168
+ end
169
+
170
+ def validate!
171
+ super
172
+ help! "A podspec name is required." unless @spec
173
+ end
174
+
175
+ def run
176
+ filepath = if @show_all
177
+ specs = get_path_of_spec(@spec, @show_all).split(/\n/)
178
+ index = choose_from_array(specs, "Which spec would you like to print [1-#{ specs.count }]? ")
179
+ specs[index]
180
+ else
181
+ get_path_of_spec(@spec)
60
182
  end
61
- require 'octokit'
62
183
 
63
- repo_id = repo_id_match[1]
64
- data = github_data_for_template(repo_id)
65
- data[:name] = @name_or_url if @url
66
- UI.puts semantic_versioning_notice(repo_id, data[:name]) if data[:version] == '0.0.1'
67
- else
68
- data = default_data_for_template(@name_or_url)
184
+ UI.puts File.open(filepath).read
69
185
  end
70
- spec = spec_template(data)
71
- (Pathname.pwd + "#{data[:name]}.podspec").open('w') { |f| f << spec }
72
- UI.puts "\nSpecification created at #{data[:name]}.podspec".green
73
186
  end
74
187
 
75
- def lint
76
- UI.puts
77
- invalid_count = 0
78
- podspecs_to_lint.each do |podspec|
79
- linter = Linter.new(podspec)
80
- linter.quick = @quick
81
- linter.local = @local
82
- linter.no_clean = @no_clean
83
-
84
- # Show immediatly which pod is being processed.
85
- print " -> #{linter.spec_name}\r" unless config.silent?
86
- $stdout.flush
87
- linter.lint
88
-
89
- case linter.result_type
90
- when :error
91
- invalid_count += 1
92
- color = :red
93
- when :warning
94
- invalid_count += 1 unless @only_errors
95
- color = :yellow
188
+ #-----------------------------------------------------------------------#
189
+
190
+ class Edit < Spec
191
+ self.summary = 'Edit a spec file.'
192
+
193
+ self.description = <<-DESC
194
+ Opens 'NAME.podspec' to be edited.
195
+ DESC
196
+
197
+ self.arguments = '[ NAME ]'
198
+
199
+ def self.options
200
+ [["--show-all", "Pick which spec to edit from all avaliable versions of the given podspec"]].concat(super)
201
+ end
202
+
203
+ def initialize(argv)
204
+ @show_all = argv.flag?('show-all')
205
+ @spec = argv.shift_argument
206
+ @spec = @spec.gsub('.podspec', '') unless @spec.nil?
207
+ super
208
+ end
209
+
210
+ def validate!
211
+ super
212
+ help! "A podspec name is required." unless @spec
213
+ end
214
+
215
+ def run
216
+ filepath = if @show_all
217
+ specs = get_path_of_spec(@spec, @show_all).split(/\n/)
218
+ index = choose_from_array(specs, "Which spec would you like to edit [1-#{ specs.count }]? ")
219
+ specs[index]
96
220
  else
97
- color = :green
221
+ get_path_of_spec(@spec)
98
222
  end
99
223
 
100
- # This overwrites the previously printed text
101
- UI.puts " -> ".send(color) << linter.spec_name unless config.silent?
102
- print_messages('ERROR', linter.errors)
103
- print_messages('WARN', linter.warnings)
104
- print_messages('NOTE', linter.notes)
224
+ exec_editor(filepath.to_s) if File.exists? filepath
225
+ raise Informative, "#{ filepath } doesn't exist."
226
+ end
105
227
 
106
- UI.puts unless config.silent?
228
+ # Thank you homebrew
229
+ def which(cmd)
230
+ dir = ENV['PATH'].split(':').find { |p| File.executable? File.join(p, cmd) }
231
+ Pathname.new(File.join(dir, cmd)) unless dir.nil?
107
232
  end
108
233
 
109
- count = podspecs_to_lint.count
110
- UI.puts "Analyzed #{count} #{'podspec'.pluralize(count)}.\n\n" unless config.silent?
111
- if invalid_count == 0
112
- lint_passed_message = count == 1 ? "#{podspecs_to_lint.first.basename} passed validation." : "All the specs passed validation."
113
- UI.puts lint_passed_message.green << "\n\n" unless config.silent?
114
- else
115
- raise Informative, count == 1 ? "The spec did not pass validation." : "#{invalid_count} out of #{count} specs failed validation."
234
+ def which_editor
235
+ editor = ENV['EDITOR']
236
+ # If an editor wasn't set, try to pick a sane default
237
+ return editor unless editor.nil?
238
+
239
+ # Find Sublime Text 2
240
+ return 'subl' if which 'subl'
241
+ # Find Textmate
242
+ return 'mate' if which 'mate'
243
+ # Find # BBEdit / TextWrangler
244
+ return 'edit' if which 'edit'
245
+ # Default to vim
246
+ return 'vim' if which 'vim'
247
+
248
+ raise Informative, "Failed to open editor. Set your 'EDITOR' environment variable."
249
+ end
250
+
251
+ def exec_editor *args
252
+ return if args.to_s.empty?
253
+ safe_exec(which_editor, *args)
254
+ end
255
+
256
+ def safe_exec(cmd, *args)
257
+ # This buys us proper argument quoting and evaluation
258
+ # of environment variables in the cmd parameter.
259
+ exec "/bin/sh", "-i", "-c", cmd + ' "$@"', "--", *args
116
260
  end
117
- podspecs_tmp_dir.rmtree if podspecs_tmp_dir.exist?
118
261
  end
119
262
 
263
+ #-----------------------------------------------------------------------#
264
+
265
+ # @todo some of the following methods can probably move to one of the
266
+ # subclasses.
267
+
120
268
  private
121
269
 
122
- def print_messages(type, messages)
123
- return if config.silent?
124
- messages.each {|msg| UI.puts " - #{type.ljust(5)} | #{msg}"}
270
+ # @return [Fixnum] the index of the chosen array item
271
+ #
272
+ def choose_from_array(array, message)
273
+ array.each_with_index do |item, index|
274
+ UI.puts "#{ index + 1 }: #{ item }"
275
+ end
276
+
277
+ print message
278
+
279
+ index = STDIN.gets.chomp.to_i - 1
280
+ if index < 0 || index > array.count
281
+ raise Informative, "#{ index + 1 } is invalid [1-#{ array.count }]"
282
+ else
283
+ index
284
+ end
285
+ end
286
+
287
+ # @param [String] spec
288
+ # The name of the specification.
289
+ #
290
+ # @param [Bool] show_all
291
+ # Whether the paths for all the versions should be returned or
292
+ # only the one for the last version.
293
+ #
294
+ # @return [Pathname] the absolute path or paths of the given podspec
295
+ #
296
+ def get_path_of_spec(spec, show_all = false)
297
+ sets = SourcesManager.search_by_name(spec)
298
+
299
+ if sets.count == 1
300
+ set = sets.first
301
+ elsif sets.map(&:name).include?(spec)
302
+ set = sets.find { |s| s.name == spec }
303
+ else
304
+ names = sets.collect(&:name) * ', '
305
+ raise Informative, "More than one spec found for '#{ spec }':\n#{ names }"
306
+ end
307
+
308
+ unless show_all
309
+ best_spec, spec_source = spec_and_source_from_set(set)
310
+ return pathname_from_spec(best_spec, spec_source)
311
+ end
312
+
313
+ return all_paths_from_set(set)
314
+ end
315
+
316
+ # @return [Pathname] the absolute path of the given spec and source
317
+ #
318
+ def pathname_from_spec(spec, source)
319
+ Pathname.new("~/.cocoapods/#{ source }/#{ spec.name }/#{ spec.version }/#{ spec.name }.podspec").expand_path
320
+ end
321
+
322
+ # @return [String] of spec paths one on each line
323
+ #
324
+ def all_paths_from_set(set)
325
+ paths = ""
326
+
327
+ sources = set.sources
328
+
329
+ sources.each do |source|
330
+ versions = source.versions(set.name)
331
+
332
+ versions.each do |version|
333
+ spec = source.specification(set.name, version)
334
+ paths += "#{ pathname_from_spec(spec, source) }\n"
335
+ end
336
+ end
337
+
338
+ paths
339
+ end
340
+
341
+ # @return [Specification, Source] the highest known specification with it's source of the given
342
+ # set.
343
+ #
344
+ def spec_and_source_from_set(set)
345
+ sources = set.sources
346
+
347
+ best_source = sources.first
348
+ best_version = best_source.versions(set.name).first
349
+ sources.each do |source|
350
+ version = source.versions(set.name).first
351
+ if version > best_version
352
+ best_source = source
353
+ best_version = version
354
+ end
355
+ end
356
+
357
+ return best_source.specification(set.name, best_version), best_source
125
358
  end
126
359
 
127
360
  def podspecs_to_lint
@@ -154,7 +387,13 @@ module Pod
154
387
  Pathname.new('/tmp/CocoaPods/Lint_podspec')
155
388
  end
156
389
 
157
- # Templates and github information retrival for spec create
390
+ #--------------------------------------#
391
+
392
+ # Templates and github information retrieval for spec create
393
+ #
394
+ # @todo It would be nice to have a template class that accepts options
395
+ # and uses the default ones if not provided.
396
+ # @todo The template is outdated.
158
397
 
159
398
  def default_data_for_template(name)
160
399
  data = {}
@@ -230,7 +469,7 @@ Pod::Spec.new do |s|
230
469
  s.homepage = "#{data[:homepage]}"
231
470
 
232
471
  # Specify the license type. CocoaPods detects automatically the license file if it is named
233
- # `LICEN{C,S}E*.*', however if the name is different, specify it.
472
+ # 'LICENCE*.*' or 'LICENSE*.*', however if the name is different, specify it.
234
473
  s.license = 'MIT (example)'
235
474
  # s.license = { :type => 'MIT (example)', :file => 'FILE_LICENSE' }
236
475
  #