xcocoapods 1.5.3

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