cocoapods-dykit 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3964bce4d5f9102fbfc4b79cb40768446441b454
4
+ data.tar.gz: 8d4057b36a2d2c5d77719761eb6ba78dbc998d03
5
+ SHA512:
6
+ metadata.gz: 7f5f0bf522eccd081170944711125a6add53bb2ec4543d5a000b2aae7e408c170290daab52e069137418f643d283aa397071af964b451770f402b1142ba66b5f
7
+ data.tar.gz: b457ccbb3b95e6600d7c7d6cffde92ea89ad35172856ccb00d91873814952ff403c99bd58a306a5c2b730f2c3fb6280cb961bc2a44ed8820261f2bf5c7471c10
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ .DS_Store
2
+ pkg
3
+ .idea/
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cocoapods-dykit.gemspec
4
+ gemspec
5
+
6
+ group :development do
7
+ gem 'cocoapods'
8
+
9
+ gem 'mocha'
10
+ gem 'bacon'
11
+ gem 'mocha-on-bacon'
12
+ gem 'prettybacon'
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2018 黄露洋 <huangluyang@douyu.tv>
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,25 @@
1
+ # cocoapods-dykit
2
+
3
+ 绕过 `pod lib lint` 模拟器验证。
4
+
5
+ ## Installation
6
+
7
+ $ sudo gem install cocoapods-dykit -v 0.1.0 -NV
8
+
9
+ ## Usage
10
+
11
+ > 说明:以下命令中 douyu、douyu-beijing、master 为本地 spec 仓库别名,可以通过 `pod repo list` 查看本地有哪些 spec 仓库别名
12
+
13
+ ~~~sh
14
+ # 验证静态库
15
+ $ pod lib dylint --sources=douyu,douyu-beijing,master --use-libraries --allow-warnings
16
+
17
+ # 验证动态库
18
+ pod lib dylint --sources=douyu,douyu-beijing,master --allow-warnings
19
+
20
+ # 推送静态库
21
+ pod repo dypush douyu --use-libraries --allow-warnings --sources=douyu,douyu-beijing,master
22
+
23
+ # 推送动态库
24
+ pod repo dypush douyu --allow-warnings --sources=douyu,douyu-beijing,master
25
+ ~~~
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ def specs(dir)
4
+ FileList["spec/#{dir}/*_spec.rb"].shuffle.join(' ')
5
+ end
6
+
7
+ desc 'Runs all the specs'
8
+ task :specs do
9
+ sh "bundle exec bacon #{specs('**')}"
10
+ end
11
+
12
+ task :default => :specs
13
+
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pod/gem_version.rb'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cocoapods-dykit'
8
+ spec.version = CocoapodsDylint::VERSION
9
+ spec.authors = ['黄露洋']
10
+ spec.email = ['huangluyang@douyu.tv']
11
+ spec.description = 'Validates a Pod without simulator.'
12
+ spec.summary = 'Validates the Pod using the files in the working directory without simulator.'
13
+ spec.homepage = 'http://gitlab.douyuios.com/douyu-ios/cocoapods-dykit'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_dependency "cocoapods", '>= 1.3.1', '< 1.4.0'
22
+ spec.add_development_dependency 'bundler', '~> 1.3'
23
+ spec.add_development_dependency 'rake'
24
+ end
@@ -0,0 +1 @@
1
+ require 'pod/gem_version'
@@ -0,0 +1 @@
1
+ require 'pod/command'
@@ -0,0 +1,2 @@
1
+ require 'pod/command/lib/dylint'
2
+ require 'pod/command/repo/dypush'
@@ -0,0 +1,11 @@
1
+ require 'cocoapods/command/fmwk/create'
2
+ require 'cocoapods/command/fmwk/build'
3
+
4
+ module Pod
5
+ class Command
6
+ class Fmwk < Command
7
+ self.abstract_command = true
8
+ self.summary = 'Develop pods'
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,136 @@
1
+ # require File.expand_path('../validator.rb', __FILE__)
2
+ require 'validator'
3
+ module Pod
4
+ class Command
5
+ # This is an example of a cocoapods plugin adding a top-level subcommand
6
+ # to the 'pod' command.
7
+ #
8
+ # You can also create subcommands of existing or new commands. Say you
9
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
10
+ # (e.g. `pod list deprecated`), there are a few things that would need
11
+ # to change.
12
+ #
13
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
14
+ # the class to exist in the the Pod::Command::List namespace
15
+ # - change this class to extend from `List` instead of `Command`. This
16
+ # tells the plugin system that it is a subcommand of `list`.
17
+ # - edit `lib/cocoapods_plugins.rb` to require this file
18
+ #
19
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
20
+ # in the `plugins.json` file, once your plugin is released.
21
+ #
22
+ class Fmwk < Command
23
+ class Create < Fmwk
24
+ self.summary = 'Validates a Pod without simulator'
25
+
26
+ self.description = <<-DESC
27
+ Validates the Pod using the files in the working directory without simulator.
28
+ DESC
29
+
30
+ def self.options
31
+ [
32
+ # ['--quick', 'Lint skips checks that would require to download and build the spec'],
33
+ # ['--allow-warnings', 'Lint validates even if warnings are present'],
34
+ # ['--subspec=NAME', 'Lint validates only the given subspec'],
35
+ # ['--no-subspecs', 'Lint skips validation of subspecs'],
36
+ # ['--no-clean', 'Lint leaves the build directory intact for inspection'],
37
+ # ['--fail-fast', 'Lint stops on the first failing platform or subspec'],
38
+ # ['--use-libraries', 'Lint uses static libraries to install the spec'],
39
+ # ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
40
+ # '(defaults to https://github.com/CocoaPods/Specs.git). ' \
41
+ # 'Multiple sources must be comma-delimited.'],
42
+ # ['--private', 'Lint skips checks that apply only to public specs'],
43
+ # ['--swift-version=VERSION', 'The SWIFT_VERSION that should be used to lint the spec. ' \
44
+ # 'This takes precedence over a .swift-version file.'],
45
+ # ['--skip-import-validation', 'Lint skips validating that the pod can be imported'],
46
+ # ['--skip-tests', 'Lint skips building and running tests during validation'],
47
+ ].concat(super)
48
+ end
49
+
50
+ def initialize(argv)
51
+ # @quick = argv.flag?('quick')
52
+ # @allow_warnings = argv.flag?('allow-warnings')
53
+ # @clean = argv.flag?('clean', true)
54
+ # @fail_fast = argv.flag?('fail-fast', false)
55
+ # @subspecs = argv.flag?('subspecs', true)
56
+ # @only_subspec = argv.option('subspec')
57
+ # @use_frameworks = !argv.flag?('use-libraries')
58
+ # @source_urls = argv.option('sources', 'https://github.com/CocoaPods/Specs.git').split(',')
59
+ # @private = argv.flag?('private', false)
60
+ # @swift_version = argv.option('swift-version', nil)
61
+ # @skip_import_validation = argv.flag?('skip-import-validation', false)
62
+ # @skip_tests = argv.flag?('skip-tests', false)
63
+ @framework_names = argv.arguments!
64
+ super
65
+ end
66
+
67
+ def validate!
68
+ super
69
+ end
70
+
71
+ def run
72
+ UI.puts
73
+ podspecs_to_lint.each do |podspec|
74
+ validator = Pod::DyValidator.new(podspec, @source_urls)
75
+ validator.local = true
76
+ validator.quick = @quick
77
+ validator.no_clean = !@clean
78
+ validator.fail_fast = @fail_fast
79
+ validator.allow_warnings = @allow_warnings
80
+ validator.no_subspecs = !@subspecs || @only_subspec
81
+ validator.only_subspec = @only_subspec
82
+ validator.use_frameworks = @use_frameworks
83
+ validator.ignore_public_only_results = @private
84
+ validator.swift_version = @swift_version
85
+ validator.skip_import_validation = @skip_import_validation
86
+ validator.skip_tests = @skip_tests
87
+ validator.validate
88
+
89
+ unless @clean
90
+ UI.puts "Pods workspace available at `#{validator.validation_dir}/App.xcworkspace` for inspection."
91
+ UI.puts
92
+ end
93
+ if validator.validated?
94
+ UI.puts "#{validator.spec.name} passed validation.".green
95
+ else
96
+ spec_name = podspec
97
+ spec_name = validator.spec.name if validator.spec
98
+ message = "#{spec_name} did not pass validation, due to #{validator.failure_reason}."
99
+
100
+ if @clean
101
+ message << "\nYou can use the `--no-clean` option to inspect " \
102
+ 'any issue.'
103
+ end
104
+ raise Informative, message
105
+ end
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ #----------------------------------------#
112
+
113
+ # !@group Private helpers
114
+
115
+ # @return [Pathname] The path of the podspec found in the current
116
+ # working directory.
117
+ #
118
+ # @raise If no podspec is found.
119
+ # @raise If multiple podspecs are found.
120
+ #
121
+ def podspecs_to_lint
122
+ if !@podspecs_paths.empty?
123
+ Array(@podspecs_paths)
124
+ else
125
+ podspecs = Pathname.glob(Pathname.pwd + '*.podspec{.json,}')
126
+ if podspecs.count.zero?
127
+ raise Informative, 'Unable to find a podspec in the working ' \
128
+ 'directory'
129
+ end
130
+ podspecs
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,136 @@
1
+ # require File.expand_path('../validator.rb', __FILE__)
2
+ require 'validator'
3
+ module Pod
4
+ class Command
5
+ # This is an example of a cocoapods plugin adding a top-level subcommand
6
+ # to the 'pod' command.
7
+ #
8
+ # You can also create subcommands of existing or new commands. Say you
9
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
10
+ # (e.g. `pod list deprecated`), there are a few things that would need
11
+ # to change.
12
+ #
13
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
14
+ # the class to exist in the the Pod::Command::List namespace
15
+ # - change this class to extend from `List` instead of `Command`. This
16
+ # tells the plugin system that it is a subcommand of `list`.
17
+ # - edit `lib/cocoapods_plugins.rb` to require this file
18
+ #
19
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
20
+ # in the `plugins.json` file, once your plugin is released.
21
+ #
22
+ class Lib < Command
23
+ class Dylint < Lib
24
+ self.summary = 'Validates a Pod without simulator'
25
+
26
+ self.description = <<-DESC
27
+ Validates the Pod using the files in the working directory without simulator.
28
+ DESC
29
+
30
+ def self.options
31
+ [
32
+ ['--quick', 'Lint skips checks that would require to download and build the spec'],
33
+ ['--allow-warnings', 'Lint validates even if warnings are present'],
34
+ ['--subspec=NAME', 'Lint validates only the given subspec'],
35
+ ['--no-subspecs', 'Lint skips validation of subspecs'],
36
+ ['--no-clean', 'Lint leaves the build directory intact for inspection'],
37
+ ['--fail-fast', 'Lint stops on the first failing platform or subspec'],
38
+ ['--use-libraries', 'Lint uses static libraries to install the spec'],
39
+ ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
40
+ '(defaults to https://github.com/CocoaPods/Specs.git). ' \
41
+ 'Multiple sources must be comma-delimited.'],
42
+ ['--private', 'Lint skips checks that apply only to public specs'],
43
+ ['--swift-version=VERSION', 'The SWIFT_VERSION that should be used to lint the spec. ' \
44
+ 'This takes precedence over a .swift-version file.'],
45
+ ['--skip-import-validation', 'Lint skips validating that the pod can be imported'],
46
+ ['--skip-tests', 'Lint skips building and running tests during validation'],
47
+ ].concat(super)
48
+ end
49
+
50
+ def initialize(argv)
51
+ @quick = argv.flag?('quick')
52
+ @allow_warnings = argv.flag?('allow-warnings')
53
+ @clean = argv.flag?('clean', true)
54
+ @fail_fast = argv.flag?('fail-fast', false)
55
+ @subspecs = argv.flag?('subspecs', true)
56
+ @only_subspec = argv.option('subspec')
57
+ @use_frameworks = !argv.flag?('use-libraries')
58
+ @source_urls = argv.option('sources', 'https://github.com/CocoaPods/Specs.git').split(',')
59
+ @private = argv.flag?('private', false)
60
+ @swift_version = argv.option('swift-version', nil)
61
+ @skip_import_validation = argv.flag?('skip-import-validation', false)
62
+ @skip_tests = argv.flag?('skip-tests', false)
63
+ @podspecs_paths = argv.arguments!
64
+ super
65
+ end
66
+
67
+ def validate!
68
+ super
69
+ end
70
+
71
+ def run
72
+ UI.puts
73
+ podspecs_to_lint.each do |podspec|
74
+ validator = Pod::DyValidator.new(podspec, @source_urls)
75
+ validator.local = true
76
+ validator.quick = @quick
77
+ validator.no_clean = !@clean
78
+ validator.fail_fast = @fail_fast
79
+ validator.allow_warnings = @allow_warnings
80
+ validator.no_subspecs = !@subspecs || @only_subspec
81
+ validator.only_subspec = @only_subspec
82
+ validator.use_frameworks = @use_frameworks
83
+ validator.ignore_public_only_results = @private
84
+ validator.swift_version = @swift_version
85
+ validator.skip_import_validation = @skip_import_validation
86
+ validator.skip_tests = @skip_tests
87
+ validator.validate
88
+
89
+ unless @clean
90
+ UI.puts "Pods workspace available at `#{validator.validation_dir}/App.xcworkspace` for inspection."
91
+ UI.puts
92
+ end
93
+ if validator.validated?
94
+ UI.puts "#{validator.spec.name} passed validation.".green
95
+ else
96
+ spec_name = podspec
97
+ spec_name = validator.spec.name if validator.spec
98
+ message = "#{spec_name} did not pass validation, due to #{validator.failure_reason}."
99
+
100
+ if @clean
101
+ message << "\nYou can use the `--no-clean` option to inspect " \
102
+ 'any issue.'
103
+ end
104
+ raise Informative, message
105
+ end
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ #----------------------------------------#
112
+
113
+ # !@group Private helpers
114
+
115
+ # @return [Pathname] The path of the podspec found in the current
116
+ # working directory.
117
+ #
118
+ # @raise If no podspec is found.
119
+ # @raise If multiple podspecs are found.
120
+ #
121
+ def podspecs_to_lint
122
+ if !@podspecs_paths.empty?
123
+ Array(@podspecs_paths)
124
+ else
125
+ podspecs = Pathname.glob(Pathname.pwd + '*.podspec{.json,}')
126
+ if podspecs.count.zero?
127
+ raise Informative, 'Unable to find a podspec in the working ' \
128
+ 'directory'
129
+ end
130
+ podspecs
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,291 @@
1
+ # require File.expand_path('../../../../validator.rb', __FILE__)
2
+ require 'validator'
3
+ module Pod
4
+ class Command
5
+ # This is an example of a cocoapods plugin adding a top-level subcommand
6
+ # to the 'pod' command.
7
+ #
8
+ # You can also create subcommands of existing or new commands. Say you
9
+ # wanted to add a subcommand to `list` to show newly deprecated pods,
10
+ # (e.g. `pod list deprecated`), there are a few things that would need
11
+ # to change.
12
+ #
13
+ # - move this file to `lib/pod/command/list/deprecated.rb` and update
14
+ # the class to exist in the the Pod::Command::List namespace
15
+ # - change this class to extend from `List` instead of `Command`. This
16
+ # tells the plugin system that it is a subcommand of `list`.
17
+ # - edit `lib/cocoapods_plugins.rb` to require this file
18
+ #
19
+ # @todo Create a PR to add your plugin to CocoaPods/cocoapods.org
20
+ # in the `plugins.json` file, once your plugin is released.
21
+ #
22
+ class Repo < Command
23
+ class Dypush < Repo
24
+ self.summary = 'Push new specifications to a spec-repo'
25
+
26
+ self.description = <<-DESC
27
+ Validates `NAME.podspec` or `*.podspec` in the current working dir,
28
+ creates a directory and version folder for the pod in the local copy of
29
+ `REPO` (~/.cocoapods/repos/[REPO]), copies the podspec file into the
30
+ version directory, and finally it pushes `REPO` to its remote.
31
+ DESC
32
+
33
+ self.arguments = [
34
+ CLAide::Argument.new('REPO', true),
35
+ CLAide::Argument.new('NAME.podspec', false),
36
+ ]
37
+
38
+ def self.options
39
+ [
40
+ ['--allow-warnings', 'Allows pushing even if there are warnings'],
41
+ ['--use-libraries', 'Linter uses static libraries to install the spec'],
42
+ ['--sources=https://github.com/artsy/Specs,master', 'The sources from which to pull dependent pods ' \
43
+ '(defaults to all available repos). ' \
44
+ 'Multiple sources must be comma-delimited.'],
45
+ ['--local-only', 'Does not perform the step of pushing REPO to its remote'],
46
+ ['--no-private', 'Lint includes checks that apply only to public repos'],
47
+ ['--skip-import-validation', 'Lint skips validating that the pod can be imported'],
48
+ ['--skip-tests', 'Lint skips building and running tests during validation'],
49
+ ['--commit-message="Fix bug in pod"', 'Add custom commit message. ' \
50
+ 'Opens default editor if no commit message is specified.'],
51
+ ['--use-json', 'Push JSON spec to repo'],
52
+ ['--swift-version=VERSION', 'The SWIFT_VERSION that should be used when linting the spec. ' \
53
+ 'This takes precedence over a .swift-version file.'],
54
+ ].concat(super)
55
+ end
56
+
57
+ def initialize(argv)
58
+ @allow_warnings = argv.flag?('allow-warnings')
59
+ @local_only = argv.flag?('local-only')
60
+ @repo = argv.shift_argument
61
+ @source = source_for_repo
62
+ @source_urls = argv.option('sources', config.sources_manager.all.map(&:url).join(',')).split(',')
63
+ @podspec = argv.shift_argument
64
+ @use_frameworks = !argv.flag?('use-libraries')
65
+ @private = argv.flag?('private', true)
66
+ @message = argv.option('commit-message')
67
+ @commit_message = argv.flag?('commit-message', false)
68
+ @use_json = argv.flag?('use-json')
69
+ @swift_version = argv.option('swift-version', nil)
70
+ @skip_import_validation = argv.flag?('skip-import-validation', false)
71
+ @skip_tests = argv.flag?('skip-tests', false)
72
+ super
73
+ end
74
+
75
+ def validate!
76
+ super
77
+ help! 'A spec-repo name or url is required.' unless @repo
78
+ unless @source && @source.repo.directory?
79
+ raise Informative,
80
+ "Unable to find the `#{@repo}` repo. " \
81
+ 'If it has not yet been cloned, add it via `pod repo add`.'
82
+ end
83
+ end
84
+
85
+ def run
86
+ open_editor if @commit_message && @message.nil?
87
+ check_if_master_repo
88
+ validate_podspec_files
89
+ check_repo_status
90
+ update_repo
91
+ add_specs_to_repo
92
+ push_repo unless @local_only
93
+ end
94
+
95
+ #---------------------------------------------------------------------#
96
+
97
+ private
98
+
99
+ # @!group Push sub-steps
100
+
101
+ extend Executable
102
+ executable :git
103
+
104
+ # Open default editor to allow users to enter commit message
105
+ #
106
+ def open_editor
107
+ return if ENV['EDITOR'].nil?
108
+
109
+ file = Tempfile.new('cocoapods')
110
+ File.chmod(0777, file.path)
111
+ file.close
112
+
113
+ system("#{ENV['EDITOR']} #{file.path}")
114
+ @message = File.read file.path
115
+ end
116
+
117
+ # Temporary check to ensure that users do not push accidentally private
118
+ # specs to the master repo.
119
+ #
120
+ def check_if_master_repo
121
+ remotes = `git -C "#{repo_dir}" remote -v 2>&1`
122
+ master_repo_urls = [
123
+ 'git@github.com:CocoaPods/Specs.git',
124
+ 'https://github.com/CocoaPods/Specs.git',
125
+ ]
126
+ is_master_repo = master_repo_urls.any? do |url|
127
+ remotes.include?(url)
128
+ end
129
+
130
+ if is_master_repo
131
+ raise Informative, 'To push to the CocoaPods master repo use ' \
132
+ "the `pod trunk push` command.\n\nIf you are using a fork of " \
133
+ 'the master repo for private purposes we recommend to migrate ' \
134
+ 'to a clean private repo. To disable this check remove the ' \
135
+ 'remote pointing to the CocoaPods master repo.'
136
+ end
137
+ end
138
+
139
+ # Performs a full lint against the podspecs.
140
+ #
141
+ def validate_podspec_files
142
+ UI.puts "\nValidating #{'spec'.pluralize(count)}".yellow
143
+ podspec_files.each do |podspec|
144
+ validator = DyValidator.new(podspec, @source_urls)
145
+ validator.allow_warnings = @allow_warnings
146
+ validator.use_frameworks = @use_frameworks
147
+ validator.ignore_public_only_results = @private
148
+ validator.swift_version = @swift_version
149
+ validator.skip_import_validation = @skip_import_validation
150
+ validator.skip_tests = @skip_tests
151
+ begin
152
+ validator.validate
153
+ rescue => e
154
+ raise Informative, "The `#{podspec}` specification does not validate." \
155
+ "\n\n#{e.message}"
156
+ end
157
+ raise Informative, "The `#{podspec}` specification does not validate." unless validator.validated?
158
+ end
159
+ end
160
+
161
+ # Checks that the repo is clean.
162
+ #
163
+ # @raise If the repo is not clean.
164
+ #
165
+ # @todo Add specs for staged and unstaged files.
166
+ #
167
+ # @todo Gracefully handle the case where source is not under git
168
+ # source control.
169
+ #
170
+ # @return [void]
171
+ #
172
+ def check_repo_status
173
+ clean = `git -C "#{repo_dir}" status --porcelain 2>&1` == ''
174
+ raise Informative, "The repo `#{@repo}` at #{UI.path repo_dir} is not clean" unless clean
175
+ end
176
+
177
+ # Updates the git repo against the remote.
178
+ #
179
+ # @return [void]
180
+ #
181
+ def update_repo
182
+ UI.puts "Updating the `#{@repo}' repo\n".yellow
183
+ UI.puts `git -C "#{repo_dir}" pull 2>&1`
184
+ end
185
+
186
+ # Commits the podspecs to the source, which should be a git repo.
187
+ #
188
+ # @note The pre commit hook of the repo is skipped as the podspecs have
189
+ # already been linted.
190
+ #
191
+ # @return [void]
192
+ #
193
+ def add_specs_to_repo
194
+ UI.puts "\nAdding the #{'spec'.pluralize(count)} to the `#{@repo}' repo\n".yellow
195
+ podspec_files.each do |spec_file|
196
+ spec = Pod::Specification.from_file(spec_file)
197
+ output_path = @source.pod_path(spec.name) + spec.version.to_s
198
+ if @message && !@message.empty?
199
+ message = @message
200
+ elsif output_path.exist?
201
+ message = "[Fix] #{spec}"
202
+ elsif output_path.dirname.directory?
203
+ message = "[Update] #{spec}"
204
+ else
205
+ message = "[Add] #{spec}"
206
+ end
207
+ FileUtils.mkdir_p(output_path)
208
+
209
+ if @use_json
210
+ json_file_name = "#{spec.name}.podspec.json"
211
+ json_file = File.join(output_path, json_file_name)
212
+ File.open(json_file, 'w') { |file| file.write(spec.to_pretty_json) }
213
+ else
214
+ FileUtils.cp(spec_file, output_path)
215
+ end
216
+
217
+ # only commit if modified
218
+ if repo_git('status', '--porcelain').include?(spec.name)
219
+ UI.puts " - #{message}"
220
+ repo_git('add', spec.name)
221
+ repo_git('commit', '--no-verify', '-m', message)
222
+ else
223
+ UI.puts " - [No change] #{spec}"
224
+ end
225
+ end
226
+ end
227
+
228
+ # Pushes the git repo against the remote.
229
+ #
230
+ # @return [void]
231
+ #
232
+ def push_repo
233
+ UI.puts "\nPushing the `#{@repo}' repo\n".yellow
234
+ repo_git('-C', repo_dir, 'push', 'origin', 'master')
235
+ end
236
+
237
+ #---------------------------------------------------------------------#
238
+
239
+ private
240
+
241
+ # @!group Private helpers
242
+
243
+ # @return result of calling the git! with args in repo_dir
244
+ #
245
+ def repo_git(*args)
246
+ git!(['-C', repo_dir] + args)
247
+ end
248
+
249
+ # @return [Pathname] The directory of the repository.
250
+ #
251
+ def repo_dir
252
+ @source.specs_dir
253
+ end
254
+
255
+ # @return [Array<Pathname>] The path of the specifications to push.
256
+ #
257
+ def podspec_files
258
+ if @podspec
259
+ path = Pathname(@podspec)
260
+ raise Informative, "Couldn't find #{@podspec}" unless path.exist?
261
+ [path]
262
+ else
263
+ files = Pathname.glob('*.podspec{,.json}')
264
+ raise Informative, "Couldn't find any podspec files in current directory" if files.empty?
265
+ files
266
+ end
267
+ end
268
+
269
+ # @return [Integer] The number of the podspec files to push.
270
+ #
271
+ def count
272
+ podspec_files.count
273
+ end
274
+
275
+ # Returns source for @repo
276
+ #
277
+ # @note If URL is invalid or repo doesn't exist, validate! will throw the error
278
+ #
279
+ # @return [Source]
280
+ #
281
+ def source_for_repo
282
+ config.sources_manager.source_with_name_or_url(@repo) unless @repo.nil?
283
+ rescue
284
+ nil
285
+ end
286
+
287
+ #---------------------------------------------------------------------#
288
+ end
289
+ end
290
+ end
291
+ end