cocoapods 0.16.4 → 0.17.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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
  #