forked from berkshelf/berkshelf
-
Notifications
You must be signed in to change notification settings - Fork 3
/
packager.rb
107 lines (92 loc) · 2.83 KB
/
packager.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
require "archive/tar/minitar"
require "find" unless defined?(Find)
require "zlib" unless defined?(Zlib)
module Berkshelf
# A class for archiving and compressing directory containing one or more cookbooks.
#
# Example:
# Archiving a path containing the cookbooks:
# * "/path/to/cookbooks/my_face"
# * "/path/to/cookbooks/nginx"
#
# irb> source = "/path/to/cookbooks"
# irb> packager = Berkshelf::Packager.new("some/path/cookbooks.tar.gz")
# irb> packager.run(source) #=> "some/path/cookbooks.tar.gz"
class Packager
class << self
def validate_destination(path)
path.to_s
end
end
# @return [String]
attr_reader :out_file
# @param [#to_s] out_file
# path to write the archive to
def initialize(out_file)
@out_file = out_file.to_s
@out_dir, @filename = File.split(@out_file)
end
# Archive the contents of given path
#
# @param [#to_s] source
# the filepath to archive the contents of
#
# @raise [PackageError]
# if an error is encountered while writing the out_file
#
# @return [String]
# path to the generated archive
def run(source)
begin
dest = Zlib::GzipWriter.open(out_file)
tar = RelativeTarWriter.new(dest, source)
Find.find(source) do |entry|
next if source == entry
Archive::Tar::Minitar.pack_file(entry, tar)
end
ensure
tar.close
dest.close
end
out_file
rescue SystemCallError => ex
raise PackageError, ex
end
# Validate that running the packager would be successful. Returns nil if would be
# successful and raises an error if would not.
#
# @raise [PackageError]
# if running the packager would absolutely not result in a success
#
# @return [nil]
def validate!
raise PackageError, "Path is not a directory: #{out_dir}" unless File.directory?(out_dir)
raise PackageError, "Directory is not writable: #{out_dir}" unless File.writable?(out_dir)
end
private
# @return [String]
attr_reader :out_dir
# @return [String]
attr_reader :filename
# A private decorator for Archive::Tar::Minitar::Writer that
# turns absolute paths into relative ones.
class RelativeTarWriter < SimpleDelegator # :nodoc:
def initialize(io, base_path)
@base_path = Pathname.new(base_path)
super(Archive::Tar::Minitar::Writer.new(io))
end
%w{add_file add_file_simple mkdir}.each do |method|
class_eval <<~RUBY
def #{method}(name, *opts, &block)
super(relative_path(name), *opts, &block)
end
RUBY
end
private
attr_reader :base_path
def relative_path(path)
Pathname.new(path).relative_path_from(base_path).to_s
end
end
end
end