pkgr 1.2.0 → 1.3.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 (51) hide show
  1. data/README.md +16 -2
  2. data/data/build_dependencies/centos.yml +13 -0
  3. data/{lib/pkgr/data/distributions/debian/build_dependencies.yml → data/build_dependencies/debian.yml} +2 -2
  4. data/data/build_dependencies/ubuntu.yml +15 -0
  5. data/data/buildpacks/centos-6 +2 -0
  6. data/data/buildpacks/debian-6 +2 -0
  7. data/{lib/pkgr/data/distributions/debian/buildpacks/debian_wheezy → data/buildpacks/debian-7} +1 -1
  8. data/data/buildpacks/ubuntu-10.04 +2 -0
  9. data/{lib/pkgr/data/distributions/debian/buildpacks/ubuntu_precise → data/buildpacks/ubuntu-12.04} +1 -1
  10. data/{lib/pkgr/data/distributions/debian/runner.erb → data/cli/cli.sh.erb} +105 -57
  11. data/data/dependencies/centos.yml +9 -0
  12. data/{lib/pkgr/data/distributions/debian/dependencies.yml → data/dependencies/debian.yml} +2 -2
  13. data/data/dependencies/ubuntu.yml +21 -0
  14. data/data/environment/default.erb +9 -0
  15. data/{lib/pkgr/data/distributions/debian → data}/hooks/postinstall.sh +7 -4
  16. data/data/hooks/preinstall.sh +13 -0
  17. data/{lib/pkgr/data/distributions/debian/sysv → data/init/sysv/lsb-3.1}/master.erb +0 -0
  18. data/{lib/pkgr/data/distributions/debian/sysv → data/init/sysv/lsb-3.1}/process.erb +84 -11
  19. data/{lib/pkgr/data/distributions/debian/sysv → data/init/sysv/lsb-3.1}/process_master.erb +0 -0
  20. data/{lib/pkgr/data/distributions/debian/upstart → data/init/upstart/1.5}/init.d.sh.erb +0 -0
  21. data/{lib/pkgr/data/distributions/debian/upstart → data/init/upstart/1.5}/master.conf.erb +0 -0
  22. data/{lib/pkgr/data/distributions/debian/upstart → data/init/upstart/1.5}/process.conf.erb +0 -0
  23. data/{lib/pkgr/data/distributions/debian/upstart → data/init/upstart/1.5}/process_master.conf.erb +0 -0
  24. data/{lib/pkgr/data/distributions/debian → data/logrotate}/logrotate.erb +0 -0
  25. data/lib/pkgr.rb +1 -1
  26. data/lib/pkgr/builder.rb +8 -2
  27. data/lib/pkgr/buildpack.rb +1 -0
  28. data/lib/pkgr/cli.rb +12 -6
  29. data/lib/pkgr/config.rb +20 -2
  30. data/lib/pkgr/distributions.rb +9 -7
  31. data/lib/pkgr/distributions/base.rb +159 -0
  32. data/lib/pkgr/distributions/centos.rb +12 -0
  33. data/lib/pkgr/distributions/debian.rb +39 -163
  34. data/lib/pkgr/distributions/redhat.rb +51 -0
  35. data/lib/pkgr/distributions/runner.rb +39 -0
  36. data/lib/pkgr/distributions/ubuntu.rb +17 -0
  37. data/lib/pkgr/version.rb +1 -1
  38. metadata +30 -29
  39. data/lib/pkgr/app.rb +0 -279
  40. data/lib/pkgr/data/bin/executable +0 -36
  41. data/lib/pkgr/data/config/pre_boot.rb +0 -15
  42. data/lib/pkgr/data/distributions/debian/buildpacks/debian_squeeze +0 -2
  43. data/lib/pkgr/data/distributions/debian/buildpacks/ubuntu_lucid +0 -2
  44. data/lib/pkgr/data/distributions/debian/cron.d +0 -4
  45. data/lib/pkgr/data/distributions/debian/default.erb +0 -12
  46. data/lib/pkgr/data/distributions/debian/hooks/preinstall.sh +0 -9
  47. data/lib/pkgr/data/pkgr.yml +0 -32
  48. data/lib/pkgr/distributions/debian_squeeze.rb +0 -11
  49. data/lib/pkgr/distributions/debian_wheezy.rb +0 -11
  50. data/lib/pkgr/distributions/ubuntu_lucid.rb +0 -15
  51. data/lib/pkgr/distributions/ubuntu_precise.rb +0 -15
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -e
4
+
5
+ APP_USER="<%= user %>"
6
+
7
+ if ! getent passwd "${APP_USER}" > /dev/null; then
8
+ if [ -f /etc/redhat-release ]; then
9
+ adduser "${APP_USER}" --user-group --system --create-home --shell /bin/bash
10
+ else
11
+ adduser "${APP_USER}" --disabled-login --group --system --quiet --shell /bin/bash
12
+ fi
13
+ fi
@@ -26,7 +26,7 @@ pidfile="/var/run/${full_process_name}.pid"
26
26
 
