cocoapods-tt 0.0.1

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 (124) hide show
  1. checksums.yaml +7 -0
  2. data/lib/cocoapods-tt/command/native/install.rb +56 -0
  3. data/lib/cocoapods-tt/command/native/update.rb +157 -0
  4. data/lib/cocoapods-tt/command/tt/make.rb +92 -0
  5. data/lib/cocoapods-tt/command/tt.rb +115 -0
  6. data/lib/cocoapods-tt/command.rb +1 -0
  7. data/lib/cocoapods-tt/gem_version.rb +3 -0
  8. data/lib/cocoapods-tt/native/command.rb +185 -0
  9. data/lib/cocoapods-tt/native/config.rb +366 -0
  10. data/lib/cocoapods-tt/native/core_overrides.rb +1 -0
  11. data/lib/cocoapods-tt/native/downloader/cache.rb +322 -0
  12. data/lib/cocoapods-tt/native/downloader/request.rb +86 -0
  13. data/lib/cocoapods-tt/native/downloader/response.rb +16 -0
  14. data/lib/cocoapods-tt/native/downloader.rb +192 -0
  15. data/lib/cocoapods-tt/native/executable.rb +247 -0
  16. data/lib/cocoapods-tt/native/external_sources/abstract_external_source.rb +205 -0
  17. data/lib/cocoapods-tt/native/external_sources/downloader_source.rb +30 -0
  18. data/lib/cocoapods-tt/native/external_sources/path_source.rb +55 -0
  19. data/lib/cocoapods-tt/native/external_sources/podspec_source.rb +54 -0
  20. data/lib/cocoapods-tt/native/external_sources.rb +57 -0
  21. data/lib/cocoapods-tt/native/gem_version.rb +5 -0
  22. data/lib/cocoapods-tt/native/generator/acknowledgements/markdown.rb +44 -0
  23. data/lib/cocoapods-tt/native/generator/acknowledgements/plist.rb +94 -0
  24. data/lib/cocoapods-tt/native/generator/acknowledgements.rb +107 -0
  25. data/lib/cocoapods-tt/native/generator/app_target_helper.rb +363 -0
  26. data/lib/cocoapods-tt/native/generator/bridge_support.rb +22 -0
  27. data/lib/cocoapods-tt/native/generator/constant.rb +19 -0
  28. data/lib/cocoapods-tt/native/generator/copy_dsyms_script.rb +56 -0
  29. data/lib/cocoapods-tt/native/generator/copy_resources_script.rb +223 -0
  30. data/lib/cocoapods-tt/native/generator/copy_xcframework_script.rb +227 -0
  31. data/lib/cocoapods-tt/native/generator/dummy_source.rb +31 -0
  32. data/lib/cocoapods-tt/native/generator/embed_frameworks_script.rb +196 -0
  33. data/lib/cocoapods-tt/native/generator/file_list.rb +39 -0
  34. data/lib/cocoapods-tt/native/generator/header.rb +103 -0
  35. data/lib/cocoapods-tt/native/generator/info_plist_file.rb +128 -0
  36. data/lib/cocoapods-tt/native/generator/module_map.rb +99 -0
  37. data/lib/cocoapods-tt/native/generator/prefix_header.rb +60 -0
  38. data/lib/cocoapods-tt/native/generator/script_phase_constants.rb +100 -0
  39. data/lib/cocoapods-tt/native/generator/umbrella_header.rb +46 -0
  40. data/lib/cocoapods-tt/native/hooks_manager.rb +132 -0
  41. data/lib/cocoapods-tt/native/installer/analyzer/analysis_result.rb +87 -0
  42. data/lib/cocoapods-tt/native/installer/analyzer/locking_dependency_analyzer.rb +103 -0
  43. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant.rb +87 -0
  44. data/lib/cocoapods-tt/native/installer/analyzer/pod_variant_set.rb +175 -0
  45. data/lib/cocoapods-tt/native/installer/analyzer/podfile_dependency_cache.rb +55 -0
  46. data/lib/cocoapods-tt/native/installer/analyzer/sandbox_analyzer.rb +268 -0
  47. data/lib/cocoapods-tt/native/installer/analyzer/specs_state.rb +108 -0
  48. data/lib/cocoapods-tt/native/installer/analyzer/target_inspection_result.rb +58 -0
  49. data/lib/cocoapods-tt/native/installer/analyzer/target_inspector.rb +258 -0
  50. data/lib/cocoapods-tt/native/installer/analyzer.rb +1204 -0
  51. data/lib/cocoapods-tt/native/installer/base_install_hooks_context.rb +135 -0
  52. data/lib/cocoapods-tt/native/installer/installation_options.rb +195 -0
  53. data/lib/cocoapods-tt/native/installer/pod_source_installer.rb +224 -0
  54. data/lib/cocoapods-tt/native/installer/pod_source_preparer.rb +77 -0
  55. data/lib/cocoapods-tt/native/installer/podfile_validator.rb +168 -0
  56. data/lib/cocoapods-tt/native/installer/post_install_hooks_context.rb +9 -0
  57. data/lib/cocoapods-tt/native/installer/post_integrate_hooks_context.rb +9 -0
  58. data/lib/cocoapods-tt/native/installer/pre_install_hooks_context.rb +51 -0
  59. data/lib/cocoapods-tt/native/installer/pre_integrate_hooks_context.rb +9 -0
  60. data/lib/cocoapods-tt/native/installer/project_cache/project_cache.rb +11 -0
  61. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analysis_result.rb +53 -0
  62. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_analyzer.rb +200 -0
  63. data/lib/cocoapods-tt/native/installer/project_cache/project_cache_version.rb +43 -0
  64. data/lib/cocoapods-tt/native/installer/project_cache/project_installation_cache.rb +103 -0
  65. data/lib/cocoapods-tt/native/installer/project_cache/project_metadata_cache.rb +73 -0
  66. data/lib/cocoapods-tt/native/installer/project_cache/target_cache_key.rb +176 -0
  67. data/lib/cocoapods-tt/native/installer/project_cache/target_metadata.rb +74 -0
  68. data/lib/cocoapods-tt/native/installer/sandbox_dir_cleaner.rb +105 -0
  69. data/lib/cocoapods-tt/native/installer/sandbox_header_paths_installer.rb +45 -0
  70. data/lib/cocoapods-tt/native/installer/source_provider_hooks_context.rb +34 -0
  71. data/lib/cocoapods-tt/native/installer/target_uuid_generator.rb +34 -0
  72. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +179 -0
  73. data/lib/cocoapods-tt/native/installer/user_project_integrator/target_integrator.rb +815 -0
  74. data/lib/cocoapods-tt/native/installer/user_project_integrator.rb +280 -0
  75. data/lib/cocoapods-tt/native/installer/xcode/multi_pods_project_generator.rb +82 -0
  76. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_dependency_installer.rb +66 -0
  77. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/aggregate_target_installer.rb +192 -0
  78. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/app_host_installer.rb +154 -0
  79. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/file_references_installer.rb +329 -0
  80. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_dependency_installer.rb +195 -0
  81. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_installer.rb +1239 -0
  82. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pod_target_integrator.rb +312 -0
  83. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/pods_project_writer.rb +90 -0
  84. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/project_generator.rb +120 -0
  85. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installation_result.rb +140 -0
  86. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer.rb +257 -0
  87. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator/target_installer_helper.rb +110 -0
  88. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator.rb +291 -0
  89. data/lib/cocoapods-tt/native/installer/xcode/pods_project_generator_result.rb +54 -0
  90. data/lib/cocoapods-tt/native/installer/xcode/single_pods_project_generator.rb +38 -0
  91. data/lib/cocoapods-tt/native/installer/xcode/target_validator.rb +170 -0
  92. data/lib/cocoapods-tt/native/installer/xcode.rb +11 -0
  93. data/lib/cocoapods-tt/native/installer.rb +1044 -0
  94. data/lib/cocoapods-tt/native/native_target_extension.rb +60 -0
  95. data/lib/cocoapods-tt/native/open-uri.rb +33 -0
  96. data/lib/cocoapods-tt/native/podfile.rb +13 -0
  97. data/lib/cocoapods-tt/native/project.rb +544 -0
  98. data/lib/cocoapods-tt/native/resolver/lazy_specification.rb +88 -0
  99. data/lib/cocoapods-tt/native/resolver/resolver_specification.rb +41 -0
  100. data/lib/cocoapods-tt/native/resolver.rb +600 -0
  101. data/lib/cocoapods-tt/native/sandbox/file_accessor.rb +532 -0
  102. data/lib/cocoapods-tt/native/sandbox/headers_store.rb +163 -0
  103. data/lib/cocoapods-tt/native/sandbox/path_list.rb +242 -0
  104. data/lib/cocoapods-tt/native/sandbox/pod_dir_cleaner.rb +71 -0
  105. data/lib/cocoapods-tt/native/sandbox/podspec_finder.rb +23 -0
  106. data/lib/cocoapods-tt/native/sandbox.rb +470 -0
  107. data/lib/cocoapods-tt/native/sources_manager.rb +221 -0
  108. data/lib/cocoapods-tt/native/target/aggregate_target.rb +558 -0
  109. data/lib/cocoapods-tt/native/target/build_settings.rb +1385 -0
  110. data/lib/cocoapods-tt/native/target/pod_target.rb +1168 -0
  111. data/lib/cocoapods-tt/native/target.rb +378 -0
  112. data/lib/cocoapods-tt/native/user_interface/error_report.rb +204 -0
  113. data/lib/cocoapods-tt/native/user_interface/inspector_reporter.rb +102 -0
  114. data/lib/cocoapods-tt/native/user_interface.rb +463 -0
  115. data/lib/cocoapods-tt/native/validator.rb +1170 -0
  116. data/lib/cocoapods-tt/native/version_metadata.rb +26 -0
  117. data/lib/cocoapods-tt/native/xcode/framework_paths.rb +54 -0
  118. data/lib/cocoapods-tt/native/xcode/linkage_analyzer.rb +22 -0
  119. data/lib/cocoapods-tt/native/xcode/xcframework/xcframework_slice.rb +138 -0
  120. data/lib/cocoapods-tt/native/xcode/xcframework.rb +99 -0
  121. data/lib/cocoapods-tt/native/xcode.rb +7 -0
  122. data/lib/cocoapods-tt.rb +1 -0
  123. data/lib/cocoapods_plugin.rb +17 -0
  124. metadata +193 -0
