xcocoapods 1.5.3

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/CHANGELOG.md +6303 -0
  3. data/LICENSE +28 -0
  4. data/README.md +80 -0
  5. data/bin/pod +56 -0
  6. data/bin/sandbox-pod +168 -0
  7. data/lib/cocoapods.rb +73 -0
  8. data/lib/cocoapods/command.rb +175 -0
  9. data/lib/cocoapods/command/cache.rb +28 -0
  10. data/lib/cocoapods/command/cache/clean.rb +90 -0
  11. data/lib/cocoapods/command/cache/list.rb +69 -0
  12. data/lib/cocoapods/command/env.rb +66 -0
  13. data/lib/cocoapods/command/init.rb +128 -0
  14. data/lib/cocoapods/command/install.rb +45 -0
  15. data/lib/cocoapods/command/ipc.rb +19 -0
  16. data/lib/cocoapods/command/ipc/list.rb +40 -0
  17. data/lib/cocoapods/command/ipc/podfile.rb +31 -0
  18. data/lib/cocoapods/command/ipc/podfile_json.rb +30 -0
  19. data/lib/cocoapods/command/ipc/repl.rb +51 -0
  20. data/lib/cocoapods/command/ipc/spec.rb +29 -0
  21. data/lib/cocoapods/command/ipc/update_search_index.rb +24 -0
  22. data/lib/cocoapods/command/lib.rb +11 -0
  23. data/lib/cocoapods/command/lib/create.rb +105 -0
  24. data/lib/cocoapods/command/lib/lint.rb +121 -0
  25. data/lib/cocoapods/command/list.rb +39 -0
  26. data/lib/cocoapods/command/options/project_directory.rb +36 -0
  27. data/lib/cocoapods/command/options/repo_update.rb +34 -0
  28. data/lib/cocoapods/command/outdated.rb +140 -0
  29. data/lib/cocoapods/command/repo.rb +29 -0
  30. data/lib/cocoapods/command/repo/add.rb +103 -0
  31. data/lib/cocoapods/command/repo/lint.rb +82 -0
  32. data/lib/cocoapods/command/repo/list.rb +93 -0
  33. data/lib/cocoapods/command/repo/push.rb +281 -0
  34. data/lib/cocoapods/command/repo/remove.rb +36 -0
  35. data/lib/cocoapods/command/repo/update.rb +28 -0
  36. data/lib/cocoapods/command/setup.rb +103 -0
  37. data/lib/cocoapods/command/spec.rb +112 -0
  38. data/lib/cocoapods/command/spec/cat.rb +51 -0
  39. data/lib/cocoapods/command/spec/create.rb +283 -0
  40. data/lib/cocoapods/command/spec/edit.rb +87 -0
  41. data/lib/cocoapods/command/spec/env_spec.rb +53 -0
  42. data/lib/cocoapods/command/spec/lint.rb +137 -0
  43. data/lib/cocoapods/command/spec/which.rb +43 -0
  44. data/lib/cocoapods/command/update.rb +101 -0
  45. data/lib/cocoapods/config.rb +347 -0
  46. data/lib/cocoapods/core_overrides.rb +1 -0
  47. data/lib/cocoapods/downloader.rb +190 -0
  48. data/lib/cocoapods/downloader/cache.rb +233 -0
  49. data/lib/cocoapods/downloader/request.rb +86 -0
  50. data/lib/cocoapods/downloader/response.rb +16 -0
  51. data/lib/cocoapods/executable.rb +222 -0
  52. data/lib/cocoapods/external_sources.rb +57 -0
  53. data/lib/cocoapods/external_sources/abstract_external_source.rb +205 -0
  54. data/lib/cocoapods/external_sources/downloader_source.rb +30 -0
  55. data/lib/cocoapods/external_sources/path_source.rb +55 -0
  56. data/lib/cocoapods/external_sources/podspec_source.rb +54 -0
  57. data/lib/cocoapods/gem_version.rb +5 -0
  58. data/lib/cocoapods/generator/acknowledgements.rb +107 -0
  59. data/lib/cocoapods/generator/acknowledgements/markdown.rb +44 -0
  60. data/lib/cocoapods/generator/acknowledgements/plist.rb +94 -0
  61. data/lib/cocoapods/generator/app_target_helper.rb +244 -0
  62. data/lib/cocoapods/generator/bridge_support.rb +22 -0
  63. data/lib/cocoapods/generator/constant.rb +19 -0
  64. data/lib/cocoapods/generator/copy_resources_script.rb +230 -0
  65. data/lib/cocoapods/generator/dummy_source.rb +31 -0
  66. data/lib/cocoapods/generator/embed_frameworks_script.rb +215 -0
  67. data/lib/cocoapods/generator/header.rb +103 -0
  68. data/lib/cocoapods/generator/info_plist_file.rb +116 -0
  69. data/lib/cocoapods/generator/module_map.rb +99 -0
  70. data/lib/cocoapods/generator/prefix_header.rb +60 -0
  71. data/lib/cocoapods/generator/umbrella_header.rb +46 -0
  72. data/lib/cocoapods/hooks_manager.rb +132 -0
  73. data/lib/cocoapods/installer.rb +703 -0
  74. data/lib/cocoapods/installer/analyzer.rb +972 -0
  75. data/lib/cocoapods/installer/analyzer/analysis_result.rb +87 -0
  76. data/lib/cocoapods/installer/analyzer/locking_dependency_analyzer.rb +98 -0
  77. data/lib/cocoapods/installer/analyzer/pod_variant.rb +67 -0
  78. data/lib/cocoapods/installer/analyzer/pod_variant_set.rb +157 -0
  79. data/lib/cocoapods/installer/analyzer/podfile_dependency_cache.rb +54 -0
  80. data/lib/cocoapods/installer/analyzer/sandbox_analyzer.rb +240 -0
  81. data/lib/cocoapods/installer/analyzer/specs_state.rb +84 -0
  82. data/lib/cocoapods/installer/analyzer/target_inspection_result.rb +53 -0
  83. data/lib/cocoapods/installer/analyzer/target_inspector.rb +260 -0
  84. data/lib/cocoapods/installer/installation_options.rb +158 -0
  85. data/lib/cocoapods/installer/pod_source_installer.rb +202 -0
  86. data/lib/cocoapods/installer/pod_source_preparer.rb +77 -0
  87. data/lib/cocoapods/installer/podfile_validator.rb +139 -0
  88. data/lib/cocoapods/installer/post_install_hooks_context.rb +132 -0
  89. data/lib/cocoapods/installer/pre_install_hooks_context.rb +51 -0
  90. data/lib/cocoapods/installer/source_provider_hooks_context.rb +34 -0
  91. data/lib/cocoapods/installer/user_project_integrator.rb +250 -0
  92. data/lib/cocoapods/installer/user_project_integrator/target_integrator.rb +463 -0
  93. data/lib/cocoapods/installer/user_project_integrator/target_integrator/xcconfig_integrator.rb +146 -0
  94. data/lib/cocoapods/installer/xcode.rb +8 -0
  95. data/lib/cocoapods/installer/xcode/pods_project_generator.rb +416 -0
  96. data/lib/cocoapods/installer/xcode/pods_project_generator/aggregate_target_installer.rb +181 -0
  97. data/lib/cocoapods/installer/xcode/pods_project_generator/app_host_installer.rb +84 -0
  98. data/lib/cocoapods/installer/xcode/pods_project_generator/file_references_installer.rb +334 -0
  99. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_installer.rb +777 -0
  100. data/lib/cocoapods/installer/xcode/pods_project_generator/pod_target_integrator.rb +116 -0
  101. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installation_result.rb +86 -0
  102. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer.rb +256 -0
  103. data/lib/cocoapods/installer/xcode/pods_project_generator/target_installer_helper.rb +68 -0
  104. data/lib/cocoapods/installer/xcode/target_validator.rb +147 -0
  105. data/lib/cocoapods/open-uri.rb +33 -0
  106. data/lib/cocoapods/project.rb +414 -0
  107. data/lib/cocoapods/resolver.rb +585 -0
  108. data/lib/cocoapods/resolver/lazy_specification.rb +79 -0
  109. data/lib/cocoapods/sandbox.rb +404 -0
  110. data/lib/cocoapods/sandbox/file_accessor.rb +444 -0
  111. data/lib/cocoapods/sandbox/headers_store.rb +146 -0
  112. data/lib/cocoapods/sandbox/path_list.rb +220 -0
  113. data/lib/cocoapods/sandbox/pod_dir_cleaner.rb +85 -0
  114. data/lib/cocoapods/sandbox/podspec_finder.rb +23 -0
  115. data/lib/cocoapods/sources_manager.rb +157 -0
  116. data/lib/cocoapods/target.rb +261 -0
  117. data/lib/cocoapods/target/aggregate_target.rb +338 -0
  118. data/lib/cocoapods/target/build_settings.rb +1075 -0
  119. data/lib/cocoapods/target/pod_target.rb +559 -0
  120. data/lib/cocoapods/user_interface.rb +459 -0
  121. data/lib/cocoapods/user_interface/error_report.rb +187 -0
  122. data/lib/cocoapods/user_interface/inspector_reporter.rb +109 -0
  123. data/lib/cocoapods/validator.rb +981 -0
  124. metadata +533 -0