27
27
  start() {
28
28
  # Run the program!
29
- /usr/local/bin/${name} run ${process_name} >> /var/log/${name}/${process_name}-PROCESS_NUM.log 2>&1 &
29
+ ${name} run ${process_name} >> /var/log/${name}/${process_name}-PROCESS_NUM.log 2>&1 &
30
30
 
31
31
  # Generate the pidfile from here. If we instead made the forked process
32
32
  # generate it there will be a race condition between the pidfile writing
@@ -37,18 +37,86 @@ start() {
37
37
  return 0
38
38
  }
39
39
 
40
+ subpids() {
41
+ local parent=$1
42
+ ps -o pid --ppid ${parent} --noheaders
43
+ }
44
+
45
+ process_kill() {
46
+ local pid=$1
47
+ local sig=$2
48
+ process_status $pid && kill -${sig} ${pid}
49
+ }
50
+
51
+ process_status() {
52
+ local pid=$1
53
+ if kill -0 $pid > /dev/null 2> /dev/null ; then
54
+ return 0
55
+ else
56
+ return 2
57
+ fi
58
+ }
59
+
60
+ stop_childs() {
61
+ local pids=$1
62
+
63
+ if [ ! "$pids" = "" ]; then
64
+ echo "Subprocesses detected ($pids), attempting to kill them first"
65
+ for pid in $pids ; do
66
+
67
+ # start in subshell, otherwise pid variable pollutes parent functions
68
+ (
69
+ stop_childs $(subpids $pid)
70
+ )
71
+
72
+ process_kill $pid "TERM"
73
+
74
+ for i in 1 2 3 4 5 ; do
75
+ echo -n "Waiting for pid $pid to die... "
76
+ process_status $pid || break
77
+ echo ""
78
+ sleep 1
79
+ done
80
+
81
+ if $(process_status $pid) ; then
82
+ echo "subprocess $pid stop failed; still running."
83
+ return 1
84
+ else
85
+ echo "stopped."
86
+ fi
87
+ done
88
+ fi
89
+ }
90
+
91
+ force_stop_childs() {
92
+ local pids=$1
93
+ for pid in $pids ; do
94
+ (
95
+ force_stop_childs $(subpids $pid)
96
+ )
97
+ process_kill $pid "KILL"
98
+ done
99
+ }
100
+
101
+
40
102
  stop() {
41
103
  # Try a few times to kill TERM the program
42
104
  if status ; then
43
- pid=`cat "$pidfile"`
105
+ local pid=`cat "$pidfile"`
44
106
  echo "Killing ${full_process_name} (pid $pid) with SIGTERM"
45
- kill -TERM $pid
46
- # Wait for it to exit.
47
- for i in 1 2 3 4 5 ; do
48
- echo "Waiting ${full_process_name} (pid $pid) to die..."
49
- status || break
50
- sleep 1
51
- done
107
+
108
+ # start in subshell, otherwise pid variable pollutes parent functions
109
+ if ( stop_childs $(subpids $pid) ) ; then
110
+ process_kill $pid "TERM"
111
+
112
+ # Wait for it to exit.
113
+ for i in 1 2 3 4 5 ; do
114
+ echo "Waiting ${full_process_name} (pid $pid) to die..."
115
+ status || break
116
+ sleep 1
117
+ done
118
+ fi
119
+
52
120
  if status ; then
53
121
  echo "${full_process_name} stop failed; still running."
54
122
  else
@@ -59,7 +127,7 @@ stop() {
59
127
 
60
128
  status() {
61
129
  if [ -f "$pidfile" ] ; then
62
- pid=`cat "$pidfile"`
130
+ local pid=`cat "$pidfile"`
63
131
  if kill -0 $pid > /dev/null 2> /dev/null ; then
64
132
  return 0
65
133
  else
@@ -72,8 +140,13 @@ status() {
72
140
 
73
141
  force_stop() {
74
142
  if status ; then
143
+ pid=$(cat "$pidfile")
75
144
  stop
76
- status && kill -KILL `cat "$pidfile"`
145
+ # start in subshell, otherwise pid variable pollutes parent functions
146
+ (
147
+ force_stop_childs $(subpids $pid)
148
+ )
149
+ process_kill $pid "KILL"
77
150
  fi
78
151
  }
79
152
 
@@ -14,7 +14,7 @@ module Pkgr
14
14
  end
15
15
 
16
16
  def data_dir
17
- File.expand_path("../pkgr/data", __FILE__)
17
+ File.expand_path("../../data", __FILE__)
18
18
  end
19
19
  module_function :data_dir
20
20
  end
@@ -38,7 +38,7 @@ module Pkgr
38
38
  # Setup the build directory structure
39
39
  def setup
40
40
  Dir.chdir(build_dir) do
41
- distribution.templates(config.name).each do |template|
41
+ distribution.templates(config).each do |template|
42
42
  template.install(config.sesame)
43
43
  end
44
44
  end
@@ -66,6 +66,12 @@ module Pkgr
66
66
  Pkgr.debug "Loading #{distribution.slug} from #{config_file}."
67
67
  @config = Config.load_file(config_file, distribution.slug).merge(config)
68
68
  Pkgr.debug "Found .pkgr.yml file. Updated config is now: #{config.inspect}"
69
+
70
+ # FIXME: make Config the authoritative source of the runner config (distribution only tells the default runner)
71
+ if @config.runner
72
+ type, *version = @config.runner.split("-")
73
+ distribution.runner = Distributions::Runner.new(type, version.join("-"))
74
+ end
69
75
  end
70
76
  end
71
77
 
@@ -162,7 +168,7 @@ module Pkgr
162
168
 
163
169
  # Path to the directory containing the main app files.
164
170
  def source_dir
165
- File.join(build_dir, "opt/#{config.name}")
171
+ File.join(build_dir, config.home)
166
172
  end
167
173
 
168
174
  # Build directory. Will be used by fpm to make the package.
@@ -85,6 +85,7 @@ module Pkgr
85
85
  def install
86
86
  FileUtils.mkdir_p(buildpack_cache_dir)
87
87
  Dir.chdir(buildpack_cache_dir) do
88
+ puts "-----> Fetching buildpack #{url} at #{branch}"
88
89
  buildpack_install = Mixlib::ShellOut.new("git clone \"#{url}\"")
89
90
  buildpack_install.logger = Pkgr.logger
90
91
  buildpack_install.run_command
@@ -21,7 +21,7 @@ module Pkgr
21
21
  :desc => "Directory where to store the buildpacks",
22
22
  :default => Pkgr::Buildpack.buildpacks_cache_dir
23
23
 
24
- desc "package TARBALL", "Package the given tarball or directory"
24
+ desc "package TARBALL", "Package the given tarball or directory, as a deb or rpm depending on the build machine"
25
25
 
26
26
  method_option :buildpack,
27
27
  :type => :string,
@@ -29,10 +29,6 @@ module Pkgr
29
29
  method_option :buildpack_list,
30
30
  :type => :string,
31
31
  :desc => "Specify a file containing a list of buildpacks to use (--buildpack takes precedence if given)"
32
- method_option :target,
33
- :type => :string,
34
- :default => "deb",
35
- :desc => "Target package to build (only 'deb' supported for now)"
36
32
  method_option :changelog,
37
33
  :type => :string,
38
34
  :desc => "Changelog"
@@ -43,6 +39,9 @@ module Pkgr
43
39
  :type => :string,
44
40
  :default => "x86_64",
45
41
  :desc => "Target architecture for the package"
42
+ method_option :runner,
43
+ :type => :string,
44
+ :desc => "Force a specific runner (e.g. upstart-1.5, sysv-lsb-1.3)"
46
45
  method_option :homepage,
47
46
  :type => :string,
48
47
  :desc => "Project homepage"
@@ -56,6 +55,10 @@ module Pkgr
56
55
  :type => :string,
57
56
  :default => Time.now.strftime("%Y%m%d%H%M%S"),
58
57
  :desc => "Package iteration (you should keep the default here)"
58
+ method_option :license,
59
+ :type => :string,
60
+ :default => nil,
61
+ :desc => "The license of your package (see <https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/#license-short-name>)"
59
62
  method_option :user,
60
63
  :type => :string,
61
64
  :desc => "User to run the app under (defaults to your app name)"
@@ -68,6 +71,9 @@ module Pkgr
68
71
  method_option :before_precompile,
69
72
  :type => :string,
70
73
  :desc => "Provide a script to run just before the buildpack compilation. Path will be resolved from the temporary code repository folder, so use absolute paths if needed."
74
+ method_option :after_precompile,
75
+ :type => :string,
76
+ :desc => "Provide a script to run just after the buildpack compilation. Path will be resolved from the temporary code repository folder, so use absolute paths if needed."
71
77
  method_option :dependencies,
72
78
  :type => :array,
73
79
  :default => [],
@@ -97,7 +103,7 @@ module Pkgr
97
103
  :desc => 'Specify environment variables for buildpack (--env "CURL_TIMEOUT=2" "BUNDLE_WITHOUT=development test")'
98
104
  method_option :force_os,
99
105
  :type => :string,
100
- :desc => 'Force a specific distribution to build for (e.g. --force-os "debian-wheezy")'
106
+ :desc => 'Force a specific distribution to build for (e.g. --force-os "ubuntu-12.04"). This may result in a broken package.'
101
107
 
102
108
  def package(tarball)
103
109
  Pkgr.level = Logger::INFO if options[:verbose]
@@ -3,12 +3,27 @@ require 'yaml'
3
3
 
4
4
  module Pkgr
5
5
  class Config < OpenStruct
6
+ DISTRO_COMPATIBILITY_MAPPING = {
7
+ "ubuntu-lucid" => "ubuntu-10.04",
8
+ "ubuntu-precise" => "ubuntu-12.04",
9
+ "debian-squeeze" => "debian-6",
10
+ "debian-wheezy" => "debian-7"
11
+ }
12
+
6
13
  class << self
7
14
  def load_file(path, distribution)
8
- config = YAML.load_file(path)
15
+ config = YAML.load_file(path) || {}
9
16
  Pkgr.debug "Configuration from file: #{config.inspect} - Distribution: #{distribution.inspect}."
10
17
 
11
18
  targets = config.delete("targets") || {}
19
+
20
+ # backward compatibility
21
+ DISTRO_COMPATIBILITY_MAPPING.each do |from, to|
22
+ if targets.has_key?(from)
23
+ targets[to] = targets.delete(from)
24
+ end
25
+ end
26
+
12
27
  (targets[distribution.to_s] || {}).each do |k,v|
13
28
  config[k] = v
14
29
  end
@@ -128,6 +143,7 @@ module Pkgr
128
143
  end
129
144
  end
130
145
 
146
+ # TODO: DRY this with cli.rb
131
147
  def to_args
132
148
  args = [
133
149
  "--name \"#{name}\"",
@@ -137,7 +153,6 @@ module Pkgr
137
153
  "--iteration \"#{iteration}\"",
138
154
  "--homepage \"#{homepage}\"",
139
155
  "--architecture \"#{architecture}\"",
140
- "--target \"#{target}\"",
141
156
  "--description \"#{description}\"",
142
157
  "--maintainer \"#{maintainer}\""
143
158
  ]
@@ -145,9 +160,12 @@ module Pkgr
145
160
  args.push "--build-dependencies #{build_dependencies.map{|d| "\"#{d}\""}.join}" unless build_dependencies.nil? || build_dependencies.empty?
146
161
  args.push "--compile-cache-dir \"#{compile_cache_dir}\"" unless compile_cache_dir.nil? || compile_cache_dir.empty?
147
162
  args.push "--before-precompile \"#{before_precompile}\"" unless before_precompile.nil? || before_precompile.empty?
163
+ args.push "--after-precompile \"#{after_precompile}\"" unless after_precompile.nil? || after_precompile.empty?
164
+ args.push "--license \"#{license}\"" unless license.nil? || license.empty?
148
165
  args.push "--buildpack \"#{buildpack}\"" unless buildpack.nil? || buildpack.empty?
149
166
  args.push "--buildpack_list \"#{buildpack_list}\"" unless buildpack_list.nil? || buildpack_list.empty?
150
167
  args.push "--force-os \"#{force_os}\"" unless force_os.nil? || force_os.empty?
168
+ args.push "--runner \"#{runner}\"" unless runner.nil? || runner.empty?
151
169
  args.push "--env #{env.variables.map{|v| "\"#{v}\""}.join(" ")}" if env.present?
152
170
  args.push "--auto" if auto
153
171
  args.push "--verbose" if verbose
@@ -1,21 +1,23 @@
1
1
  require 'pkgr/templates/file_template'
2
2
  require 'pkgr/templates/dir_template'
3
- require 'pkgr/distributions/debian'
3
+ require 'pkgr/distributions/base'
4
4
  require 'facter'
5
5
 
6
6
  module Pkgr
7
7
  module Distributions
8
8
  def current(force_os = nil)
9
- distro = if force_os.nil?
10
- [Facter.value('operatingsystem'), Facter.value('lsbdistcodename')]
9
+ os, release = if force_os.nil?
10
+ [Facter.value('operatingsystem'), Facter.value('operatingsystemrelease')]
11
11
  else
12
12
  force_os.split("-")
13
- end.map(&:capitalize).join("")
13
+ end
14
14
 
15
- klass = const_get(distro)
16
- klass.new
15
+ os.downcase!
16
+
17
+ klass = const_get(os.capitalize)
18
+ klass.new(release)
17
19
  rescue NameError => e
18
- raise Errors::UnknownDistribution, "Don't know about the current distribution you're on: #{distro}"
20
+ raise Errors::UnknownDistribution, "Don't know about the current distribution you're on: #{os}-#{release}"
19
21
  end
20
22
  module_function :current
21
23
  end
@@ -0,0 +1,159 @@
1
+ require 'pkgr/buildpack'
2
+ require 'pkgr/env'
3
+ require 'pkgr/distributions/runner'
4
+ require 'yaml'
5
+
6
+ module Pkgr
7
+ module Distributions
8
+ # Base components and behaviors for all distributions.
9
+ class Base
10
+ attr_reader :release
11
+ attr_writer :runner
12
+
13
+ def initialize(release)
14
+ @release = release
15
+ end
16
+
17
+ def os
18
+ self.class.name.split("::")[-1].downcase
19
+ end # def os
20
+
21
+ # e.g. ubuntu-12.04
22
+ def slug
23
+ [os, release].join("-")
24
+ end # def slug
25
+
26
+ def package_test_command(package)
27
+ raise NotImplementedError, "package_test_command must be implemented"
28
+ end
29
+
30
+ def package_install_command(packages)
31
+ raise NotImplementedError, "package_install_command must be implemented"
32
+ end
33
+
34
+ # Check if all build dependencies are present.
35
+ def check(config)
36
+ missing_packages = (build_dependencies(config.build_dependencies) || []).select do |package|
37
+ test_command = package_test_command(package)
38
+ Pkgr.debug "sh(#{test_command})"
39
+ ! system(test_command)
40
+ end
41
+
42
+ unless missing_packages.empty?
43
+ install_command = package_install_command(missing_packages)
44
+ if config.auto
45
+ package_install = Mixlib::ShellOut.new(install_command)
46
+ package_install.logger = Pkgr.logger
47
+ package_install.run_command
48
+ package_install.error!
49
+ else
50
+ Pkgr.warn("Missing build dependencies detected. Run the following to fix: #{install_command}")
51
+ end
52
+ end
53
+ end
54
+
55
+ # e.g. data/buildpacks/ubuntu/12.04
56
+ def default_buildpack_list
57
+ data_file(File.join("buildpacks", slug))
58
+ end # def default_buildpack_list
59
+
60
+ # Returns a list of Buildpack objects
61
+ def buildpacks(config)
62
+ custom_buildpack_uri = config.buildpack
63
+ if custom_buildpack_uri
64
+ uuid = Digest::SHA1.hexdigest(custom_buildpack_uri)
65
+ [Buildpack.new(custom_buildpack_uri, :custom, config.env)]
66
+ else
67
+ load_buildpack_list(config)
68
+ end
69
+ end # def buildpacks
70
+
71
+ def dependencies(other_dependencies = nil)
72
+ deps = YAML.load_file(data_file("dependencies", "#{os}.yml"))
73
+ (deps["default"] || []) | (deps[slug] || []) | (other_dependencies || [])
74
+ end # def dependencies
75
+
76
+ def build_dependencies(other_dependencies = nil)
77
+ deps = YAML.load_file(data_file("build_dependencies", "#{os}.yml"))
78
+ (deps["default"] || []) | (deps[slug] || []) | (other_dependencies || [])
79
+ end # def build_dependencies
80
+
81
+ # Returns a list of file and directory templates.
82
+ def templates(config)
83
+ app_name = config.name
84
+ list = []
85
+
86
+ # directories
87
+ [
88
+ "usr/bin",
89
+ config.home.gsub(/^\//, ""),
90
+ "etc/#{app_name}/conf.d",
91
+ "etc/default",
92
+ "etc/init",
93
+ "var/log/#{app_name}"
94
+ ].each{|dir| list.push Templates::DirTemplate.new(dir) }
95
+
96
+ list.push Templates::FileTemplate.new("etc/default/#{app_name}", data_file("environment", "default.erb"))
97
+ list.push Templates::FileTemplate.new("etc/logrotate.d/#{app_name}", data_file("logrotate", "logrotate.erb"))
98
+
99
+ # Put cli in /usr/bin, as redhat based distros don't have /usr/local/bin in their sudo PATH.
100
+ list.push Templates::FileTemplate.new("usr/bin/#{app_name}", data_file("cli", "cli.sh.erb"), mode: 0755)
101
+
102
+ # NOTE: /etc/appname/conf.d/* files are no longer installed here, since we don't want to overwrite any pre-existing config.
103
+ # They're now installed in the postinstall script.
104
+ list
105
+ end
106
+
107
+ # Returns a list of <Process, FileTemplate> tuples.
108
+ def initializers_for(app_name, procfile_entries)
109
+ list = []
110
+ procfile_entries.select(&:daemon?).each do |process|
111
+ Pkgr.debug "Adding #{process.inspect} to initialization scripts"
112
+ runner.templates(process, app_name).each do |template|
113
+ list.push [process, template]
114
+ end
115
+ end
116
+ list
117
+ end
118
+
119
+ def preinstall_file(config)
120
+ @preinstall_file ||= generate_hook_file("preinstall.sh", config)
121
+ @preinstall_file.path
122
+ end
123
+
124
+ def postinstall_file(config)
125
+ @postinstall_file ||= generate_hook_file("postinstall.sh", config)
126
+ @postinstall_file.path
127
+ end
128
+
129
+ protected
130
+
131
+ def load_buildpack_list(config)
132
+ file = config.buildpack_list || default_buildpack_list
133
+ return [] if file.nil?
134
+
135
+ File.read(file).split("\n").map do |line|
136
+ url, *raw_env = line.split(",")
137
+ buildpack_env = (config.env || Env.new).merge(Env.new(raw_env))
138
+ Buildpack.new(url, :builtin, buildpack_env)
139
+ end
140
+ end # def load_buildpack_list
141
+
142
+ def data_file(*names)
143
+ File.new(File.join(Pkgr.data_dir, *names))
144
+ end
145
+
146
+ def generate_hook_file(hook_name, config)
147
+ source = data_file("hooks", hook_name)
148
+ file = Tempfile.new("postinstall")
149
+ file.write ERB.new(File.read(source)).result(config.sesame)
150
+ file.rewind
151
+ file
152
+ end
153
+
154
+ end # class Base
155
+ end # module Distributions
156
+ end # module Pkgr
157
+
158
+ require 'pkgr/distributions/debian'
159
+ require 'pkgr/distributions/redhat'