@@ -0,0 +1,378 @@
1
+ require 'cocoapods/target/build_settings'
2
+
3
+ module Pod
4
+ # Model class which describes a Pods target.
5
+ #
6
+ # The Target class stores and provides the information necessary for
7
+ # working with a target in the Podfile and its dependent libraries.
8
+ # This class is used to represent both the targets and their libraries.
9
+ #
10
+ class Target
11
+ DEFAULT_VERSION = '1.0.0'.freeze
12
+ DEFAULT_NAME = 'Default'.freeze
13
+ DEFAULT_BUILD_CONFIGURATIONS = { 'Release' => :release, 'Debug' => :debug }.freeze
14
+
15
+ # @return [Sandbox] The sandbox where the Pods should be installed.
16
+ #
17
+ attr_reader :sandbox
18
+
19
+ # @return [Hash{String=>Symbol}] A hash representing the user build
20
+ # configurations where each key corresponds to the name of a
21
+ # configuration and its value to its type (`:debug` or `:release`).
22
+ #
23
+ attr_reader :user_build_configurations
24
+
25
+ # @return [Array<String>] The value for the ARCHS build setting.
26
+ #
27
+ attr_reader :archs
28
+
29
+ # @return [Platform] the platform of this target.
30
+ #
31
+ attr_reader :platform
32
+
33
+ # @return [BuildSettings] the build settings for this target.
34
+ #
35
+ attr_reader :build_settings
36
+
37
+ # @return [BuildType] the build type for this target.
38
+ #
39
+ attr_reader :build_type
40
+ private :build_type
41
+
42
+ # @return [Boolean] whether the target can be linked to app extensions only.
43
+ #
44
+ attr_reader :application_extension_api_only
45
+
46
+ # @return [Boolean] whether the target must be compiled with Swift's library
47
+ # evolution support, necessary for XCFrameworks.
48
+ #
49
+ attr_reader :build_library_for_distribution
50
+
51
+ # Initialize a new target
52
+ #
53
+ # @param [Sandbox] sandbox @see #sandbox
54
+ # @param [BuildType] build_type @see #build_type
55
+ # @param [Hash{String=>Symbol}] user_build_configurations @see #user_build_configurations
56
+ # @param [Array<String>] archs @see #archs
57
+ # @param [Platform] platform @see #platform
58
+ #
59
+ def initialize(sandbox, build_type, user_build_configurations, archs, platform)
60
+ @sandbox = sandbox
61
+ @user_build_configurations = user_build_configurations
62
+ @archs = archs
63
+ @platform = platform
64
+ @build_type = build_type
65
+
66
+ @application_extension_api_only = false
67
+ @build_library_for_distribution = false
68
+ @build_settings = create_build_settings
69
+ end
70
+
71
+ # @return [String] the name of the library.
72
+ #
73
+ def name
74
+ label
75
+ end
76
+
77
+ alias to_s name
78
+
79
+ # @return [String] the label for the target.
80
+ #
81
+ def label
82
+ DEFAULT_NAME
83
+ end
84
+
85
+ # @return [String] The version associated with this target
86
+ #
87
+ def version
88
+ DEFAULT_VERSION
89
+ end
90
+
91
+ # @return [Boolean] Whether the target uses Swift code
92
+ #
93
+ def uses_swift?
94
+ false
95
+ end
96
+
97
+ # @return [Boolean] whether the target is built dynamically
98
+ #
99
+ def build_as_dynamic?
100
+ build_type.dynamic?
101
+ end
102
+
103
+ # @return [Boolean] whether the target is built as a dynamic framework
104
+ #
105
+ def build_as_dynamic_framework?
106
+ build_type.dynamic_framework?
107
+ end
108
+
109
+ # @return [Boolean] whether the target is built as a dynamic library
110
+ #
111
+ def build_as_dynamic_library?
112
+ build_type.dynamic_library?
113
+ end
114
+
115
+ # @return [Boolean] whether the target is built as a framework
116
+ #
117
+ def build_as_framework?
118
+ build_type.framework?
119
+ end
120
+
121
+ # @return [Boolean] whether the target is built as a library
122
+ #
123
+ def build_as_library?
124
+ build_type.library?
125
+ end
126
+
127
+ # @return [Boolean] whether the target is built statically
128
+ #
129
+ def build_as_static?
130
+ build_type.static?
131
+ end
132
+
133
+ # @return [Boolean] whether the target is built as a static framework
134
+ #
135
+ def build_as_static_framework?
136
+ build_type.static_framework?
137
+ end
138
+
139
+ # @return [Boolean] whether the target is built as a static library
140
+ #
141
+ def build_as_static_library?
142
+ build_type.static_library?
143
+ end
144
+
145
+ # @deprecated Prefer {build_as_static_framework?}.
146
+ #
147
+ # @return [Boolean] Whether the target should build a static framework.
148
+ #
149
+ def static_framework?
150
+ build_as_static_framework?
151
+ end
152
+
153
+ # @return [String] the name to use for the source code module constructed
154
+ # for this target, and which will be used to import the module in
155
+ # implementation source files.
156
+ #
157
+ def product_module_name
158
+ c99ext_identifier(label)
159
+ end
160
+
161
+ # @return [String] the name of the product.
162
+ #
163
+ def product_name
164
+ if build_as_framework?
165
+ framework_name
166
+ else
167
+ static_library_name
168
+ end
169
+ end
170
+
171
+ # @return [String] the name of the product excluding the file extension or
172
+ # a product type specific prefix, depends on #requires_frameworks?
173
+ # and #product_module_name or #label.
174
+ #
175
+ def product_basename
176
+ if build_as_framework?
177
+ product_module_name
178
+ else
179
+ label
180
+ end
181
+ end
182
+
183
+ # @return [String] the name of the framework, depends on #label.
184
+ #
185
+ # @note This may not depend on #requires_frameworks? indirectly as it is
186
+ # used for migration.
187
+ #
188
+ def framework_name
189
+ "#{product_module_name}.framework"
190
+ end
191
+
192
+ # @return [String] the name of the library, depends on #label.
193
+ #
194
+ # @note This may not depend on #requires_frameworks? indirectly as it is
195
+ # used for migration.
196
+ #
197
+ def static_library_name
198
+ "lib#{label}.a"
199
+ end
200
+
201
+ # @return [Symbol] either :framework or :static_library, depends on
202
+ # #build_as_framework?.
203
+ #
204
+ def product_type
205
+ build_as_framework? ? :framework : :static_library
206
+ end
207
+
208
+ # @return [String] A string suitable for debugging.
209
+ #
210
+ def inspect
211
+ "#<#{self.class} name=#{name}>"
212
+ end
213
+
214
+ #-------------------------------------------------------------------------#
215
+
216
+ # @!group Framework support
217
+
218
+ # @deprecated Prefer {build_as_framework?}.
219
+ #
220
+ # @return [Boolean] whether the generated target needs to be implemented
221
+ # as a framework
222
+ #
223
+ def requires_frameworks?
224
+ build_as_framework?
225
+ end
226
+
227
+ #-------------------------------------------------------------------------#
228
+
229
+ # @!group Support files
230
+
231
+ # @return [Pathname] the folder where to store the support files of this
232
+ # library.
233
+ #
234
+ def support_files_dir
235
+ sandbox.target_support_files_dir(name)
236
+ end
237
+
238
+ # @param [String] variant
239
+ # The variant of the xcconfig. Used to differentiate build
240
+ # configurations.
241
+ #
242
+ # @return [Pathname] the absolute path of the xcconfig file.
243
+ #
244
+ def xcconfig_path(variant = nil)
245
+ if variant
246
+ support_files_dir + "#{label}.#{variant.to_s.gsub(File::SEPARATOR, '-').downcase}.xcconfig"
247
+ else
248
+ support_files_dir + "#{label}.xcconfig"
249
+ end
250
+ end
251
+
252
+ # @return [Pathname] the absolute path of the header file which contains
253
+ # the exported foundation constants with framework version
254
+ # information and all headers, which should been exported in the
255
+ # module map.
256
+ #
257
+ def umbrella_header_path
258
+ module_map_path.parent + "#{label}-umbrella.h"
259
+ end
260
+
261
+ def umbrella_header_path_to_write
262
+ module_map_path_to_write.parent + "#{label}-umbrella.h"
263
+ end
264
+
265
+ # @return [Pathname] the absolute path of the LLVM module map file that
266
+ # defines the module structure for the compiler.
267
+ #
268
+ def module_map_path
269
+ module_map_path_to_write
270
+ end
271
+
272
+ # @!private
273
+ #
274
+ # @return [Pathname] the absolute path of the module map file that
275
+ # CocoaPods writes. This can be different from `module_map_path`
276
+ # if the module map gets symlinked.
277
+ #
278
+ def module_map_path_to_write
279
+ basename = "#{label}.modulemap"
280
+ support_files_dir + basename
281
+ end
282
+
283
+ # @return [Pathname] the absolute path of the bridge support file.
284
+ #
285
+ def bridge_support_path
286
+ support_files_dir + "#{label}.bridgesupport"
287
+ end
288
+
289
+ # @return [Pathname] the absolute path of the Info.plist file.
290
+ #
291
+ def info_plist_path
292
+ support_files_dir + "#{label}-Info.plist"
293
+ end
294
+
295
+ # @return [Hash] additional entries for the generated Info.plist
296
+ #
297
+ def info_plist_entries
298
+ {}
299
+ end
300
+
301
+ # @return [Pathname] the path of the dummy source generated by CocoaPods
302
+ #
303
+ def dummy_source_path
304
+ support_files_dir + "#{label}-dummy.m"
305
+ end
306
+
307
+ # Mark the target as extension-only.
308
+ # Translates to APPLICATION_EXTENSION_API_ONLY = YES in the build settings.
309
+ #
310
+ def mark_application_extension_api_only
311
+ @application_extension_api_only = true
312
+ end
313
+
314
+ # Compiles the target with Swift's library evolution support, necessary to
315
+ # build XCFrameworks.
316
+ # Translates to BUILD_LIBRARY_FOR_DISTRIBUTION = YES in the build settings.
317
+ #
318
+ def mark_build_library_for_distribution
319
+ @build_library_for_distribution = true
320
+ end
321
+
322
+ # @return [Pathname] The absolute path of the prepare artifacts script.
323
+ #
324
+ # @deprecated
325
+ #
326
+ # @todo Remove in 2.0
327
+ #
328
+ def prepare_artifacts_script_path
329
+ support_files_dir + "#{label}-artifacts.sh"
330
+ end
331
+
332
+ # Returns an extension in the target that corresponds to the
333
+ # resource's input extension.
334
+ #
335
+ # @param [String] input_extension
336
+ # The input extension to map to.
337
+ #
338
+ # @return [String] The output extension.
339
+ #
340
+ def self.output_extension_for_resource(input_extension)
341
+ case input_extension
342
+ when '.storyboard' then '.storyboardc'
343
+ when '.xib' then '.nib'
344
+ when '.xcdatamodel' then '.mom'
345
+ when '.xcdatamodeld' then '.momd'
346
+ when '.xcmappingmodel' then '.cdm'
347
+ when '.xcassets' then '.car'
348
+ else input_extension
349
+ end
350
+ end
351
+
352
+ def self.resource_extension_compilable?(input_extension)
353
+ output_extension_for_resource(input_extension) != input_extension && input_extension != '.xcassets'
354
+ end
355
+
356
+ #-------------------------------------------------------------------------#
357
+
358
+ private
359
+
360
+ # Transforms the given string into a valid +identifier+ after C99ext
361
+ # standard, so that it can be used in source code where escaping of
362
+ # ambiguous characters is not applicable.
363
+ #
364
+ # @param [String] name
365
+ # any name, which may contain leading numbers, spaces or invalid
366
+ # characters.
367
+ #
368
+ # @return [String]
369
+ #
370
+ def c99ext_identifier(name)
371
+ name.gsub(/^([0-9])/, '_\1').gsub(/[^a-zA-Z0-9_]/, '_')
372
+ end
373
+
374
+ def create_build_settings
375
+ BuildSettings.new(self)
376
+ end
377
+ end
378
+ end
@@ -0,0 +1,204 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'rbconfig'
4
+ require 'cgi'
5
+ require 'gh_inspector'
6
+
7
+ module Pod
8
+ module UserInterface
9
+ module ErrorReport
10
+ class << self
11
+ def report(exception)
12
+ <<-EOS
13
+
14
+ #{'――― MARKDOWN TEMPLATE ―――――――――――――――――――――――――――――――――――――――――――――――――――――――――――'.reversed}
15
+
16
+ ### Command
17
+
18
+ ```
19
+ #{original_command}
20
+ ```
21
+
22
+ #{report_instructions}
23
+
24
+ #{stack}
25
+ ### Plugins
26
+
27
+ ```
28
+ #{plugins_string}
29
+ ```
30
+ #{markdown_podfile}
31
+ ### Error
32
+
33
+ ```
34
+ #{exception.class} - #{exception.message.force_encoding('UTF-8')}
35
+ #{exception.backtrace.join("\n") if exception.backtrace}
36
+ ```
37
+
38
+ #{'――― TEMPLATE END ――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――'.reversed}
39
+
40
+ #{'[!] Oh no, an error occurred.'.red}
41
+ #{error_from_podfile(exception)}
42
+ #{'Search for existing GitHub issues similar to yours:'.yellow}
43
+ #{issues_url(exception)}
44
+
45
+ #{'If none exists, create a ticket, with the template displayed above, on:'.yellow}
46
+ https://github.com/CocoaPods/CocoaPods/issues/new
47
+
48
+ #{'Be sure to first read the contributing guide for details on how to properly submit a ticket:'.yellow}
49
+ https://github.com/CocoaPods/CocoaPods/blob/master/CONTRIBUTING.md
50
+
51
+ Don't forget to anonymize any private data!
52
+
53
+ EOS
54
+ end
55
+
56
+ def report_instructions
57
+ <<-EOS
58
+ ### Report
59
+
60
+ * What did you do?
61
+
62
+ * What did you expect to happen?
63
+
64
+ * What happened instead?
65
+ EOS
66
+ end
67
+
68
+ def stack
69
+ parts = {
70
+ 'CocoaPods' => Pod::VERSION,
71
+ 'Ruby' => RUBY_DESCRIPTION,
72
+ 'RubyGems' => Gem::VERSION,
73
+ 'Host' => host_information,
74
+ 'Xcode' => xcode_information,
75
+ 'Git' => git_information,
76
+ 'Ruby lib dir' => RbConfig::CONFIG['libdir'],
77
+ 'Repositories' => repo_information,
78
+ }
79
+ justification = parts.keys.map(&:size).max
80
+
81
+ str = <<-EOS
82
+ ### Stack
83
+
84
+ ```
85
+ EOS
86
+ parts.each do |name, value|
87
+ str << name.rjust(justification)
88
+ str << ' : '
89
+ str << Array(value).join("\n" << (' ' * (justification + 3)))
90
+ str << "\n"
91
+ end
92
+
93
+ str << "```\n"
94
+ end
95
+
96
+ def plugins_string
97
+ plugins = installed_plugins
98
+ max_name_length = plugins.keys.map(&:length).max
99
+ plugins.map do |name, version|
100
+ "#{name.ljust(max_name_length)} : #{version}"
101
+ end.sort.join("\n")
102
+ end
103
+
104
+ def markdown_podfile
105
+ return '' unless Config.instance.podfile_path && Config.instance.podfile_path.exist?
106
+ <<-EOS
107
+
108
+ ### Podfile
109
+
110
+ ```ruby
111
+ #{Config.instance.podfile_path.read.strip}
112
+ ```
113
+ EOS
114
+ end
115
+
116
+ def search_for_exceptions(exception)
117
+ inspector = GhInspector::Inspector.new 'cocoapods', 'cocoapods'
118
+ message_delegate = UserInterface::InspectorReporter.new
119
+ inspector.search_exception exception, message_delegate
120
+ rescue => e
121
+ warn "Searching for inspections failed: #{e}"
122
+ nil
123
+ end
124
+
125
+ private
126
+
127
+ def `(other)
128
+ super
129
+ rescue Errno::ENOENT => e
130
+ "Unable to find an executable (#{e})"
131
+ end
132
+
133
+ def pathless_exception_message(message)
134
+ message.gsub(/- \(.*\):/, '-')
135
+ end
136
+
137
+ def error_from_podfile(error)
138
+ if error.message =~ /Podfile:(\d*)/
139
+ "\nIt appears to have originated from your Podfile at line #{Regexp.last_match[1]}.\n"
140
+ end
141
+ end
142
+
143
+ def remove_color(string)
144
+ string.gsub(/\e\[(\d+)m/, '')
145
+ end
146
+
147
+ def issues_url(exception)
148
+ message = remove_color(pathless_exception_message(exception.message))
149
+ 'https://github.com/CocoaPods/CocoaPods/search?q=' \
150
+ "#{CGI.escape(message)}&type=Issues"
151
+ end
152
+
153
+ def host_information
154
+ product, version, build = `sw_vers`.strip.split("\n").map { |line| line.split(':').last.strip }
155
+ "#{product} #{version} (#{build})"
156
+ end
157
+
158
+ def xcode_information
159
+ version, build = `xcodebuild -version`.strip.split("\n").map { |line| line.split(' ').last }
160
+ "#{version} (#{build})"
161
+ end
162
+
163
+ def git_information
164
+ `git --version`.strip.split("\n").first
165
+ end
166
+
167
+ def installed_plugins
168
+ CLAide::Command::PluginManager.specifications.
169
+ reduce({}) { |hash, s| hash.tap { |h| h[s.name] = s.version.to_s } }
170
+ end
171
+
172
+ def repo_information
173
+ Config.instance.sources_manager.all.map do |source|
174
+ repo = source.repo
175
+ if source.is_a?(Pod::CDNSource)
176
+ "#{repo.basename} - CDN - #{source.url}"
177
+ elsif source.git?
178
+ sha = git_hash(source)
179
+ "#{repo.basename} - git - #{source.url} @ #{sha}"
180
+ else
181
+ "#{repo.basename} - #{source.type}"
182
+ end
183
+ end
184
+ end
185
+
186
+ def original_command
187
+ "#{$PROGRAM_NAME} #{ARGV.join(' ')}"
188
+ end
189
+
190
+ private
191
+
192
+ # @param [Source] source
193
+ # a git source
194
+ #
195
+ # @return [String] the current git SHA
196
+ def git_hash(source)
197
+ Dir.chdir(source.repo) do
198
+ `git rev-parse HEAD 2>&1`
199
+ end
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
@@ -0,0 +1,102 @@
1
+ require 'addressable'
2
+ require 'uri'
3
+
4
+ module Pod
5
+ module UserInterface
6
+ # Redirects GH-issues delegate callbacks to CocoaPods UI methods.
7
+ #
8
+ class InspectorReporter
9
+ # Called just as the investigation has begun.
10
+ # Lets the user know that it's looking for an issue.
11
+ #
12
+ # @param [GhInspector::Inspector] inspector
13
+ # The current inspector
14
+ #
15
+ # @return [void]
16
+ #
17
+ def inspector_started_query(_, inspector)
18
+ UI.puts "Looking for related issues on #{inspector.repo_owner}/#{inspector.repo_name}..."
19
+ end
20
+
21
+ # Called once the inspector has received a report with more than one issue,
22
+ # showing the top 3 issues, and offering a link to see more.
23
+ #
24
+ # @param [GhInspector::InspectionReport] report
25
+ # Report a list of the issues
26
+ #
27
+ # @return [void]
28
+ #
29
+ def inspector_successfully_received_report(report, _)
30
+ report.issues[0..2].each { |issue| print_issue_full(issue) }
31
+
32
+ if report.issues.count > 3
33
+ UI.puts "and #{report.total_results - 3} more at:"
34
+ UI.puts report.url
35
+ end
36
+ end
37
+
38
+ # Called once the report has been received, but when there are no issues found.
39
+ #
40
+ # @param [GhInspector::Inspector] inspector
41
+ # The current inspector
42
+ #
43
+ # @return [void]
44
+ #
45
+ def inspector_received_empty_report(_, inspector)
46
+ UI.puts 'Found no similar issues. To create a new issue, please visit:'
47
+ UI.puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/issues/new"
48
+ end
49
+
50
+ # Called when there have been networking issues in creating the report.
51
+ #
52
+ # @param [Error] error
53
+ # The error returned during networking
54
+ #
55
+ # @param [String] query
56
+ # The original search query
57
+ #
58
+ # @param [GhInspector::Inspector] inspector
59
+ # The current inspector
60
+ #
61
+ # @return [void]
62
+ #
63
+ def inspector_could_not_create_report(error, query, inspector)
64
+ safe_query = Addressable::URI.escape query
65
+ UI.puts 'Could not access the GitHub API, you may have better luck via the website.'
66
+ UI.puts "https://github.com/#{inspector.repo_owner}/#{inspector.repo_name}/search?q=#{safe_query}&type=Issues&utf8=✓"
67
+ UI.puts "Error: #{error.name}"
68
+ end
69
+
70
+ private
71
+
72
+ def print_issue_full(issue)
73
+ safe_url = Addressable::URI.escape issue.html_url
74
+ UI.puts " - #{issue.title}"
75
+ UI.puts " #{safe_url} [#{issue.state}] [#{issue.comments} comment#{issue.comments == 1 ? '' : 's'}]"
76
+ UI.puts " #{pretty_date(issue.updated_at)}"
77
+ UI.puts ''
78
+ end
79
+
80
+ # Taken from https://stackoverflow.com/questions/195740/how-do-you-do-relative-time-in-rails
81
+ def pretty_date(date_string)
82
+ date = Time.parse(date_string)
83
+ a = (Time.now - date).to_i
84
+
85
+ case a
86
+ when 0 then 'just now'
87
+ when 1 then 'a second ago'
88
+ when 2..59 then a.to_s + ' seconds ago'
89
+ when 60..119 then 'a minute ago' # 120 = 2 minutes
90
+ when 120..3540 then (a / 60).to_i.to_s + ' minutes ago'
91
+ when 3541..7100 then 'an hour ago' # 3600 = 1 hour
92
+ when 7101..82_800 then ((a + 99) / 3600).to_i.to_s + ' hours ago'
93
+ when 82_801..172_000 then 'a day ago' # 86400 = 1 day
94
+ when 172_001..518_400 then ((a + 800) / (60 * 60 * 24)).to_i.to_s + ' days ago'
95
+ when 518_400..1_036_800 then 'a week ago'
96
+ when 1_036_801..4_147_204 then ((a + 180_000) / (60 * 60 * 24 * 7)).to_i.to_s + ' weeks ago'
97
+ else date.strftime('%d %b %Y')
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end