buildpack-support 1.0.0

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 (122) hide show
  1. data/LICENSE +202 -0
  2. data/NOTICE +2 -0
  3. data/docs/cache.md +77 -0
  4. data/docs/component.md +1 -0
  5. data/docs/configuration.md +27 -0
  6. data/docs/logging.md +54 -0
  7. data/docs/other.md +1 -0
  8. data/docs/rake.md +1 -0
  9. data/docs/repository.md +116 -0
  10. data/docs/test.md +1 -0
  11. data/lib/buildpack_support.rb +18 -0
  12. data/lib/buildpack_support/base_buildpack.rb +166 -0
  13. data/lib/buildpack_support/buildpack_version.rb +124 -0
  14. data/lib/buildpack_support/cache.rb +24 -0
  15. data/lib/buildpack_support/cache/application_cache.rb +41 -0
  16. data/lib/buildpack_support/cache/cached_file.rb +103 -0
  17. data/lib/buildpack_support/cache/download_cache.rb +280 -0
  18. data/lib/buildpack_support/cache/inferred_network_failure.rb +26 -0
  19. data/lib/buildpack_support/cache/internet_availability.rb +64 -0
  20. data/lib/buildpack_support/component.rb +24 -0
  21. data/lib/buildpack_support/component/application.rb +76 -0
  22. data/lib/buildpack_support/component/base_component.rb +78 -0
  23. data/lib/buildpack_support/component/base_droplet.rb +96 -0
  24. data/lib/buildpack_support/component/downloads.rb +88 -0
  25. data/lib/buildpack_support/component/services.rb +84 -0
  26. data/lib/buildpack_support/component/versioned_dependency_component.rb +71 -0
  27. data/lib/buildpack_support/component/versioned_downloads.rb +57 -0
  28. data/lib/buildpack_support/component/with_timing.rb +40 -0
  29. data/lib/buildpack_support/configuration_utils.rb +58 -0
  30. data/lib/buildpack_support/constantize.rb +46 -0
  31. data/lib/buildpack_support/dash_case.rb +29 -0
  32. data/lib/buildpack_support/directory_finder.rb +45 -0
  33. data/lib/buildpack_support/filtering_pathname.rb +227 -0
  34. data/lib/buildpack_support/format_duration.rb +57 -0
  35. data/lib/buildpack_support/logging.rb +22 -0
  36. data/lib/buildpack_support/logging/delegating_logger.rb +48 -0
  37. data/lib/buildpack_support/logging/logger_factory.rb +148 -0
  38. data/lib/buildpack_support/qualify_path.rb +36 -0
  39. data/lib/buildpack_support/rake.rb +22 -0
  40. data/lib/buildpack_support/rake/buildpack_stage_task.rb +86 -0
  41. data/lib/buildpack_support/rake/cached_artifact_finder.rb +99 -0
  42. data/lib/buildpack_support/rake/check_api_doc_task.rb +70 -0
  43. data/lib/buildpack_support/rake/dependency_cache_task.rb +87 -0
  44. data/lib/buildpack_support/rake/disable_remote_downloads_task.rb +80 -0
  45. data/lib/buildpack_support/rake/package_task.rb +133 -0
  46. data/lib/buildpack_support/rake/package_zip_task.rb +80 -0
  47. data/lib/buildpack_support/rake/repository_configuration_finder.rb +66 -0
  48. data/lib/buildpack_support/rake/write_version_file_task.rb +82 -0
  49. data/lib/buildpack_support/repository.rb +24 -0
  50. data/lib/buildpack_support/repository/configured_item.rb +81 -0
  51. data/lib/buildpack_support/repository/repository_index.rb +98 -0
  52. data/lib/buildpack_support/repository/wildcard_version_resolver.rb +75 -0
  53. data/lib/buildpack_support/shell.rb +41 -0
  54. data/lib/buildpack_support/snake_case.rb +30 -0
  55. data/lib/buildpack_support/space_case.rb +29 -0
  56. data/lib/buildpack_support/test/application_helper.rb +41 -0
  57. data/lib/buildpack_support/test/base_component_helper.rb +59 -0
  58. data/lib/buildpack_support/test/base_droplet_helper.rb +36 -0
  59. data/lib/buildpack_support/test/console_helper.rb +57 -0
  60. data/lib/buildpack_support/test/environment_helper.rb +32 -0
  61. data/lib/buildpack_support/test/internet_availability_helper.rb +29 -0
  62. data/lib/buildpack_support/test/logging_helper.rb +50 -0
  63. data/lib/buildpack_support/test/scratch_helper.rb +32 -0
  64. data/lib/buildpack_support/test/versioned_dependency_component_helper.rb +32 -0
  65. data/lib/buildpack_support/test/with_load_path_helper.rb +27 -0
  66. data/lib/buildpack_support/to_b.rb +38 -0
  67. data/lib/buildpack_support/tokenized_version.rb +157 -0
  68. data/lib/buildpack_support/version.rb +23 -0
  69. data/spec/buildpack_support/base_buildpack_spec.rb +112 -0
  70. data/spec/buildpack_support/buildpack_version_spec.rb +122 -0
  71. data/spec/buildpack_support/cache/application_cache_spec.rb +56 -0
  72. data/spec/buildpack_support/cache/cached_file_spec.rb +94 -0
  73. data/spec/buildpack_support/cache/download_cache_spec.rb +293 -0
  74. data/spec/buildpack_support/cache/internet_availability_spec.rb +57 -0
  75. data/spec/buildpack_support/cache/yield_file_with_content.rb +30 -0
  76. data/spec/buildpack_support/component/application_spec.rb +81 -0
  77. data/spec/buildpack_support/component/base_component_spec.rb +81 -0
  78. data/spec/buildpack_support/component/base_droplet_spec.rb +72 -0
  79. data/spec/buildpack_support/component/downloads_spec.rb +63 -0
  80. data/spec/buildpack_support/component/services_spec.rb +80 -0
  81. data/spec/buildpack_support/component/versioned_dependency_component_spec.rb +58 -0
  82. data/spec/buildpack_support/component/versioned_downloads_spec.rb +58 -0
  83. data/spec/buildpack_support/component/with_timing_spec.rb +30 -0
  84. data/spec/buildpack_support/configuration_utils_spec.rb +39 -0
  85. data/spec/buildpack_support/constantize_spec.rb +34 -0
  86. data/spec/buildpack_support/dash_case_spec.rb +41 -0
  87. data/spec/buildpack_support/directory_finder_spec.rb +41 -0
  88. data/spec/buildpack_support/filtering_pathname_spec.rb +443 -0
  89. data/spec/buildpack_support/format_duration_spec.rb +60 -0
  90. data/spec/buildpack_support/logging/delegating_logger_spec.rb +62 -0
  91. data/spec/buildpack_support/logging/logger_factory_spec.rb +262 -0
  92. data/spec/buildpack_support/qualify_path_spec.rb +42 -0
  93. data/spec/buildpack_support/rake/buildpack_stage_task_spec.rb +88 -0
  94. data/spec/buildpack_support/rake/cached_artifact_finder_spec.rb +73 -0
  95. data/spec/buildpack_support/rake/check_api_doc_task_spec.rb +69 -0
  96. data/spec/buildpack_support/rake/dependency_cache_task_spec.rb +133 -0
  97. data/spec/buildpack_support/rake/disable_remote_downloads_task_spec.rb +91 -0
  98. data/spec/buildpack_support/rake/package_task_spec.rb +335 -0
  99. data/spec/buildpack_support/rake/package_zip_task_spec.rb +91 -0
  100. data/spec/buildpack_support/rake/repository_configuration_finder_spec.rb +61 -0
  101. data/spec/buildpack_support/rake/write_version_file_task_spec.rb +96 -0
  102. data/spec/buildpack_support/repository/configured_item_spec.rb +78 -0
  103. data/spec/buildpack_support/repository/repository_index_spec.rb +118 -0
  104. data/spec/buildpack_support/repository/wildcard_version_resolver_spec.rb +73 -0
  105. data/spec/buildpack_support/shell_spec.rb +32 -0
  106. data/spec/buildpack_support/snake_case_spec.rb +45 -0
  107. data/spec/buildpack_support/space_case_spec.rb +41 -0
  108. data/spec/buildpack_support/to_b_spec.rb +41 -0
  109. data/spec/buildpack_support/tokenized_version_spec.rb +132 -0
  110. data/spec/fixtures/application/test-file +0 -0
  111. data/spec/fixtures/config/found-config.yml +2 -0
  112. data/spec/fixtures/droplet-resources/droplet-resource +0 -0
  113. data/spec/fixtures/stub-download-with-top-level.zip +0 -0
  114. data/spec/fixtures/stub-download.tar.gz +0 -0
  115. data/spec/fixtures/stub-download.zip +0 -0
  116. data/spec/fixtures/test-cache.yml +18 -0
  117. data/spec/fixtures/test-index.yml +2 -0
  118. data/spec/fixtures/test_component.rb +0 -0
  119. data/spec/fixtures/zip-contents/test-directory/test-deep-file +0 -0
  120. data/spec/fixtures/zip-contents/test-file +0 -0
  121. data/spec/spec_helper.rb +30 -0
  122. metadata +416 -0