@@ -0,0 +1,103 @@
1
+ module Pod
2
+ module Generator
3
+ # Generates a header file.
4
+ #
5
+ # According to the platform the header imports `UIKit/UIKit.h` or
6
+ # `Cocoa/Cocoa.h`.
7
+ #
8
+ class Header
9
+ # @return [Symbol] the platform for which the prefix header will be
10
+ # generated.
11
+ #
12
+ attr_reader :platform
13
+
14
+ # @return [Array<String>] The list of the headers to import.
15
+ #
16
+ attr_accessor :imports
17
+
18
+ # @return [Array<String>] The list of the modules to import.
19
+ #
20
+ attr_reader :module_imports
21
+
22
+ # Initialize a new instance
23
+ #
24
+ # @param [Symbol] platform
25
+ # @see platform
26
+ #
27
+ def initialize(platform)
28
+ @platform = platform
29
+ @imports = []
30
+ @module_imports = []
31
+ end
32
+
33
+ # Generates the contents of the header according to the platform.
34
+ #
35
+ # @note If the platform is iOS an import call to `UIKit/UIKit.h` is
36
+ # added to the top of the prefix header. For OS X `Cocoa/Cocoa.h`
37
+ # is imported.
38
+ #
39
+ # @return [String]
40
+ #
41
+ def generate
42
+ result = ''
43
+ result << "#ifdef __OBJC__\n"
44
+ result << generate_platform_import_header
45
+ result << "#else\n"
46
+ result << "#ifndef FOUNDATION_EXPORT\n"
47
+ result << "#if defined(__cplusplus)\n"
48
+ result << "#define FOUNDATION_EXPORT extern \"C\"\n"
49
+ result << "#else\n"
50
+ result << "#define FOUNDATION_EXPORT extern\n"
51
+ result << "#endif\n"
52
+ result << "#endif\n"
53
+ result << "#endif\n"
54
+ result << "\n"
55
+
56
+ imports.each do |import|
57
+ result << %(#import "#{import}"\n)
58
+ end
59
+
60
+ unless module_imports.empty?
61
+ module_imports.each do |import|
62
+ result << %(\n@import #{import})
63
+ end
64
+ result << "\n"
65
+ end
66
+
67
+ result
68
+ end
69
+
70
+ # Generates and saves the header to the given path.
71
+ #
72
+ # @param [Pathname] path
73
+ # The path where the header should be stored.
74
+ #
75
+ # @return [void]
76
+ #
77
+ def save_as(path)
78
+ path.open('w') { |header| header.write(generate) }
79
+ end
80
+
81
+ #-----------------------------------------------------------------------#
82
+
83
+ protected
84
+
85
+ # Generates the contents of the header according to the platform.
86
+ #
87
+ # @note If the platform is iOS an import call to `UIKit/UIKit.h` is
88
+ # added to the top of the header. For OS X `Cocoa/Cocoa.h` is
89
+ # imported.
90
+ #
91
+ # @return [String]
92
+ #
93
+ def generate_platform_import_header
94
+ case platform.name
95
+ when :ios then "#import <UIKit/UIKit.h>\n"
96
+ when :tvos then "#import <UIKit/UIKit.h>\n"
97
+ when :osx then "#import <Cocoa/Cocoa.h>\n"
98
+ else "#import <Foundation/Foundation.h>\n"
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,116 @@
1
+ module Pod
2
+ module Generator
3
+ # Generates Info.plist files. A Info.plist file is generated for each
4
+ # Pod and for each Pod target definition, that requires to be built as
5
+ # framework. It states public attributes.
6
+ #
7
+ class InfoPlistFile
8
+ # @return [Version] version The version to use for when generating this Info.plist file.
9
+ #
10
+ attr_reader :version
11
+
12
+ # @return [Platform] The platform to use for when generating this Info.plist file.
13
+ #
14
+ attr_reader :platform
15
+
16
+ # @return [Symbol] the CFBundlePackageType of the target this Info.plist
17
+ # file is for.
18
+ #
19
+ attr_reader :bundle_package_type
20
+
21
+ # Initialize a new instance
22
+ #
23
+ # @param [Version] version @see version
24
+ # @param [Platform] platform @see platform
25
+ # @param [Symbol] bundle_package_type @see bundle_package_type
26
+ #
27
+ def initialize(version, platform, bundle_package_type = :fmwk)
28
+ @version = version
29
+ @platform = platform
30
+ @bundle_package_type = bundle_package_type
31
+ end
32
+
33
+ # Generates and saves the Info.plist to the given path.
34
+ #
35
+ # @param [Pathname] path
36
+ # the path where the prefix header should be stored.
37
+ #
38
+ # @return [void]
39
+ #
40
+ def save_as(path)
41
+ contents = generate
42
+ path.open('w') do |f|
43
+ f.write(contents)
44
+ end
45
+ end
46
+
47
+ # Generates the contents of the Info.plist
48
+ #
49
+ # @return [String]
50
+ #
51
+ def generate
52
+ to_plist(info)
53
+ end
54
+
55
+ private
56
+
57
+ def header
58
+ <<-PLIST
59
+ <?xml version="1.0" encoding="UTF-8"?>
60
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
61
+ <plist version="1.0">
62
+ PLIST
63
+ end
64
+
65
+ def footer
66
+ <<-PLIST
67
+ </plist>
68
+ PLIST
69
+ end
70
+
71
+ def to_plist(root)
72
+ serialize(root, header) << footer
73
+ end
74
+
75
+ def serialize(value, output, indentation = 0)
76
+ indent = ' ' * indentation
77
+ case value
78
+ when Array
79
+ output << indent << "<array>\n"
80
+ value.each { |v| serialize(v, output, indentation + 2) }
81
+ output << indent << "</array>\n"
82
+ when Hash
83
+ output << indent << "<dict>\n"
84
+ value.to_a.sort_by(&:first).each do |key, v|
85
+ output << indent << ' ' << "<key>#{key}</key>\n"
86
+ serialize(v, output, indentation + 2)
87
+ end
88
+ output << indent << "</dict>\n"
89
+ when String
90
+ output << indent << "<string>#{value}</string>\n"
91
+ end
92
+ output
93
+ end
94
+
95
+ def info
96
+ info = {
97
+ 'CFBundleIdentifier' => '${PRODUCT_BUNDLE_IDENTIFIER}',
98
+ 'CFBundleInfoDictionaryVersion' => '6.0',
99
+ 'CFBundleName' => '${PRODUCT_NAME}',
100
+ 'CFBundlePackageType' => bundle_package_type.to_s.upcase,
101
+ 'CFBundleShortVersionString' => version,
102
+ 'CFBundleSignature' => '????',
103
+ 'CFBundleVersion' => '${CURRENT_PROJECT_VERSION}',
104
+ 'NSPrincipalClass' => '',
105
+ 'CFBundleDevelopmentRegion' => 'en',
106
+ }
107
+
108
+ info['CFBundleExecutable'] = '${EXECUTABLE_NAME}' if bundle_package_type != :bndl
109
+ info['CFBundleVersion'] = '1' if bundle_package_type == :bndl
110
+ info['NSPrincipalClass'] = 'NSApplication' if bundle_package_type == :appl && platform == :osx
111
+
112
+ info
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,99 @@
1
+ module Pod
2
+ module Generator
3
+ # Generates LLVM module map files. A module map file is generated for each
4
+ # Pod and for each Pod target definition that is built as a framework. It
5
+ # specifies a different umbrella header than usual to avoid name conflicts
6
+ # with existing headers of the podspec.
7
+ #
8
+ class ModuleMap
9
+ # @return [PodTarget, AggregateTarget] the target the module map is generated for.
10
+ #
11
+ attr_reader :target
12
+
13
+ attr_reader :headers
14
+
15
+ Header = Struct.new(:path, :umbrella, :private, :textual, :exclude, :size, :mtime) do
16
+ alias_method :private?, :private
17
+ def to_s
18
+ [
19
+ (:private if private?),
20
+ (:textual if textual),
21
+ (:umbrella if umbrella),
22
+ (:exclude if exclude),
23
+ 'header',
24
+ %("#{path.to_s.gsub('"', '\"')}"),
25
+ attrs,
26
+ ].compact.join(' ')
27
+ end
28
+
29
+ def attrs
30
+ attrs = {
31
+ 'size' => size,
32
+ 'mtime' => mtime,
33
+ }.reject { |_k, v| v.nil? }
34
+ return nil if attrs.empty?
35
+ attrs.to_s
36
+ end
37
+ end
38
+
39
+ # Initialize a new instance
40
+ #
41
+ # @param [PodTarget, AggregateTarget] target @see target
42
+ #
43
+ def initialize(target)
44
+ @target = target
45
+ @headers = [
46
+ Header.new(target.umbrella_header_path.basename, true),
47
+ ]
48
+ end
49
+
50
+ # Generates and saves the Info.plist to the given path.
51
+ #
52
+ # @param [Pathname] path
53
+ # the path where the prefix header should be stored.
54
+ #
55
+ # @return [void]
56
+ #
57
+ def save_as(path)
58
+ contents = generate
59
+ path.open('w') do |f|
60
+ f.write(contents)
61
+ end
62
+ end
63
+
64
+ # Generates the contents of the module.modulemap file.
65
+ #
66
+ # @return [String]
67
+ #
68
+ def generate
69
+ <<-MODULE_MAP.strip_heredoc
70
+ #{module_specifier_prefix}module #{target.product_module_name}#{module_declaration_attributes} {
71
+ #{headers.join("\n ")}
72
+
73
+ export *
74
+ module * { export * }
75
+ }
76
+ MODULE_MAP
77
+ end
78
+
79
+ private
80
+
81
+ # The prefix to `module` to prepend in the module map.
82
+ # Ensures that only framework targets have `framework` prepended.
83
+ #
84
+ def module_specifier_prefix
85
+ if target.requires_frameworks?
86
+ 'framework '
87
+ else
88
+ ''
89
+ end
90
+ end
91
+
92
+ # The suffix attributes to `module`.
93
+ #
94
+ def module_declaration_attributes
95
+ ''
96
+ end
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,60 @@
1
+ module Pod
2
+ module Generator
3
+ # Generates a prefix header file for a Pods library. The prefix header is
4
+ # generated according to the platform of the target and the pods.
5
+ #
6
+ # According to the platform the prefix header imports `UIKit/UIKit.h` or
7
+ # `Cocoa/Cocoa.h`.
8
+ #
9
+ class PrefixHeader < Header
10
+ # @return [Array<FileAccessor>] The file accessors for which to generate
11
+ # the prefix header.
12
+ #
13
+ attr_reader :file_accessors
14
+
15
+ # Initialize a new instance
16
+ #
17
+ # @param [Array<FileAccessor>] file_accessors
18
+ # @see #file_accessors
19
+ #
20
+ # @param [Platform] platform
21
+ # @see Header#platform
22
+ #
23
+ def initialize(file_accessors, platform)
24
+ @file_accessors = file_accessors
25
+ super platform
26
+ end
27
+
28
+ # Generates the contents of the prefix header according to the platform
29
+ # and the pods.
30
+ #
31
+ # @note Only unique prefix_header_contents are added to the prefix
32
+ # header.
33
+ #
34
+ # @return [String]
35
+ #
36
+ # @todo Subspecs can specify prefix header information too.
37
+ # @todo Check to see if we have a similar duplication issue with
38
+ # file_accessor.prefix_header.
39
+ #
40
+ def generate
41
+ result = super
42
+
43
+ unique_prefix_header_contents = file_accessors.map do |file_accessor|
44
+ file_accessor.spec_consumer.prefix_header_contents
45
+ end.compact.uniq
46
+
47
+ unique_prefix_header_contents.each do |prefix_header_contents|
48
+ result << prefix_header_contents
49
+ result << "\n"
50
+ end
51
+
52
+ file_accessors.map(&:prefix_header).compact.uniq.each do |prefix_header|
53
+ result << Pathname(prefix_header).read
54
+ end
55
+
56
+ result
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,46 @@
1
+ module Pod
2
+ module Generator
3
+ # Generates an umbrella header file for clang modules, which are used by
4
+ # dynamic frameworks on iOS 8 and OSX 10.10 under the hood.
5
+ #
6
+ # If the target is a +PodTarget+, then the umbrella header is required
7
+ # to make all public headers in a convenient manner available without the
8
+ # need to write out header declarations for every library header.
9
+ #
10
+ class UmbrellaHeader < Header
11
+ # @return [Target]
12
+ # the target, which provides the product name
13
+ attr_reader :target
14
+
15
+ # Initialize a new instance
16
+ #
17
+ # @param [Target] target
18
+ # @see target
19
+ #
20
+ def initialize(target)
21
+ super(target.platform)
22
+ @target = target
23
+ end
24
+
25
+ # Generates the contents of the umbrella header according to the included
26
+ # pods.
27
+ #
28
+ # @return [String]
29
+ #
30
+ def generate
31
+ result = super
32
+
33
+ result << "\n"
34
+
35
+ result << <<-eos.strip_heredoc
36
+ FOUNDATION_EXPORT double #{target.product_module_name}VersionNumber;
37
+ FOUNDATION_EXPORT const unsigned char #{target.product_module_name}VersionString[];
38
+ eos
39
+
40
+ result << "\n"
41
+
42
+ result
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,132 @@
1
+ require 'active_support/core_ext/hash/indifferent_access'
2
+
3
+ module Pod
4
+ # Provides support for the hook system of CocoaPods. The system is designed
5
+ # especially for plugins. Interested clients can register to notifications by
6
+ # name.
7
+ #
8
+ # The blocks, to prevent compatibility issues, will receive
9
+ # one and only one argument: a context object. This object should be simple
10
+ # storage of information (a typed hash). Notifications senders are
11
+ # responsible to indicate the class of the object associated with their
12
+ # notification name.
13
+ #
14
+ # Context object should not remove attribute accessors to not break
15
+ # compatibility with the plugins (this promise will be honoured strictly
16
+ # from CocoaPods 1.0).
17
+ #
18
+ module HooksManager
19
+ # Represents a single registered hook.
20
+ #
21
+ class Hook
22
+ # @return [String]
23
+ # The name of the plugin that registered the hook.
24
+ #
25
+ attr_reader :plugin_name
26
+
27
+ # @return [String]
28
+ # The name of the hook.
29
+ #
30
+ attr_reader :name
31
+
32
+ # @return [Proc]
33
+ # The block.
34
+ #
35
+ attr_reader :block
36
+
37
+ # Initialize a new instance
38
+ #
39
+ # @param [String] name @see {#name}.
40
+ #
41
+ # @param [String] plugin_name @see {#plugin_name}.
42
+ #
43
+ # @param [Proc] block @see {#block}.
44
+ #
45
+ def initialize(name, plugin_name, block)
46
+ raise ArgumentError, 'Missing name' unless name
47
+ raise ArgumentError, 'Missing plugin_name' unless plugin_name
48
+ raise ArgumentError, 'Missing block' unless block
49
+
50
+ @name = name
51
+ @plugin_name = plugin_name
52
+ @block = block
53
+ end
54
+ end
55
+
56
+ class << self
57
+ # @return [Hash{Symbol => Array<Hook>}] The list of the hooks that are
58
+ # registered for each hook name.
59
+ #
60
+ attr_reader :registrations
61
+
62
+ # Registers a block for the hook with the given name.
63
+ #
64
+ # @param [String] plugin_name
65
+ # The name of the plugin the hook comes from.
66
+ #
67
+ # @param [Symbol] hook_name
68
+ # The name of the notification.
69
+ #
70
+ # @param [Proc] block
71
+ # The block.
72
+ #
73
+ def register(plugin_name, hook_name, &block)
74
+ @registrations ||= {}
75
+ @registrations[hook_name] ||= []
76
+ @registrations[hook_name] << Hook.new(hook_name, plugin_name, block)
77
+ end
78
+
79
+ # Returns all the hooks to run for the given event name
80
+ # and set of whitelisted plugins
81
+ #
82
+ # @see #run
83
+ #
84
+ # @return [Array<Hook>] the hooks to run
85
+ #
86
+ def hooks_to_run(name, whitelisted_plugins = nil)
87
+ return [] unless registrations
88
+ hooks = registrations.fetch(name, [])
89
+ return hooks unless whitelisted_plugins
90
+ hooks.select { |hook| whitelisted_plugins.key?(hook.plugin_name) }
91
+ end
92
+
93
+ # Runs all the registered blocks for the hook with the given name.
94
+ #
95
+ # @param [Symbol] name
96
+ # The name of the hook.
97
+ #
98
+ # @param [Object] context
99
+ # The context object which should be passed to the blocks.
100
+ #
101
+ # @param [Hash<String, Hash>] whitelisted_plugins
102
+ # The plugins that should be run, in the form of a hash keyed by
103
+ # plugin name, where the values are the custom options that should
104
+ # be passed to the hook's block if it supports taking a second
105
+ # argument.
106
+ #
107
+ def run(name, context, whitelisted_plugins = nil)
108
+ raise ArgumentError, 'Missing name' unless name
109
+ raise ArgumentError, 'Missing options' unless context
110
+
111
+ hooks = hooks_to_run(name, whitelisted_plugins)
112
+ return if hooks.empty?
113
+
114
+ UI.message "- Running #{name.to_s.tr('_', ' ')} hooks" do
115
+ hooks.each do |hook|
116
+ UI.message "- #{hook.plugin_name} from " \
117
+ "`#{hook.block.source_location.first}`" do
118
+ block = hook.block
119
+ if block.arity > 1
120
+ user_options = whitelisted_plugins[hook.plugin_name]
121
+ user_options = user_options.with_indifferent_access if user_options
122
+ block.call(context, user_options)
123
+ else
124
+ block.call(context)
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end