pkgr 0.3.4 → 1.0.1.pre
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +68 -463
- data/bin/pkgr +4 -52
- data/lib/pkgr.rb +13 -29
- data/lib/pkgr/app.rb +19 -4
- data/lib/pkgr/builder.rb +207 -0
- data/lib/pkgr/buildpack.rb +80 -0
- data/lib/pkgr/cli.rb +34 -158
- data/lib/pkgr/config.rb +65 -0
- data/lib/pkgr/data/distributions/debian/build_dependencies.yml +14 -0
- data/lib/pkgr/data/{debian → distributions/debian}/cron.d +0 -0
- data/lib/pkgr/data/distributions/debian/default.erb +12 -0
- data/lib/pkgr/data/distributions/debian/dependencies.yml +17 -0
- data/lib/pkgr/data/distributions/debian/hooks/postinstall.sh +27 -0
- data/lib/pkgr/data/distributions/debian/hooks/preinstall.sh +9 -0
- data/lib/pkgr/data/{debian → distributions/debian}/logrotate.erb +0 -0
- data/lib/pkgr/data/distributions/debian/runner.erb +122 -0
- data/lib/pkgr/data/distributions/debian/upstart/master.conf.erb +7 -0
- data/lib/pkgr/data/distributions/debian/upstart/process.conf.erb +7 -0
- data/lib/pkgr/data/distributions/debian/upstart/process_master.conf.erb +2 -0
- data/lib/pkgr/dispatcher.rb +51 -0
- data/lib/pkgr/distributions.rb +18 -0
- data/lib/pkgr/distributions/debian.rb +157 -0
- data/lib/pkgr/git.rb +24 -0
- data/lib/pkgr/process.rb +18 -0
- data/lib/pkgr/templates/dir_template.rb +14 -0
- data/lib/pkgr/templates/file_template.rb +38 -0
- data/lib/pkgr/version.rb +1 -1
- metadata +93 -26
- data/lib/pkgr/data/debian/changelog +0 -0
- data/lib/pkgr/data/debian/compat.erb +0 -1
- data/lib/pkgr/data/debian/control.erb +0 -12
- data/lib/pkgr/data/debian/copyright.erb +0 -17
- data/lib/pkgr/data/debian/default.erb +0 -11
- data/lib/pkgr/data/debian/dirs.erb +0 -2
- data/lib/pkgr/data/debian/docs.erb +0 -0
- data/lib/pkgr/data/debian/init.d.erb +0 -155
- data/lib/pkgr/data/debian/install.erb +0 -16
- data/lib/pkgr/data/debian/links.erb +0 -5
- data/lib/pkgr/data/debian/postinst.erb +0 -59
- data/lib/pkgr/data/debian/prerm.erb +0 -57
- data/lib/pkgr/data/debian/rules.erb +0 -7
- data/lib/pkgr/pkgr.rake +0 -50
- data/lib/pkgr/railtie.rb +0 -7
data/bin/pkgr
CHANGED
@@ -1,56 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
4
|
-
require 'pkgr/cli'
|
3
|
+
require "pkgr/cli"
|
5
4
|
|
6
|
-
|
5
|
+
STDERR.sync = true
|
6
|
+
STDOUT.sync = true
|
7
7
|
|
8
|
-
|
9
|
-
opts.banner = <<BANNER
|
10
|
-
* Description
|
11
|
-
pkgr #{Pkgr::VERSION} - Package Rails apps effortlessly.
|
12
|
-
* Usage
|
13
|
-
pkgr --uri GIT_REPOSITORY --config database.yml:http://path/to/database.yml --config ...
|
14
|
-
BANNER
|
15
|
-
|
16
|
-
opts.separator ""
|
17
|
-
opts.separator "* Common options"
|
18
|
-
opts.on("--uri=", "Sets the Git repository URI (FILE, HTTP, SSH, GIT, etc.) [required]") do |v|
|
19
|
-
OPTIONS[:uri] = v
|
20
|
-
end
|
21
|
-
opts.on("-c=", "--config=", "Download a configuration file into the config/ folder of the app (HTTP or FILE URIs)") do |v|
|
22
|
-
OPTIONS[:config_files] ||= []
|
23
|
-
OPTIONS[:config_files] << v
|
24
|
-
end
|
25
|
-
opts.on("-b=", "--bump=", "Sets the app version [required]") do |v|
|
26
|
-
OPTIONS[:version] = v
|
27
|
-
end
|
28
|
-
opts.on("-n=", "--name=", "Sets the app name [optional]") do |v|
|
29
|
-
OPTIONS[:name] = v
|
30
|
-
end
|
31
|
-
opts.on("--ref=", "Sets the git reference to checkout [default=#{OPTIONS[:ref]}]") do |v|
|
32
|
-
OPTIONS[:ref] = v
|
33
|
-
end
|
34
|
-
opts.on("--host=", "Sets the build machine hostname. If none, the process will stop just before building the package.") do |v|
|
35
|
-
OPTIONS[:host] = v
|
36
|
-
end
|
37
|
-
|
38
|
-
opts.separator ""
|
39
|
-
opts.separator "* Other"
|
40
|
-
opts.on_tail("-h", "--help", "Show this message") do
|
41
|
-
puts opts
|
42
|
-
exit
|
43
|
-
end
|
44
|
-
opts.on_tail("--version", "Show version") do
|
45
|
-
puts Pkgr::VERSION
|
46
|
-
exit
|
47
|
-
end
|
48
|
-
end.parse!
|
49
|
-
|
50
|
-
begin
|
51
|
-
cli = Pkgr::CLI.new(OPTIONS)
|
52
|
-
cli.run
|
53
|
-
rescue Pkgr::CLI::Error, StandardError => e
|
54
|
-
puts e.message
|
55
|
-
puts e.backtrace if $DEBUG
|
56
|
-
end
|
8
|
+
Pkgr::CLI.start
|
data/lib/pkgr.rb
CHANGED
@@ -1,35 +1,19 @@
|
|
1
|
-
require 'pkgr/
|
2
|
-
require 'pkgr/
|
1
|
+
require 'pkgr/version'
|
2
|
+
require 'pkgr/cli'
|
3
|
+
require 'pkgr/dispatcher'
|
4
|
+
require 'mixlib/log'
|
3
5
|
|
4
6
|
module Pkgr
|
5
|
-
|
7
|
+
extend Mixlib::Log
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
module Errors
|
10
|
+
class Base < StandardError; end
|
11
|
+
class UnknownAppType < Base; end
|
12
|
+
class ConfigurationInvalid < Base; end
|
9
13
|
end
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
def self.setup_config(root)
|
14
|
-
puts "Setting up configuration file..."
|
15
|
-
target = File.join(root, "config", "pkgr.yml")
|
16
|
-
FileUtils.mkdir_p(File.dirname(target))
|
17
|
-
if File.exist?(target)
|
18
|
-
puts "'#{target}' already exists. Skipped."
|
19
|
-
else
|
20
|
-
FileUtils.cp(File.expand_path("../pkgr/data/pkgr.yml", __FILE__), target, :verbose => true)
|
21
|
-
puts "Edit '#{target}' and fill in the required information, then enter 'rake pkgr:generate' to generate the debian files."
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
def self.mkdir(target)
|
27
|
-
if File.directory?(target)
|
28
|
-
puts "#{target} directory already exists. Skipped."
|
29
|
-
elsif File.file?(target)
|
30
|
-
raise "#{target} already exists and is a file. Aborting."
|
31
|
-
else
|
32
|
-
FileUtils.mkdir_p target, :verbose => true
|
33
|
-
end
|
15
|
+
def data_dir
|
16
|
+
File.expand_path("../pkgr/data", __FILE__)
|
34
17
|
end
|
35
|
-
|
18
|
+
module_function :data_dir
|
19
|
+
end
|
data/lib/pkgr/app.rb
CHANGED
@@ -22,6 +22,7 @@ module Pkgr
|
|
22
22
|
@config = YAML::load_file(path)
|
23
23
|
raise ArgumentError, "The given configuration file at '#{path}' is not a well-formed YAML file. Please fix it or remove it and run 'rake pkgr:setup'" unless @config.kind_of?(Hash)
|
24
24
|
@config['_path'] = path
|
25
|
+
normalize_name!
|
25
26
|
end
|
26
27
|
|
27
28
|
def write_config
|
@@ -215,8 +216,8 @@ module Pkgr
|
|
215
216
|
#{debian_steps.join(" &&\n")}'
|
216
217
|
}
|
217
218
|
sh cmd
|
218
|
-
# Fetch
|
219
|
-
sh "scp #{host}:/tmp/#{name}_#{version}
|
219
|
+
# Fetch all package files, and put it in the `pkg` directory
|
220
|
+
sh "scp #{host}:/tmp/#{name}_#{version}* pkg/"
|
220
221
|
end
|
221
222
|
end
|
222
223
|
|
@@ -252,7 +253,7 @@ module Pkgr
|
|
252
253
|
|
253
254
|
private
|
254
255
|
def bundler_version
|
255
|
-
@config.fetch('bundler_version') { '1.
|
256
|
+
@config.fetch('bundler_version') { '1.3.5' }
|
256
257
|
end
|
257
258
|
|
258
259
|
def debian_file(filename)
|
@@ -260,5 +261,19 @@ module Pkgr
|
|
260
261
|
raise "The debian/changelog file does not exist. Please generate it first." unless File.exist?(file)
|
261
262
|
file
|
262
263
|
end
|
264
|
+
|
265
|
+
def normalize_name!
|
266
|
+
# debian packages can not contain capitalized letters nor underscores
|
267
|
+
if (raw_name = @config.fetch('name', '')) =~ /[A-Z_-]/
|
268
|
+
normalized_name = raw_name.
|
269
|
+
gsub(/[A-Z]/) { |m| "_#{m.downcase}" }. # underscore each word
|
270
|
+
gsub(/[_-]+/, '-'). # normalize underscores/dashes
|
271
|
+
sub(/^-/, '') # strip leading dash
|
272
|
+
puts "Normalized application name to %s (original: %s)." % [
|
273
|
+
normalized_name.inspect, raw_name.inspect
|
274
|
+
] unless normalized_name == raw_name
|
275
|
+
@config['name'] = normalized_name
|
276
|
+
end
|
277
|
+
end
|
263
278
|
end
|
264
|
-
end
|
279
|
+
end
|
data/lib/pkgr/builder.rb
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'pkgr/config'
|
4
|
+
require 'pkgr/distributions'
|
5
|
+
require 'pkgr/process'
|
6
|
+
|
7
|
+
module Pkgr
|
8
|
+
class Builder
|
9
|
+
attr_reader :tarball, :config
|
10
|
+
|
11
|
+
# Accepts a path to a tarball (gzipped or not), or you can pass '-' to read from stdin.
|
12
|
+
def initialize(tarball, config)
|
13
|
+
@tarball = tarball
|
14
|
+
@config = config
|
15
|
+
Pkgr.debug "Initializing builder with the following config: #{config.inspect}"
|
16
|
+
end
|
17
|
+
|
18
|
+
# Launch the full packaging procedure
|
19
|
+
def call
|
20
|
+
check
|
21
|
+
setup
|
22
|
+
extract
|
23
|
+
compile
|
24
|
+
write_env
|
25
|
+
write_init
|
26
|
+
package
|
27
|
+
end
|
28
|
+
|
29
|
+
# Check configuration, and verifies that the current distribution's requirements are satisfied
|
30
|
+
def check
|
31
|
+
raise Errors::ConfigurationInvalid, config.errors.join("; ") unless config.valid?
|
32
|
+
distribution.check(config)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Setup the build directory structure
|
36
|
+
def setup
|
37
|
+
Dir.chdir(build_dir) do
|
38
|
+
distribution.templates(config.name).each do |template|
|
39
|
+
template.install(config.sesame)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Extract the given tarball to the target directory
|
45
|
+
def extract
|
46
|
+
raise "#{source_dir} does not exist" unless File.directory?(source_dir)
|
47
|
+
|
48
|
+
opts = {}
|
49
|
+
if tarball == "-"
|
50
|
+
# FIXME: not really happy with reading everything in memory
|
51
|
+
opts[:input] = $stdin.read
|
52
|
+
end
|
53
|
+
|
54
|
+
tarball_extract = Mixlib::ShellOut.new("tar xzf #{tarball} -C #{source_dir}", opts)
|
55
|
+
tarball_extract.run_command
|
56
|
+
tarball_extract.error!
|
57
|
+
end
|
58
|
+
|
59
|
+
# Pass the app through the buildpack
|
60
|
+
def compile
|
61
|
+
if buildpack_for_app
|
62
|
+
puts "-----> #{buildpack_for_app.banner} app"
|
63
|
+
|
64
|
+
FileUtils.mkdir_p(compile_cache_dir)
|
65
|
+
|
66
|
+
run_hook config.before_precompile
|
67
|
+
buildpack_for_app.compile(source_dir, compile_cache_dir)
|
68
|
+
buildpack_for_app.release(source_dir, compile_cache_dir)
|
69
|
+
else
|
70
|
+
raise Errors::UnknownAppType, "Can't find a buildpack for your app"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Parses the output of buildpack/bin/release executable to find out its default Procfile commands.
|
75
|
+
# Then merges those with the ones from the app's Procfile (if any).
|
76
|
+
# Finally, generates a binstub in vendor/pkgr/processes/ so that these commands can be called using the app's executable.
|
77
|
+
def write_env
|
78
|
+
FileUtils.mkdir_p proc_dir
|
79
|
+
|
80
|
+
procfile_entries.each do |process|
|
81
|
+
process_file = File.join(proc_dir, process.name)
|
82
|
+
|
83
|
+
File.open(process_file, "w+") do |f|
|
84
|
+
f << process.command
|
85
|
+
f << " $@"
|
86
|
+
end
|
87
|
+
|
88
|
+
FileUtils.chmod 0755, process_file
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Write startup scripts.
|
93
|
+
def write_init
|
94
|
+
FileUtils.mkdir_p scaling_dir
|
95
|
+
Dir.chdir(scaling_dir) do
|
96
|
+
distribution.initializers_for(config.name, procfile_entries).each do |(process, file)|
|
97
|
+
process_config = config.dup
|
98
|
+
process_config.process_name = process.name
|
99
|
+
process_config.process_command = process.command
|
100
|
+
file.install(process_config.sesame)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Launch the FPM command that will generate the package.
|
106
|
+
def package
|
107
|
+
Pkgr.info "Running command: #{fpm_command}"
|
108
|
+
app_package = Mixlib::ShellOut.new(fpm_command)
|
109
|
+
app_package.run_command
|
110
|
+
app_package.error!
|
111
|
+
end
|
112
|
+
|
113
|
+
# Make sure to get rid of the build directory
|
114
|
+
def teardown
|
115
|
+
FileUtils.rm_rf(build_dir)
|
116
|
+
end
|
117
|
+
|
118
|
+
def procfile_entries
|
119
|
+
@procfile_entries ||= begin
|
120
|
+
default_process_types = YAML.load_file(release_file)["default_process_types"]
|
121
|
+
|
122
|
+
entries = if File.exist?(procfile)
|
123
|
+
File.read(procfile).gsub("\r\n","\n").split("\n").map do |line|
|
124
|
+
if line =~ /^([A-Za-z0-9_]+):\s*(.+)$/
|
125
|
+
[$1, $2]
|
126
|
+
end
|
127
|
+
end.compact
|
128
|
+
else
|
129
|
+
[]
|
130
|
+
end
|
131
|
+
|
132
|
+
default_process_types.merge(Hash[entries]).map{|name, command| Process.new(name, command)}
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Path to the release file generated after the buildpack compilation.
|
137
|
+
def release_file
|
138
|
+
File.join(source_dir, ".release")
|
139
|
+
end
|
140
|
+
|
141
|
+
# Path to the directory containing the main app files.
|
142
|
+
def source_dir
|
143
|
+
File.join(build_dir, "opt/#{config.name}")
|
144
|
+
end
|
145
|
+
|
146
|
+
# Build directory. Will be used by fpm to make the package.
|
147
|
+
def build_dir
|
148
|
+
@build_dir ||= Dir.mktmpdir
|
149
|
+
end
|
150
|
+
|
151
|
+
def vendor_dir
|
152
|
+
File.join(source_dir, "vendor", "pkgr")
|
153
|
+
end
|
154
|
+
|
155
|
+
# Directory where binstubs will be created for the corresponding Procfile commands.
|
156
|
+
def proc_dir
|
157
|
+
File.join(vendor_dir, "processes")
|
158
|
+
end
|
159
|
+
|
160
|
+
def scaling_dir
|
161
|
+
File.join(vendor_dir, "scaling")
|
162
|
+
end
|
163
|
+
|
164
|
+
# Returns the path to the app's (supposedly present) Procfile.
|
165
|
+
def procfile
|
166
|
+
File.join(source_dir, "Procfile")
|
167
|
+
end
|
168
|
+
|
169
|
+
# Directory where the buildpacks can store stuff.
|
170
|
+
def compile_cache_dir
|
171
|
+
config.compile_cache_dir || File.join(source_dir, ".git/cache")
|
172
|
+
end
|
173
|
+
|
174
|
+
# Returns the current distribution we're packaging for.
|
175
|
+
def distribution
|
176
|
+
@distribution ||= Distributions.current
|
177
|
+
end
|
178
|
+
|
179
|
+
# List of available buildpacks for the current distribution.
|
180
|
+
def buildpacks
|
181
|
+
distribution.buildpacks
|
182
|
+
end
|
183
|
+
|
184
|
+
# Buildpack detected for the app, if any.
|
185
|
+
def buildpack_for_app
|
186
|
+
raise "#{source_dir} does not exist" unless File.directory?(source_dir)
|
187
|
+
@buildpack_for_app ||= buildpacks.find do |buildpack|
|
188
|
+
buildpack.setup
|
189
|
+
buildpack.detect(source_dir)
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def fpm_command
|
194
|
+
distribution.fpm_command(build_dir, config)
|
195
|
+
end
|
196
|
+
|
197
|
+
protected
|
198
|
+
def run_hook(file)
|
199
|
+
return true if file.nil?
|
200
|
+
Dir.chdir(source_dir) do
|
201
|
+
app_package = Mixlib::ShellOut.new("bash '#{file}'")
|
202
|
+
app_package.run_command
|
203
|
+
app_package.error!
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module Pkgr
|
4
|
+
class Buildpack
|
5
|
+
class << self
|
6
|
+
attr_writer :buildpack_cache_dir
|
7
|
+
|
8
|
+
def buildpack_cache_dir
|
9
|
+
@buildpack_cache_dir ||= File.expand_path("~/.pkgr/buildpacks").tap do |dir|
|
10
|
+
FileUtils.mkdir_p(dir)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_reader :url, :banner
|
16
|
+
|
17
|
+
def initialize(url)
|
18
|
+
@url = url
|
19
|
+
end
|
20
|
+
|
21
|
+
def buildpack_cache_dir
|
22
|
+
self.class.buildpack_cache_dir
|
23
|
+
end
|
24
|
+
|
25
|
+
def detect(path)
|
26
|
+
buildpack_detect = Mixlib::ShellOut.new("#{dir}/bin/detect \"#{path}\"")
|
27
|
+
buildpack_detect.run_command
|
28
|
+
@banner = buildpack_detect.stdout.chomp
|
29
|
+
buildpack_detect.exitstatus == 0
|
30
|
+
end
|
31
|
+
|
32
|
+
def compile(path, compile_cache_dir)
|
33
|
+
Dir.chdir(path) do
|
34
|
+
IO.popen(%{ env -i PATH="$PATH" #{dir}/bin/compile "#{path}" "#{compile_cache_dir}" }) do |io|
|
35
|
+
until io.eof?
|
36
|
+
data = io.gets
|
37
|
+
print data
|
38
|
+
end
|
39
|
+
end
|
40
|
+
raise "compile failed" unless $?.exitstatus.zero?
|
41
|
+
end
|
42
|
+
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def release(path, compile_cache_dir)
|
47
|
+
buildpack_release = Mixlib::ShellOut.new("#{dir}/bin/release \"#{path}\" \"#{compile_cache_dir}\" > #{path}/.release")
|
48
|
+
buildpack_release.run_command
|
49
|
+
buildpack_release.exitstatus == 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def dir
|
53
|
+
File.join(buildpack_cache_dir, File.basename(url, ".git"))
|
54
|
+
end
|
55
|
+
|
56
|
+
def exists?
|
57
|
+
File.directory?(dir)
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup
|
61
|
+
exists? ? refresh : install
|
62
|
+
end
|
63
|
+
|
64
|
+
def refresh
|
65
|
+
Dir.chdir(dir) do
|
66
|
+
buildpack_refresh = Mixlib::ShellOut.new("git fetch origin && git reset --hard origin/master")
|
67
|
+
buildpack_refresh.run_command
|
68
|
+
buildpack_refresh.error!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def install
|
73
|
+
Dir.chdir(buildpack_cache_dir) do
|
74
|
+
buildpack_install = Mixlib::ShellOut.new("git clone \"#{url}\"")
|
75
|
+
buildpack_install.run_command
|
76
|
+
buildpack_install.error!
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/pkgr/cli.rb
CHANGED
@@ -1,164 +1,40 @@
|
|
1
|
-
require
|
2
|
-
require 'fileutils'
|
1
|
+
require "thor"
|
3
2
|
require 'pkgr'
|
4
|
-
require 'uri'
|
5
3
|
|
6
4
|
module Pkgr
|
7
|
-
class CLI
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
generate
|
41
|
-
bump
|
42
|
-
build
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
def valid?
|
47
|
-
@errors.clear
|
48
|
-
@errors.push("You must pass a repository URI through --uri") if uri.nil?
|
49
|
-
@errors.push("You must pass a version number through --bump") if version.nil?
|
50
|
-
@errors.empty?
|
51
|
-
end
|
52
|
-
|
53
|
-
def build
|
54
|
-
if host.nil?
|
55
|
-
puts "Can't build the package. You must pass the --host option for this."
|
56
|
-
else
|
57
|
-
@app.build_debian_package(host)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
def bump
|
62
|
-
@app.bump!(:custom, version)
|
63
|
-
end
|
64
|
-
|
65
|
-
def bundle
|
66
|
-
sh "bundle install"
|
67
|
-
sh "git add -f Gemfile.lock"
|
68
|
-
sh "if git status --porcelain | grep Gemfile.lock; then git commit -m '[pkgr] Update Gemfile.lock.'; fi"
|
69
|
-
end
|
70
|
-
|
71
|
-
def checkout
|
72
|
-
sh "if git branch | grep '#{pkgr_branch}'; then git checkout #{pkgr_branch}; else git checkout -b #{pkgr_branch} #{ref}; fi"
|
73
|
-
end
|
74
|
-
|
75
|
-
def clone_repository
|
76
|
-
parsed_uri = URI.parse(uri)
|
77
|
-
case parsed_uri.scheme
|
78
|
-
when nil, "file"
|
79
|
-
@dir = parsed_uri.path
|
80
|
-
else
|
81
|
-
@dir = File.basename(uri, ".git")
|
82
|
-
sh "git clone #{uri}"
|
83
|
-
end
|
84
|
-
@dir = File.expand_path @dir
|
85
|
-
end
|
86
|
-
|
87
|
-
def configure_app
|
88
|
-
@app = Pkgr::App.new(dir, "config/pkgr.yml")
|
89
|
-
@app.config['git_ref'] = pkgr_branch
|
90
|
-
@app.config['config_files'].push(*Dir["config/*.yml"].map{|f| File.basename(f)}).uniq!
|
91
|
-
if name.nil?
|
92
|
-
@app.config['name'] = File.basename(dir) if @app.name.nil?
|
93
|
-
else
|
94
|
-
@app.config['name'] = name
|
95
|
-
end
|
96
|
-
raise Error, "The app is not correctly configured: #{@app.errors.join(", ")}" unless @app.valid?
|
97
|
-
@app.write_config
|
98
|
-
end
|
99
|
-
|
100
|
-
# Download the given config files
|
101
|
-
def copy_remote_config_files
|
102
|
-
(config_files || []).each do |file|
|
103
|
-
filename, file_uri = file.split("::")
|
104
|
-
if file_uri.nil?
|
105
|
-
file_uri = filename
|
106
|
-
filename = File.basename(file_uri)
|
107
|
-
end
|
108
|
-
|
109
|
-
file_uri = File.expand_path(file_uri) if URI.parse(file_uri).scheme.nil?
|
110
|
-
target = "config/#{filename}"
|
111
|
-
puts "Copying #{file_uri} into #{target}..."
|
112
|
-
File.open(target, "w+") { |f| f << open(file_uri).read }
|
113
|
-
end
|
114
|
-
end
|
115
|
-
|
116
|
-
def copy_example_config_files
|
117
|
-
[".example", ".dist"].each do |pattern|
|
118
|
-
Dir["config/*.yml#{pattern}"].each do |file|
|
119
|
-
target = File.basename(file, pattern)
|
120
|
-
unless File.exist?("config/#{target}")
|
121
|
-
FileUtils.cp(file, "config/#{target}")
|
122
|
-
end
|
123
|
-
end
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def generate
|
128
|
-
@app.generate_required_files
|
129
|
-
sh "git add debian/"
|
130
|
-
sh "if git status --porcelain | grep debian/; then git commit -m '[pkgr] Add debian files.'; fi"
|
131
|
-
sh "git add bin/"
|
132
|
-
sh "if git status --porcelain | grep bin/; then git commit -m '[pkgr] Add executable file.'; fi"
|
133
|
-
end
|
134
|
-
|
135
|
-
def pkgr_branch
|
136
|
-
"pkgr-#{ref}"
|
137
|
-
end
|
138
|
-
|
139
|
-
def setup
|
140
|
-
Pkgr.setup(dir)
|
141
|
-
|
142
|
-
gemfile = File.read("Gemfile")
|
143
|
-
unless gemfile =~ /^gem 'pkgr'/
|
144
|
-
File.open("Gemfile", "a") do |f|
|
145
|
-
f.puts
|
146
|
-
f.puts "gem 'pkgr'"
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
unless gemfile =~ /^gem 'thin'/
|
151
|
-
File.open("Gemfile", "a") do |f|
|
152
|
-
f.puts
|
153
|
-
f.puts "gem 'thin'"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
sh "git add Gemfile"
|
158
|
-
sh" if git status --porcelain | grep Gemfile; then git commit -m '[pkgr] Update Gemfile.'; fi"
|
159
|
-
sh "git add -f config/*.yml"
|
160
|
-
sh" if git status --porcelain | grep config/*.yml; then git commit -m '[pkgr] Update configuration files.'; fi"
|
5
|
+
class CLI < Thor
|
6
|
+
class_option :verbose, :type => :boolean, :default => false, :desc => "Run verbosely"
|
7
|
+
class_option :debug, :type => :boolean, :default => false, :desc => "Run very verbosely"
|
8
|
+
class_option :name, :type => :string, :desc => "Application name (if directory given, it will default to the directory name)"
|
9
|
+
|
10
|
+
desc "package TARBALL", "Package the given tarball or directory"
|
11
|
+
|
12
|
+
method_option :target, :type => :string, :default => "deb", :desc => "Target package to build (only 'deb' supported for now)"
|
13
|
+
method_option :changelog, :type => :string, :desc => "Changelog"
|
14
|
+
method_option :architecture, :type => :string, :default => "x86_64", :desc => "Target architecture for the package"
|
15
|
+
method_option :homepage, :type => :string, :desc => "Project homepage"
|
16
|
+
method_option :description, :type => :string, :desc => "Project description"
|
17
|
+
method_option :version, :type => :string, :desc => "Package version (if git directory given, it will use the latest git tag available)"
|
18
|
+
method_option :iteration, :type => :string, :default => Time.now.strftime("%Y%m%d%H%M%S"), :desc => "Package iteration (you should keep the default here)"
|
19
|
+
method_option :user, :type => :string, :desc => "User to run the app under (defaults to your app name)"
|
20
|
+
method_option :group, :type => :string, :desc => "Group to run the app under (defaults to your app name)"
|
21
|
+
method_option :compile_cache_dir, :type => :string, :desc => "Where to store the files cached between packaging runs"
|
22
|
+
method_option :dependencies, :type => :array, :default => [], :desc => "Specific system dependencies that you want to install with the package"
|
23
|
+
method_option :build_dependencies, :type => :array, :default => [], :desc => "Specific system dependencies that must be present before building"
|
24
|
+
method_option :before_precompile, :type => :string, :desc => "Provide a script to run just before the buildpack compilation"
|
25
|
+
method_option :host, :type => :string, :desc => "Remote host to build on (default: local machine)"
|
26
|
+
method_option :auto, :type => :boolean, :default => false, :desc => "Automatically attempt to install missing dependencies"
|
27
|
+
|
28
|
+
def package(tarball)
|
29
|
+
Pkgr.level = Logger::INFO if options[:verbose]
|
30
|
+
Pkgr.level = Logger::DEBUG if options[:debug]
|
31
|
+
|
32
|
+
packager = Dispatcher.new(tarball, options)
|
33
|
+
packager.call
|
34
|
+
rescue Pkgr::Errors::Base => e
|
35
|
+
Pkgr.error "#{e.class.name} : #{e.message}"
|
36
|
+
puts "* ERROR: #{e.message}"
|
37
|
+
exit 1
|
161
38
|
end
|
162
39
|
end
|
163
|
-
|
164
40
|
end
|