data/docs/test.md ADDED
@@ -0,0 +1 @@
1
+ TODO: Document Test support code
@@ -0,0 +1,18 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ # A module encapsulating all of the code for the Buildpack Support utilities
17
+ module BuildpackSupport
18
+ end
@@ -0,0 +1,166 @@
1
+ # Encoding: utf-8
2
+ # # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support'
17
+ require 'buildpack_support/space_case'
18
+ require 'buildpack_support/buildpack_version'
19
+ require 'buildpack_support/component/application'
20
+ require 'buildpack_support/logging/logger_factory'
21
+ require 'buildpack_support/snake_case'
22
+
23
+ module BuildpackSupport
24
+
25
+ # A base class for all buildpack implementations to extend from. This implementation provides a number of utility methods for dealing with components.
26
+ class BaseBuildpack
27
+
28
+ # Iterates over all of the components to detect if this buildpack can be used to run an application
29
+ #
30
+ # @return [Array<String>] An array of strings that identify the components and versions that will be used to run
31
+ # this application. If no container can run the application, the array will be empty
32
+ # (+[]+).
33
+ def detect
34
+ fail "Method 'detect' must be defined"
35
+ end
36
+
37
+ # Transforms the application directory such that the engine, and frameworks can run the application
38
+ #
39
+ # @return [Void]
40
+ def compile
41
+ fail "Method 'compile' must be defined"
42
+ end
43
+
44
+ # Generates the payload required to run the application. The payload format is defined by the
45
+ # {Heroku Buildpack API}[https://devcenter.heroku.com/articles/buildpack-api#buildpack-api].
46
+ #
47
+ # @return [String] The payload required to run the application.
48
+ def release
49
+ fail "Method 'release' must be defined"
50
+ end
51
+
52
+ protected
53
+
54
+ # Returns the components that are detected for an application
55
+ #
56
+ # @param [String] type the type of components
57
+ # @param [String] components the candidate components
58
+ # @param [Boolean] unique whether there must be _exactly_ one component detected
59
+ # @return [Array<BuildpackSupport::Component::BaseComponent>] the collection of detected components
60
+ def component_detection(type, components, unique)
61
+ detected, _tags = detection type, components, unique
62
+ detected
63
+ end
64
+
65
+ # Returns the components, and the tags from those components that are detected for an application
66
+ #
67
+ # @param [String] type the type of components
68
+ # @param [Array<BuildpackSupport::Component::BaseComponent>] components the candidate components
69
+ # @param [Boolean] unique whether there must be _exactly_ one component detected
70
+ # @return [Array<BuildpackSupport::Component::BaseComponent>] the collection of detected components
71
+ # @return [Array<String>] the collection of tags from the detected components
72
+ def detection(type, components, unique)
73
+ detected = []
74
+ tags = []
75
+
76
+ components.each do |component|
77
+ result = component.detect
78
+
79
+ next unless result
80
+
81
+ detected << component
82
+ tags << result
83
+ end
84
+
85
+ fail "Application can be run by more than one #{type}: #{names detected}" if unique && detected.size > 1
86
+ [detected, tags]
87
+ end
88
+
89
+ # +require+ a component based on its id
90
+ #
91
+ # @param [Pathname] load_root the +$LOAD_ROOT+ to load the component from
92
+ # @param [String] component the name of the component to load
93
+ def require_component(load_root, component)
94
+ file = load_root + "#{component.snake_case}.rb"
95
+
96
+ if file.exist?
97
+ require component.snake_case
98
+ @logger.debug { "Successfully required #{component}" }
99
+ else
100
+ @logger.debug { "Cannot require #{component} because #{file} does not exist" }
101
+ end
102
+ end
103
+
104
+ # Returns the tags that are detected for an application
105
+ #
106
+ # @param [String] type the type of components
107
+ # @param [String] components the candidate components
108
+ # @param [Boolean] unique whether there must be _exactly_ one component detected
109
+ # @return [Array<String>] the collection of tags from the detected components
110
+ def tag_detection(type, components, unique)
111
+ _detected, tags = detection type, components, unique
112
+ tags
113
+ end
114
+
115
+ private_class_method :new
116
+
117
+ private
118
+
119
+ def initialize(_app_dir, _application)
120
+ @logger = Logging::LoggerFactory.instance.get_logger self.class
121
+ @buildpack_version = BuildpackVersion.new
122
+
123
+ @logger.debug { "Environment Variables: #{ENV.to_hash}" }
124
+ end
125
+
126
+ def names(components)
127
+ components.map { |component| component.class.to_s.space_case }.join(', ')
128
+ end
129
+
130
+ class << self
131
+
132
+ # Main entry to the buildpack. Initializes the buildpack and all of its dependencies and yields a new instance
133
+ # to any given block. Any exceptions thrown as part of the buildpack setup or execution are handled
134
+ #
135
+ # @param [String] app_dir the path of the application directory
136
+ # @param [String] message an error message with an insert for the reason for failure
137
+ # @yield [Buildpack] the buildpack to work with
138
+ # @return [Object] the return value from the given block
139
+ def with_buildpack(app_dir, message)
140
+ app_dir = Pathname.new(File.expand_path(app_dir))
141
+ application = Component::Application.new(app_dir)
142
+ Logging::LoggerFactory.instance.setup app_dir
143
+
144
+ yield new(app_dir, application) if block_given?
145
+ rescue => e
146
+ handle_error(e, message)
147
+ end
148
+
149
+ private
150
+
151
+ def handle_error(e, message)
152
+ if Logging::LoggerFactory.instance.initialized
153
+ logger = Logging::LoggerFactory.instance.get_logger BaseBuildpack
154
+
155
+ logger.error { message % e.inspect }
156
+ logger.debug { "Exception #{e.inspect} backtrace:\n#{e.backtrace.join("\n")}" }
157
+ end
158
+
159
+ abort e.message
160
+ end
161
+
162
+ end
163
+
164
+ end
165
+
166
+ end
@@ -0,0 +1,124 @@
1
+ # Encoding: utf-8
2
+ # # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support'
17
+ require 'buildpack_support/configuration_utils'
18
+ require 'buildpack_support/directory_finder'
19
+ require 'buildpack_support/to_b'
20
+
21
+ module BuildpackSupport
22
+
23
+ # A representation of the buildpack's version. The buildpack's version is determined using the following algorithm:
24
+ #
25
+ # 1. using the +config/version.yml+ file if it exists
26
+ # 2. using +git+ to determine the remote and hash if the buildpack is in a git repository
27
+ # 3. unknown
28
+ class BuildpackVersion
29
+ extend DirectoryFinder
30
+
31
+ # @!attribute [r] hash
32
+ # @return [String, nil] the Git hash of this version, or +nil+ if it cannot be determined
33
+ attr_reader :hash
34
+
35
+ # @!attribute [r] offline
36
+ # @return [Boolean] +true+ if the buildpack is offline, +false+ otherwise
37
+ attr_reader :offline
38
+
39
+ # @!attribute [r] remote
40
+ # @return [String, nil] the Git remote of this version, or +nil+ if it cannot be determined
41
+ attr_reader :remote
42
+
43
+ # @!attribute [r] version
44
+ # @return [String, nil] the version name of this version, or +nil+ if it cannot be determined
45
+ attr_reader :version
46
+
47
+ # Creates a new instance
48
+ def initialize(should_log = true)
49
+ configuration = ConfigurationUtils.new(should_log).load 'version'
50
+ @hash = configuration['hash'] || hash
51
+ @offline = configuration['offline'] || ENV['OFFLINE'].to_b
52
+ @remote = configuration['remote'] || remote
53
+ @version = configuration['version'] || ENV['VERSION'] || @hash
54
+
55
+ return unless should_log
56
+
57
+ logger = Logging::LoggerFactory.instance.get_logger BuildpackVersion
58
+ logger.debug { to_s }
59
+ end
60
+
61
+ # Returns a +Hash+ representation of the buildpack version.
62
+ #
63
+ # @return [Hash] a representation of the buildpack version
64
+ def to_hash
65
+ h = {}
66
+
67
+ h['hash'] = @hash if @hash
68
+ h['offline'] = @offline if @offline
69
+ h['remote'] = @remote if @remote
70
+ h['version'] = @version if @version
71
+
72
+ h
73
+ end
74
+
75
+ # Creates a string representation of the version. The string representation looks like the following:
76
+ # +[[<VERSION> [(offline)] | ] <REMOTE>#<HASH>] | [unknown]+. Some examples:
77
+ #
78
+ # +2.1.2 (offline) | https://github.com/cloudfoundry/java-buildpack.git#12345+ (custom version number, offline buildpack)
79
+ # +abcde | https://github.com/cloudfoundry/java-buildpack.git#abcde+ (default version number, online buildpack)
80
+ # +https://github.com/cloudfoundry/java-buildpack#12345+ (cloned buildpack)
81
+ # +unknown+ (un-packaged, un-cloned)
82
+ #
83
+ # @param [Boolean] human_readable whether the output should be human readable or machine readable
84
+ # @return [String] a +String+ representation of the version
85
+ def to_s(human_readable = true)
86
+ s = []
87
+ s << @version if @version
88
+ s << (human_readable ? '(offline)' : 'offline') if @offline
89
+ s << '|' if @version && human_readable
90
+ s << "#{@remote}##{@hash}" if @remote && @hash
91
+ s << 'unknown' if s.empty?
92
+
93
+ s.join(human_readable ? ' ' : '-')
94
+ end
95
+
96
+ private
97
+
98
+ GIT_DIR = BuildpackVersion.load_path_peer('.git').freeze
99
+
100
+ private_constant :GIT_DIR
101
+
102
+ def git(command)
103
+ `git --git-dir=#{GIT_DIR} #{command}`.chomp if git? && git_dir?
104
+ end
105
+
106
+ def git?
107
+ system 'which git > /dev/null'
108
+ end
109
+
110
+ def git_dir?
111
+ GIT_DIR.exist?
112
+ end
113
+
114
+ def hash
115
+ git 'rev-parse --short HEAD'
116
+ end
117
+
118
+ def remote
119
+ git 'config --get remote.origin.url'
120
+ end
121
+
122
+ end
123
+
124
+ end
@@ -0,0 +1,24 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support'
17
+
18
+ module BuildpackSupport
19
+
20
+ # A module encapsulating all of the code for the cache utilities
21
+ module Cache
22
+ end
23
+
24
+ end
@@ -0,0 +1,41 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'buildpack_support/cache'
17
+ require 'buildpack_support/cache/download_cache'
18
+
19
+ module BuildpackSupport
20
+ module Cache
21
+
22
+ # An extension of {DownloadCache} that is configured to use the application cache. The application
23
+ # cache location is defined by the second argument (<tt>ARGV[1]</tt>) to the +compile+ script.
24
+ #
25
+ # <b>WARNING: This cache should only by used by code run by the +compile+ script</b>
26
+ class ApplicationCache < DownloadCache
27
+
28
+ # Creates an instance that is configured to use the application cache. The application cache location is defined
29
+ # by the second argument (<tt>ARGV[1]</tt>) to the +compile+ script.
30
+ #
31
+ # @raise if the second argument (<tt>ARGV[1]</tt>) to the +compile+ script is +nil+
32
+ def initialize
33
+ application_cache_directory = ARGV[1]
34
+ fail 'Application cache directory is undefined' if application_cache_directory.nil?
35
+ super(Pathname.new(application_cache_directory), CACHED_RESOURCES_DIRECTORY)
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,103 @@
1
+ # Encoding: utf-8
2
+ # Copyright 2013-2014 the original author or authors.
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require 'fileutils'
17
+ require 'buildpack_support/cache'
18
+
19
+ module BuildpackSupport
20
+ module Cache
21
+
22
+ # Represents a file cached on a filesystem
23
+ #
24
+ # Note: this class is thread-safe, however access to the cached files is not
25
+ class CachedFile
26
+
27
+ # Creates an instance of the cached file. Files created and expected by this class will all be rooted at
28
+ # +cache_root+.
29
+ #
30
+ # @param [Pathname] cache_root the filesystem root for the file created and expected by this class
31
+ # @param [String] uri a uri which uniquely identifies the file in the cache
32
+ def initialize(cache_root, uri)
33
+ FileUtils.mkdir_p cache_root
34
+
35
+ key = URI.escape(uri, '/')
36
+ @cached = cache_root + "#{key}.cached"
37
+ @etag = cache_root + "#{key}.etag"
38
+ @last_modified = cache_root + "#{key}.last_modified"
39
+ end
40
+
41
+ # Opens the cached file
42
+ #
43
+ # @param [String, integer] mode_enc the mode to open the file in. Can be a string like +"r"+ or an integer like
44
+ # +File::CREAT | File::WRONLY+.
45
+ # @param [Array] additional_args any additional arguments to be passed to the block
46
+ # @yield [file, additional_args] the cached file and any additional arguments passed in
47
+ # @return [Void]
48
+ def cached(mode_enc, *additional_args, &block)
49
+ @cached.open(mode_enc) { |f| block.call f, *additional_args }
50
+ end
51
+
52
+ # Returns whether or not data is cached.
53
+ #
54
+ # @return [Boolean] +true+ if and only if data is cached
55
+ def cached?
56
+ @cached.exist?
57
+ end
58
+
59
+ # Destroys the cached file
60
+ def destroy
61
+ [@cached, @etag, @last_modified].each { |f| f.delete if f.exist? }
62
+ end
63
+
64
+ # Opens the etag file
65
+ #
66
+ # @param [String, integer] mode_enc the mode to open the file in. Can be a string like +"r"+ or an integer like
67
+ # +File::CREAT | File::WRONLY+.
68
+ # @param [Array] additional_args any additional arguments to be passed to the block
69
+ # @yield [file] the etag file
70
+ # @return [Void]
71
+ def etag(mode_enc, *additional_args, &block)
72
+ @etag.open(mode_enc) { |f| block.call f, *additional_args }
73
+ end
74
+
75
+ # Returns whether or not an etag is stored.
76
+ #
77
+ # @return [Boolean] +true+ if and only if an etag is stored
78
+ def etag?
79
+ @etag.exist?
80
+ end
81
+
82
+ # Opens the last modified file
83
+ #
84
+ # @param [String, integer] mode_enc the mode to open the file in. Can be a string like +"r"+ or an integer like
85
+ # +File::CREAT | File::WRONLY+.
86
+ # @param [Array] additional_args any additional arguments to be passed to the block
87
+ # @yield [file] the last modified file
88
+ # @return [Void]
89
+ def last_modified(mode_enc, *additional_args, &block)
90
+ @last_modified.open(mode_enc) { |f| block.call f, *additional_args }
91
+ end
92
+
93
+ # Returns whether or not a last modified time stamp is stored.
94
+ #
95
+ # @return [Boolean] +true+ if and only if a last modified time stamp is stored
96
+ def last_modified?
97
+ @last_modified.exist?
98
+ end
99
+
100
+ end
101
+
102
+ end
103
+ end