cocoapods-generate-minlison 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a7c911d9b5f53ae4a8ae418965e638901f93f6b11ea44996043771b2856046e8
4
+ data.tar.gz: a53b6c9a1f70684ef0e283fa558ba426ce7ecd5a760ac0ca3a1b58cfb0a55909
5
+ SHA512:
6
+ metadata.gz: ffa21baf0cfcec3474430ce033331db762aa9bf654ababc844aa5ef7412cad8d95a6d4074a892c3b0b749ac045cb196fdd4a669ee402100e026b7b2e4d88d801
7
+ data.tar.gz: a11298fa62d3702675871604b4c9a38a2b0de00f543fff85e99c306e4b2ca126c2ff072d10130bc10f8e392544f255109403a3ef5b6dd8231894631030b46d99
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at segiddins@squareup.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
@@ -0,0 +1,9 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,131 @@
1
+ # `cocoapods-generate`
2
+
3
+ A [CocoaPods](https://cocoapods.org/) plugin that allows you to easily generate a workspace from a podspec.
4
+
5
+ Whether you want to completely remove all Xcode projects from your library's repository or you want to be able to focus on a small piece of a monorepo, a single `pod gen` command will build up a workspace suitable for writing, running, testing, and debugging in Xcode.
6
+
7
+ When you're done working, you don't have to do anything -- and that means no merge conflicts, no managing Xcode projects, and no tearing down a sample app setup. `pod gen` manages all that for you.
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'cocoapods-generate'
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ $ bundle
20
+
21
+ Or install it yourself as:
22
+
23
+ $ gem install cocoapods-generate
24
+
25
+ ## CLI
26
+
27
+ The main point of interaction with the plugin is via the `pod gen` command.
28
+ It takes in a list of podspecs (or directories) as arguments,
29
+ as well as many options that modify how `gen` will create your workspace.
30
+
31
+ <!-- begin cli usage -->
32
+ ```
33
+ Usage:
34
+
35
+ $ pod gen [PODSPEC|DIR ...]
36
+
37
+ Generates Xcode workspaces from a podspec.
38
+
39
+ pod gen allows you to keep your Podfile and podspecs as the single source of
40
+ truth for pods under development. By generating throw-away workspaces capable of
41
+ building, running, and testing a pod, you can focus on library development
42
+ without worrying about other code or managing an Xcode project.
43
+
44
+ pod gen works particularly well for monorepo projects, since it is capable of
45
+ using your existing settings when generating the workspace, making each gen'ed
46
+ project truly a small slice of the larger application.
47
+
48
+ Options:
49
+
50
+ --silent Show nothing
51
+ --verbose Show more debugging information
52
+ --no-ansi Show output without ANSI codes
53
+ --help Show help banner of specified command
54
+ --podfile-path=PATH Path to podfile to use
55
+ --use-podfile Whether restrictions should be copied from
56
+ the podfile
57
+ --use-podfile-plugins Whether plugins should be copied from the
58
+ podfile
59
+ --use-lockfile Whether the lockfile should be used to
60
+ discover transitive dependencies
61
+ --use-lockfile-versions Whether versions from the lockfile should
62
+ be used
63
+ --use-libraries Whether to use libraries instead of
64
+ frameworks
65
+ --generate-multiple-pod-projects Whether to generate multiple Xcode projects
66
+ --incremental-installation Whether to use incremental installation
67
+ --gen-directory=PATH Path to generate workspaces in
68
+ --auto-open Whether to automatically open the generated
69
+ workspaces
70
+ --clean Whether to clean the generated directories
71
+ before generating
72
+ --app-host-source-dir=DIR A directory containing sources to use for
73
+ the app host
74
+ --sources=SOURCE1,SOURCE2 The sources from which to pull dependent
75
+ pods (defaults to all repos in the podfile
76
+ if using the podfile, else all available
77
+ repos). Can be a repo name or URL. Multiple
78
+ sources must be comma-delimited.
79
+ --local-sources=SOURCE1,SOURCE2 Paths from which to find local podspecs for
80
+ transitive dependencies. Multiple
81
+ local-sources must be comma-delimited.
82
+ --repo-update Force running `pod repo update` before
83
+ install
84
+ --use-default-plugins Whether installation should activate
85
+ default plugins
86
+ --deterministic-uuids Whether installation should use
87
+ deterministic UUIDs for pods projects
88
+ --share-schemes-for-development-pods Whether installation should share schemes
89
+ for development pods
90
+ --warn-for-multiple-pod-sources Whether installation should warn when a pod
91
+ is found in multiple sources
92
+ --use-modular-headers Whether the target should be generated as a
93
+ clang module, treating dependencies as
94
+ modules, as if `use_modular_headers!` were
95
+ specified. Will error if both this option
96
+ and a podfile are specified
97
+ ```
98
+ <!-- end cli usage -->
99
+
100
+ ## `.gen_config.yml`
101
+
102
+ All of the command line options above can also be specified in a `.gen_config.yml` file.
103
+
104
+ For example, the equivalent of running `pod gen --no-deterministic-uuids --sources=a,b --gen-directory=/tmp/gen --use-libraries` would be
105
+
106
+ ```yaml
107
+ deterministic_uuids: false
108
+ sources:
109
+ - a
110
+ - b
111
+ gen_directory: /tmp/gen
112
+ use_libraries: true
113
+ ```
114
+
115
+ ## Development
116
+
117
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `bin/rake spec` to run the tests.
118
+
119
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
120
+
121
+ To install this gem onto your local machine, run `bundle exec rake install`.
122
+
123
+ To release a new version, update the version number in `VERSION`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
124
+
125
+ ## Contributing
126
+
127
+ Bug reports and pull requests are welcome on GitHub at https://github.com/square/cocoapods-generate. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
128
+
129
+ ## Code of Conduct
130
+
131
+ Everyone interacting in the cocoapods-generate project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/square/cocoapods-generate/blob/master/CODE_OF_CONDUCT.md).
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.5.0
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'cocoapods/generate'
4
+
5
+ module Pod
6
+ class Command
7
+ class Gen < Command
8
+ self.summary = 'Generates Xcode workspaces from a podspec.'
9
+
10
+ self.description = <<-DESC.strip_heredoc
11
+ #{summary}
12
+
13
+ pod gen allows you to keep your Podfile and podspecs as the single source of
14
+ truth for pods under development. By generating throw-away workspaces capable of
15
+ building, running, and testing a pod, you can focus on library development
16
+ without worrying about other code or managing an Xcode project.
17
+
18
+ pod gen works particularly well for monorepo projects, since it is capable of
19
+ using your existing settings when generating the workspace, making each gen'ed
20
+ project truly a small slice of the larger application.
21
+ DESC
22
+
23
+ def self.options
24
+ super.concat(Generate::Configuration.options.map do |option|
25
+ next unless option.cli_name
26
+
27
+ flag = "--#{option.cli_name}"
28
+ flag += "=#{option.arg_name}" if option.arg_name
29
+ [flag, option.message]
30
+ end.compact)
31
+ end
32
+
33
+ self.arguments = [
34
+ CLAide::Argument.new(%w[PODSPEC DIR], false, true)
35
+ ]
36
+
37
+ # @return [Configuration]
38
+ # the configuration used when generating workspaces
39
+ #
40
+ attr_reader :configuration
41
+
42
+ def initialize(argv)
43
+ options_hash = Generate::Configuration.options.each_with_object({}) do |option, options|
44
+ value =
45
+ if option.name == :podspec_paths
46
+ argv.arguments!
47
+ elsif option.flag?
48
+ argv.flag?(option.cli_name)
49
+ else
50
+ argv.option(option.cli_name)
51
+ end
52
+
53
+ next if value.nil?
54
+ options[option.name] = option.coerce(value)
55
+ end
56
+ @configuration = merge_configuration(options_hash)
57
+ super
58
+ end
59
+
60
+ def run
61
+ UI.puts "[pod gen] Running with #{configuration.to_s.gsub("\n", " \n")}" if configuration.pod_config.verbose?
62
+
63
+ # this is done here rather than in the installer so we only update sources once,
64
+ # even if there are multiple podspecs
65
+ update_sources if configuration.repo_update?
66
+
67
+ Generate::PodfileGenerator.new(configuration).podfiles_by_spec.each do |spec, podfile|
68
+ Generate::Installer.new(configuration, spec, podfile).install!
69
+ end
70
+
71
+ remove_warnings(UI.warnings)
72
+ end
73
+
74
+ def validate!
75
+ super
76
+
77
+ config_errors = configuration.validate
78
+ help! config_errors.join("\n ") if config_errors.any?
79
+ end
80
+
81
+ private
82
+
83
+ def merge_configuration(options)
84
+ # must use #to_enum explicitly since descend doesn't return an enumerator on 2.1
85
+ config_hashes = Pathname.pwd.to_enum(:descend).map do |dir|
86
+ path = dir + '.gen_config.yml'
87
+ next unless path.file?
88
+ Pod::Generate::Configuration.from_file(path)
89
+ end
90
+
91
+ env = Generate::Configuration.from_env(ENV)
92
+ config_hashes.insert(-2, env)
93
+ config_hashes << options
94
+
95
+ configuration = config_hashes.compact.each_with_object({}) { |e, h| h.merge!(e) }
96
+ Pod::Generate::Configuration.new(pod_config: config, **configuration)
97
+ end
98
+
99
+ def remove_warnings(warnings)
100
+ warnings.reject! do |warning|
101
+ warning[:message].include? 'Automatically assigning platform'
102
+ end
103
+ end
104
+
105
+ def update_sources
106
+ UI.title 'Updating specs repos' do
107
+ configuration.sources.each do |source|
108
+ source = config.sources_manager.source_with_name_or_url(source)
109
+ UI.titled_section "Updating spec repo `#{source.name}`" do
110
+ source.update(config.verbose?)
111
+ source.verify_compatibility!
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,10 @@
1
+
2
+ # frozen_string_literal: true
3
+
4
+ module Pod
5
+ module Generate
6
+ autoload :Configuration, 'cocoapods/generate/configuration'
7
+ autoload :Installer, 'cocoapods/generate/installer'
8
+ autoload :PodfileGenerator, 'cocoapods/generate/podfile_generator'
9
+ end
10
+ end
@@ -0,0 +1,342 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pod
4
+ module Generate
5
+ class Configuration
6
+ @options = []
7
+ class << self
8
+ # @return [Array<Option>]
9
+ # all of the options available in the configuration
10
+ #
11
+ attr_reader :options
12
+ end
13
+
14
+ Option = Struct.new(:name, :type, :default, :message, :arg_name, :validator, :coercer) do
15
+ def validate(value)
16
+ return if value.nil?
17
+ errors = []
18
+ if (exceptions = Array(value).grep(Exception)) && exceptions.any?
19
+ errors << "Error computing #{name}"
20
+ errors.concat exceptions.map(&:message)
21
+ else
22
+ errors << "got type #{value.class}, expected object of type #{Array(type).join('|')}" unless Array(type).any? { |t| t === value }
23
+ validator_errors = begin
24
+ validator && validator[value]
25
+ rescue StandardError
26
+ "failed to run validator (#{$ERROR_INFO})"
27
+ end
28
+ errors.concat Array(validator_errors) if validator_errors
29
+ errors.unshift "#{value.inspect} invalid for #{name}" if errors.any?
30
+ end
31
+ errors.join(', ') unless errors.empty?
32
+ end
33
+
34
+ def cli_name
35
+ return unless message
36
+ @cli_name ||= name.to_s.tr '_', '-'
37
+ end
38
+
39
+ def flag?
40
+ arg_name.nil?
41
+ end
42
+
43
+ def coerce(value)
44
+ coercer ? coercer[value] : value
45
+ end
46
+ end
47
+ private_constant :Option
48
+
49
+ # Declares a new option
50
+ #
51
+ # @!macro [attach] $0
52
+ # @attribute [r] $1
53
+ # @return [$2] $4
54
+ # defaults to `$3`
55
+ #
56
+ def self.option(*args)
57
+ options << Option.new(*args)
58
+ end
59
+ private_class_method :option
60
+
61
+ # @visibility private
62
+ #
63
+ # Implements `===` to do type checking against an array.
64
+ #
65
+ class ArrayOf
66
+ attr_reader :types
67
+
68
+ def initialize(*types)
69
+ @types = types
70
+ end
71
+
72
+ def to_s
73
+ "Array<#{types.join('|')}>"
74
+ end
75
+
76
+ # @return [Boolean] whether the given object is an array with elements all of the given types
77
+ #
78
+ def ===(other)
79
+ other.is_a?(Array) && other.all? { |o| types.any? { |t| t === o } }
80
+ end
81
+ end
82
+ private_constant :ArrayOf
83
+
84
+ # @visibility private
85
+ #
86
+ # Implements `===` to do type checking against a hash.
87
+ #
88
+ class HashOf
89
+ attr_reader :key_types, :value_types
90
+
91
+ def initialize(keys:, values:)
92
+ @key_types = keys
93
+ @value_types = values
94
+ end
95
+
96
+ def to_s
97
+ "Hash<#{key_types.join('|')} => #{value_types.join('|')}}>"
98
+ end
99
+
100
+ # @return [Boolean] whether the given object is a hash with elements all of the given types
101
+ #
102
+ def ===(other)
103
+ other.is_a?(Hash) && other.all? do |key, value|
104
+ key_types.any? { |t| t === key } &&
105
+ value_types.any? { |t| t === value }
106
+ end
107
+ end
108
+ end
109
+ private_constant :HashOf
110
+
111
+ coerce_to_bool = lambda do |value|
112
+ if value.is_a?(String)
113
+ value =
114
+ case value.downcase
115
+ when ''
116
+ nil
117
+ when 'true'
118
+ true
119
+ when 'false'
120
+ false
121
+ end
122
+ end
123
+ value
124
+ end
125
+
126
+ coerce_to_pathname = lambda do |path|
127
+ path && Pathname(path).expand_path
128
+ end
129
+
130
+ BOOLEAN = [TrueClass, FalseClass].freeze
131
+ private_constant :BOOLEAN
132
+
133
+ option :pod_config, Config, 'Pod::Config.instance', nil
134
+
135
+ option :podfile_path, [String, Pathname], 'pod_config.podfile_path', 'Path to podfile to use', 'PATH', ->(path) { 'file does not exist' unless path.file? }, coerce_to_pathname
136
+ option :podfile, [Podfile], 'Podfile.from_file(podfile_path) if (podfile_path && File.file?(File.expand_path(podfile_path)))'
137
+ option :use_podfile, BOOLEAN, '!!podfile', 'Whether restrictions should be copied from the podfile', nil, nil, coerce_to_bool
138
+ option :use_podfile_plugins, BOOLEAN, 'use_podfile', 'Whether plugins should be copied from the podfile', nil, nil, coerce_to_bool
139
+ option :podfile_plugins, HashOf.new(keys: [String], values: [NilClass, HashOf.new(keys: [String], values: [TrueClass, FalseClass, NilClass, String, Hash, Array])]),
140
+ '(use_podfile && podfile) ? podfile.plugins : {}',
141
+ nil,
142
+ nil,
143
+ nil,
144
+ ->(hash) { Hash[hash] }
145
+
146
+ option :lockfile, [Pod::Lockfile], 'pod_config.lockfile', nil
147
+ option :use_lockfile, BOOLEAN, '!!lockfile', 'Whether the lockfile should be used to discover transitive dependencies', nil, nil, coerce_to_bool
148
+ option :use_lockfile_versions, BOOLEAN, 'use_lockfile', 'Whether versions from the lockfile should be used', nil, nil, coerce_to_bool
149
+
150
+ option :use_libraries, BOOLEAN, 'false', 'Whether to use libraries instead of frameworks', nil, nil, coerce_to_bool
151
+
152
+ option :generate_multiple_pod_projects, BOOLEAN, 'false', 'Whether to generate multiple Xcode projects', nil, nil, coerce_to_bool
153
+ option :incremental_installation, BOOLEAN, 'false', 'Whether to use incremental installation', nil, nil, coerce_to_bool
154
+
155
+ option :gen_directory, [String, Pathname], 'Pathname("gen").expand_path', 'Path to generate workspaces in', 'PATH', ->(path) { 'path is file' if path.file? }, coerce_to_pathname
156
+ option :auto_open, BOOLEAN, 'false', 'Whether to automatically open the generated workspaces', nil, nil, coerce_to_bool
157
+ option :clean, BOOLEAN, 'false', 'Whether to clean the generated directories before generating', nil, nil, coerce_to_bool
158
+
159
+ option :app_host_source_dir, [String, Pathname], 'nil',
160
+ 'A directory containing sources to use for the app host',
161
+ 'DIR',
162
+ ->(dir) { 'not a directory' unless dir.directory? },
163
+ coerce_to_pathname
164
+
165
+ option :podspec_paths, ArrayOf.new(String, Pathname, URI),
166
+ '[Pathname(?.)]',
167
+ nil,
168
+ nil,
169
+ ->(paths) { ('paths do not exist' unless paths.all? { |p| p.is_a?(URI) || p.exist? }) },
170
+ ->(paths) { paths && paths.map { |path| path.to_s =~ %r{https?://} ? URI(path) : Pathname(path).expand_path } }
171
+ option :podspecs, ArrayOf.new(Pod::Specification),
172
+ 'self.class.podspecs_from_paths(podspec_paths)',
173
+ nil,
174
+ nil,
175
+ ->(specs) { 'no podspecs found' if specs.empty? },
176
+ ->(paths) { paths && paths.map { |path| Pathname(path).expand_path } }
177
+
178
+ # installer options
179
+ option :sources, ArrayOf.new(String),
180
+ 'if use_podfile && podfile then ::Pod::Installer::Analyzer.new(:sandbox, podfile).sources.map(&:url) else pod_config.sources_manager.all.map(&:url) end',
181
+ 'The sources from which to pull dependent pods (defaults to all repos in the podfile if using the podfile, else all available repos). Can be a repo name or URL. Multiple sources must be comma-delimited.',
182
+ 'SOURCE1,SOURCE2',
183
+ ->(_) { nil },
184
+ ->(sources) { Array(sources).flat_map { |s| s.split(',') } }
185
+ option :local_sources, ArrayOf.new(String),
186
+ [],
187
+ 'Paths from which to find local podspecs for transitive dependencies. Multiple local-sources must be comma-delimited.',
188
+ 'SOURCE1,SOURCE2',
189
+ ->(_) { nil },
190
+ ->(local_sources) { Array(local_sources).flat_map { |s| s.split(',') } }
191
+ option :repo_update, BOOLEAN, 'false', 'Force running `pod repo update` before install', nil, nil, coerce_to_bool
192
+ option :use_default_plugins, BOOLEAN, 'false', 'Whether installation should activate default plugins', nil, nil, coerce_to_bool
193
+ option :deterministic_uuids, BOOLEAN, 'false', 'Whether installation should use deterministic UUIDs for pods projects', nil, nil, coerce_to_bool
194
+ option :share_schemes_for_development_pods, BOOLEAN, 'true', 'Whether installation should share schemes for development pods', nil, nil, coerce_to_bool
195
+ option :warn_for_multiple_pod_sources, BOOLEAN, 'false', 'Whether installation should warn when a pod is found in multiple sources', nil, nil, coerce_to_bool
196
+ option :use_modular_headers, BOOLEAN, 'false', 'Whether the target should be generated as a clang module, treating dependencies as modules, as if `use_modular_headers!` were specified. Will error if both this option and a podfile are specified', nil, nil, coerce_to_bool
197
+
198
+ options.freeze
199
+ options.each do |o|
200
+ attr_reader o.name
201
+ alias_method :"#{o.name}?", o.name if o.type == BOOLEAN
202
+ end
203
+
204
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
205
+ # @!visibility private
206
+ def initialize(
207
+ #{options.map { |o| "#{o.name}: (begin (#{o.default}); rescue => e; e; end)" }.join(', ')}
208
+ )
209
+ #{options.map { |o| "@#{o.name} = #{o.name}" }.join('; ')}
210
+ end
211
+ RUBY
212
+
213
+ # @return [Hash<Symbol,Object>] the configuration hash parsed from the given file
214
+ #
215
+ # @param [Pathname] path
216
+ #
217
+ # @raises [Informative] if the file does not exist or is not a YAML hash
218
+ #
219
+ def self.from_file(path)
220
+ raise Informative, "No cocoapods-generate configuration found at #{UI.path path}" unless path.file?
221
+ require 'yaml'
222
+ yaml = YAML.load_file(path)
223
+ unless yaml.is_a?(Hash)
224
+ unless path.read.strip.empty?
225
+ raise Informative, "Hash not found in configuration at #{UI.path path} -- got #{yaml.inspect}"
226
+ end
227
+ yaml = {}
228
+ end
229
+ yaml = yaml.with_indifferent_access
230
+
231
+ Dir.chdir(path.dirname) do
232
+ options.each_with_object({}) do |option, config|
233
+ next unless yaml.key?(option.name)
234
+ config[option.name] = option.coerce yaml[option.name]
235
+ end
236
+ end
237
+ end
238
+
239
+ # @return [Hash<Symbol,Object>] the configuration hash parsed from the env
240
+ #
241
+ # @param [ENV,Hash<String,String>] env
242
+ #
243
+ def self.from_env(env = ENV)
244
+ options.each_with_object({}) do |option, config|
245
+ next unless (value = env["COCOAPODS_GENERATE_#{option.name.upcase}"])
246
+ config[option.name] = option.coerce(value)
247
+ end
248
+ end
249
+
250
+ # @return [Array<String>] errors in the configuration
251
+ #
252
+ def validate
253
+ hash = to_h
254
+ self.class.options.map do |option|
255
+ option.validate(hash[option.name])
256
+ end.compact
257
+ end
258
+
259
+ # @return [Configuration] a new configuration object with the given changes applies
260
+ #
261
+ # @param [Hash<Symbol,Object>] changes
262
+ #
263
+ def with_changes(changes)
264
+ self.class.new(**to_h.merge(changes))
265
+ end
266
+
267
+ # @return [Hash<Symbol,Object>]
268
+ # a hash where the keys are option names and values are the non-nil set values
269
+ #
270
+ def to_h
271
+ self.class.options.each_with_object({}) do |option, hash|
272
+ value = send(option.name)
273
+ next if value.nil?
274
+ hash[option.name] = value
275
+ end
276
+ end
277
+
278
+ # @return [Boolean] whether this configuration is equivalent to other
279
+ #
280
+ def ==(other)
281
+ self.class == other.class &&
282
+ to_h == other.to_h
283
+ end
284
+
285
+ # @return [String] a string describing the configuration, suitable for UI presentation
286
+ #
287
+ def to_s
288
+ hash = to_h
289
+ hash.delete(:pod_config)
290
+ hash.each_with_index.each_with_object('`pod gen` configuration {'.dup) do |((k, v), i), s|
291
+ s << ',' unless i.zero?
292
+ s << "\n" << ' ' << k.to_s << ': ' << v.to_s.gsub(/:0x\h+/, '')
293
+ end << ' }'
294
+ end
295
+
296
+ # @return [Pathname] the directory for installation of the generated workspace
297
+ #
298
+ # @param [String] name the name of the pod
299
+ #
300
+ def gen_dir_for_pod(name)
301
+ gen_directory.join(name)
302
+ end
303
+
304
+ # @return [Boolean] whether gen should install with dynamic frameworks
305
+ #
306
+ def use_frameworks?
307
+ !use_libraries?
308
+ end
309
+
310
+ # @return [Array<Specification>] the podspecs found at the given paths.
311
+ # This method will download specs from URLs and traverse a directory's children.
312
+ #
313
+ # @param [Array<Pathname,URI>] paths
314
+ # the paths to search for podspecs
315
+ #
316
+ def self.podspecs_from_paths(paths)
317
+ paths = [Pathname('.')] if paths.empty?
318
+ paths.flat_map do |path|
319
+ if path.is_a?(URI)
320
+ require 'cocoapods/open-uri'
321
+ begin
322
+ contents = open(path.to_s).read
323
+ rescue StandardError => e
324
+ next e
325
+ end
326
+ begin
327
+ Pod::Specification.from_string contents, path.to_s
328
+ rescue StandardError
329
+ $ERROR_INFO
330
+ end
331
+ elsif path.directory?
332
+ glob = Pathname.glob(path + '*.podspec{.json,}')
333
+ next StandardError.new "no specs found in #{UI.path path}" if glob.empty?
334
+ glob.map { |f| Pod::Specification.from_file(f) }
335
+ else
336
+ Pod::Specification.from_file(path)
337
+ end
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end