class CookbookOmnifetch::StagingArea
stage.discard!
stage.publish!(install_path)
# Copy files to stage.path
stage = CookbookOmnifetch::StagingArea.new
@example creating a staging area and publishing it manually
end
# Copy files to staging_path
CookbookOmnifetch::StagingArea.stage(install_path) do |staging_path|
@example installing files using the {.stage} helper
staging area it creates before returning.
those directories. The {.stage} method handles directory cleanup for the
is the caller’s responsibility to use {discard!} when it is done to remove
{StagingArea} allocates temporary directories on the local file system. It
cache before it is completely installed. (See {publish!} for details.)
running in parallel might retrieve an incomplete cookbook from the local
from the web, {StagingArea} allows you to minimize the risk that a process
When performing long operations such as installing or updating a cookbook
local directory.
A staging area in which the caller can stage files and publish them to a
def self.stage(target_path)
- Yieldparam: staging_path -
Parameters:
-
target_path
(Pathname
) --
def self.stage(target_path) sa = new begin yield(sa.path) sa.publish!(target_path) unless sa.empty? || sa.match?(target_path) ensure sa.discard! end end
def discard!
the file system. Future attempts to use it will raise
The staging area is no longer available once {discard!} removes it from
Removes the staging area and its contents from the file system.
def discard! FileUtils.rm_rf(@stage_tmp) unless @stage_tmp.nil? @unavailable = true end
def empty?
-
(Boolean)
- whether the staging area is empty
Raises:
-
(StagingAreaNotAvailable)
-
def empty? !path.exist? || path.empty? end
def files_different?(base1, base2, subpath)
def files_different?(base1, base2, subpath) file1 = File.join(base1, subpath) file2 = File.join(base2, subpath) return true unless File.ftype(file1) == File.ftype(file2) return true if File.file?(file1) && !FileUtils.cmp(file1, file2) false end
def match?(compare_path)
-
(Boolean)
- whether the staging area matches +compare_path+
Raises:
-
(StagingAreaNotAvailable)
-
Parameters:
-
compare_path
(String
) --
def match?(compare_path) raise StagingAreaNotAvailable if unavailable? target = Pathname(compare_path) return false unless target.exist? files = Dir.glob("**/*", File::FNM_DOTMATCH, base: path) target_files = Dir.glob("**/*", File::FNM_DOTMATCH, base: target) return false unless files.sort == target_files.sort files.each do |subpath| return false if files_different?(path, target, subpath) end true end
def path
-
(Pathname)
- path to the staging folder
Raises:
-
(StagingAreaNotAvailable)
-
def path raise StagingAreaNotAvailable if unavailable? return @path unless @path.nil? # Dir.mktmpdir returns a directory with restrictive permissions that it # doesn't support modifying, so create a subdirectory under it with # regular permissions for staging. @stage_tmp = Dir.mktmpdir @path = Pathname.new(File.join(@stage_tmp, "staging")) FileUtils.mkdir(@path) @path end
def publish!(install_path)
-
(StagingAreaNotAvailable)
-
Parameters:
-
install_path
(String
) --
def publish!(install_path) target = Pathname(install_path) cache_dir = target.parent cache_dir.mkpath Dir.mktmpdir("_STAGING_TMP_", cache_dir) do |tmpdir| newtmp = File.join(tmpdir, "new_cookbook") oldtmp = File.join(tmpdir, "old_cookbook") FileUtils.cp_r(path, newtmp) # We could achieve an atomic replace using symbolic links, if they are # supported on all platforms. File.rename(target, oldtmp) if target.exist? File.rename(newtmp, target) end end
def unavailable?
-
(Boolean)
- whether the staging area is unavailable
def unavailable? !!@unavailable end