pkgr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Cyril Rohr
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,149 @@
1
+ # pkgr
2
+
3
+ Plug this [Railtie](http://api.rubyonrails.org/classes/Rails/Railtie.html)
4
+ into your Rails 3 app (ruby1.9 only), and you'll be ready to package your
5
+ Rails app as a DEB or RPM (coming soon) package.
6
+
7
+ ## Why?
8
+
9
+ [Capistrano](http://capify.org/) is great for deploying Rails/Ruby
10
+ applications, but the deployment recipe can quickly become a mess, and scaling
11
+ the deployment to more than a few servers can prove to be difficult. Plus, if
12
+ you're already using automation tools such as
13
+ [Puppet](http://www.puppetlabs.com/) to configure your servers, you have to
14
+ run two different processes to configure your infrastructure.
15
+
16
+ Another issue with Capistrano is that the hook system is not that powerful.
17
+ Compare that with the pre/post-install/upgrade/uninstall steps that you can
18
+ define in a RPM or DEB package, and you'll quickly see the advantage of
19
+ letting a robust package manager such as `apt` or `yum` handle all those
20
+ things for you in a reliable manner.
21
+
22
+ Last thing, once you built your RPM or DEB package and you tested that it
23
+ works once, you can deploy it on any number of servers at any time and you're
24
+ sure that it will install the required package dependencies, run the hooks,
25
+ and put the files in the directories you specified, creating them as needed.
26
+ Then, you can downgrade or uninstall the whole application in one command.
27
+
28
+ ## How?
29
+
30
+ The issue with Ruby applications is that most of the gems are not (yet)
31
+ packaged in the various Linux distributions. And even if they were, installing
32
+ multiple Ruby applications that need two different versions of the same Ruby
33
+ library would be impossible, since you can't install two different (minor)
34
+ versions of a library with the package managers.
35
+
36
+ So, how are we going to easily package Ruby applications and avoid dependency
37
+ issues? Well, I know package maintainers will scream at me, but we'll just
38
+ vendor the required gems in the package we'll build, and use bundler to manage
39
+ those dependencies. Thus, the only dependency we'll put in our package will be
40
+ the Ruby1.9 (+rubygems).
41
+
42
+ ## What?
43
+
44
+ This gem will allow you to package your Rails3 application, create an `init.d`
45
+ script for you, install a binary file to start your app/rake tasks/console,
46
+ put your configuration files in `/etc/app-name/`, setup a proper logrotate
47
+ file so that your log files don't eat all the disk space of your server, and a
48
+ few other things.
49
+
50
+ The default target installation directory for the other app files will be
51
+ `/opt/local/app-name`. This can be configured.
52
+
53
+ ## Usage
54
+
55
+ Declare `pkgr` as one of your **development** dependencies in your `Gemfile`:
56
+
57
+ group :development do
58
+ gem 'pkgr'
59
+ end
60
+
61
+ Now make sure you have all the gems installed:
62
+
63
+ bundle install
64
+
65
+ `pkgr` will install a number of new rake tasks to handle the packaging
66
+ workflow. But first, you'll have to create a configuration file to get it
67
+ working:
68
+
69
+ rake pkgr:setup
70
+
71
+ This will create a configuration file at `config/pkgr.yml`. Edit it, and fill
72
+ in details about the `name` of your application, description, and the list of
73
+ runtime dependencies it depends on. Same for dependencies required at build
74
+ time only (most of the time, development headers).
75
+
76
+ Now you can generate all the files required for building a debian package:
77
+
78
+ rake pkgr:generate
79
+
80
+ A new directory `debian/` should have been created. You can have a look at it,
81
+ but you should not have to edit anything manually.
82
+
83
+ Once you're ready to package your app, just run the following steps:
84
+
85
+ * Increment the version number:
86
+
87
+ rake pkgr:bump:patch # or rake pkgr:bump:minor or rake pkgr:bump:major
88
+
89
+ * Re-generate the debian files:
90
+
91
+ rake pkgr:generate
92
+
93
+ * Commit your changes (the `pkgr` app will `git archive HEAD`, which means all
94
+ your changes must be committed first -- we may want to change this):
95
+
96
+ commit -am "..."
97
+
98
+ * Build the package on your machine (default, but you better be running a
99
+ Debian Squeeze), or on a remote machine (recommended, for instance you can
100
+ get a Vagrant VM in no time):
101
+
102
+ HOST=debian-build-machine rake pkgr:build:deb
103
+ # or HOST=localhost rake pkgr:build:deb, or just rake pkgr:build:deb
104
+
105
+ Note that the user with which you're connecting to the build machine **must
106
+ have `sudo` privileges** (required to install build and runtime
107
+ dependencies).
108
+
109
+ Also, it's most likely that you'll have to do this a few times at first, as
110
+ well as adding missing runtime and build dependencies, before your app can
111
+ be successfully packaged.
112
+
113
+ * Your .deb package should be made available in the `pkg` directory of your
114
+ app. Next step is probably to upload it to a local apt repository, and then
115
+ a simple `apt-get install my-app` will install everything. Enjoy!
116
+
117
+
118
+
119
+ ## Requirements
120
+
121
+ * You must use Rails3+ and ruby1.9+ in your application. This may work with
122
+ other rubies but then you'll need to add a rubygems dependency.
123
+
124
+ * Your Rails application must be able to run with the
125
+ [`thin`](http://code.macournoyer.com/thin/) web server. Don't forget to add
126
+ `thin` to your Gemfile!
127
+
128
+ * Your application must be checked into a **Git** repository. Your name and
129
+ email is taken from the git configuration, and the changelog is populated
130
+ based on the git log between two versions.
131
+
132
+ ## TODO
133
+
134
+ * Speed up the packaging process (currently, bundler re-downloads all the gems
135
+ each time you package an app).
136
+
137
+ * Include tasks for building RPMs.
138
+
139
+ * Better debian initd script.
140
+
141
+ * Some tests.
142
+
143
+ ## Authors
144
+
145
+ * Cyril Rohr <cyril.rohr@gmail.com> - <http://crohr.me>
146
+
147
+ ## Copyright
148
+
149
+ See LICENSE (MIT)
@@ -0,0 +1,35 @@
1
+ require 'pkgr/app'
2
+ require 'pkgr/railtie' if defined?(Rails)
3
+
4
+ module Pkgr
5
+ DEBIAN_DIR = "debian"
6
+
7
+ def self.setup(root)
8
+ setup_config(root)
9
+ end
10
+
11
+ protected
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:debian' to generate the debian control 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
34
+ end
35
+ end
@@ -0,0 +1,246 @@
1
+ require 'rake'
2
+ require 'erb'
3
+
4
+ module Pkgr
5
+ class App
6
+ include RakeFileUtils
7
+ attr_reader :root
8
+ attr_reader :errors
9
+ attr_reader :config
10
+
11
+ # +root+: the root directory of the app.
12
+ # +config+ a Configuration object, hosting the parameters defined in `config/pkgr.yml`.
13
+ def initialize(root, config_path)
14
+ @root = root
15
+ load_config(config_path)
16
+ @errors = []
17
+ end
18
+
19
+ def load_config(path)
20
+ @config = YAML::load_file(path)
21
+ 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)
22
+ @config['_path'] = path
23
+ end
24
+
25
+ def write_config
26
+ File.open(@config['_path'] || raise("Don't know where to save myself!"), "w+") {|f|
27
+ YAML.dump(@config.reject{|k,v| k == '_path'}, f)
28
+ }
29
+ end
30
+
31
+ # Returns true if the app is correctly configured. Else otherwise.
32
+ def valid?
33
+ @errors.clear
34
+ @errors.push("is not a valid git repository") unless File.exist?(File.join(@root, ".git", "HEAD"))
35
+ @errors.push("must have a name") unless @config.fetch('name')
36
+ @errors.push("must have a valid name ([a-zA-Z0-9_-])") unless @config.fetch('name').scan(/[^a-z0-9\_\-]/i)
37
+ @errors.push("must have a version") unless @config.fetch('version')
38
+ @errors.push("must have a valid target architecture") unless @config.fetch('architecture')
39
+ @errors.empty?
40
+ end
41
+
42
+ def generate_required_files
43
+ setup_debian
44
+ setup_binary
45
+ end
46
+
47
+ def git_ref
48
+ @config.fetch('git_ref') { 'HEAD' }
49
+ end
50
+
51
+ def prefix
52
+ @config.fetch('prefix') { "/opt/local" }
53
+ end
54
+
55
+ def author_name
56
+ @author_name ||= `git config --get user.name`.chomp
57
+ end
58
+
59
+ def author_email
60
+ @author_email ||= `git config --get user.email`.chomp
61
+ end
62
+
63
+ def name
64
+ @config['name']
65
+ end
66
+
67
+ def description
68
+ @config['description'] || ""
69
+ end
70
+
71
+ def debian_build_dependencies(installable_only = false)
72
+ deps = @config['debian_build_dependencies'] || []
73
+ if installable_only
74
+ deps = deps.reject{|d| d =~ /[\$\{\}]/}.map{|d| d.split(/\s/)[0]}
75
+ end
76
+ deps
77
+ end
78
+
79
+ def debian_runtime_dependencies(installable_only = false)
80
+ deps = @config['debian_runtime_dependencies'] || []
81
+ if installable_only
82
+ deps = deps.reject{|d| d =~ /[\$\{\}]/}.map{|d| d.split(/\s/)[0]}
83
+ end
84
+ deps
85
+ end
86
+
87
+ def architecture
88
+ @config['architecture'] || "all"
89
+ end
90
+
91
+ def homepage
92
+ @config['homepage'] || ""
93
+ end
94
+
95
+ def config_files
96
+ @config['config_files'] || []
97
+ end
98
+
99
+ def version
100
+ @config['version']
101
+ end
102
+
103
+ def user
104
+ @config.fetch('user') { name }
105
+ end
106
+
107
+ def group
108
+ @config.fetch('group') { name }
109
+ end
110
+
111
+ # prefix without the leading slash.
112
+ def pkg_prefix
113
+ prefix[1..-1]
114
+ end
115
+
116
+ def setup_debian
117
+ target = File.join(root, Pkgr::DEBIAN_DIR)
118
+ Pkgr.mkdir(target)
119
+
120
+ Dir[File.expand_path("../data/debian/*", __FILE__)].each do |file|
121
+ case File.extname(file)
122
+ when ".erb"
123
+ file_target = File.join(target, File.basename(file, ".erb"))
124
+ File.open(file_target, "w+") do |f|
125
+ f << ERB.new(File.read(file)).result(binding)
126
+ end
127
+ else
128
+ file_target = File.join(target, File.basename(file))
129
+ if File.exist?(file_target)
130
+ puts "File #{file_target} already exists. Skipped."
131
+ else
132
+ FileUtils.cp(file, file_target, :verbose => true)
133
+ end
134
+ end
135
+ end
136
+
137
+ puts "Correctly set up debian files."
138
+ end
139
+
140
+ # Creates an executable file for easy launch of the server/console/rake tasks once it is installed.
141
+ # E.g. /usr/bin/my-app console, /usr/bin/my-app server start -p 8080
142
+ def setup_binary
143
+ target = File.join(root, "bin", name)
144
+ Pkgr.mkdir(File.dirname(target))
145
+ FileUtils.cp(File.expand_path("../data/bin/executable", __FILE__), target, :verbose => true)
146
+ FileUtils.chmod 0755, target, :verbose => true
147
+ puts "Correctly set up executable file. Try running './bin/#{name} console'."
148
+ end
149
+
150
+ # FIXME: this is ugly
151
+ def bump!(version_index = :patch)
152
+ indices = [:major, :minor, :patch]
153
+ index = indices.index(version_index) || raise(ArgumentError, "The given version index is not valid (#{version_index})")
154
+ version = @config.fetch('version') { '0.0.0' }
155
+ fragments = version.split(".")
156
+ fragments[index] = fragments[index].to_i+1
157
+ ((index+1)..2).each{|i|
158
+ fragments[i] = 0
159
+ }
160
+ new_version = fragments.join(".")
161
+
162
+ changelog = File.read(debian_file("changelog"))
163
+
164
+ last_commit = changelog.scan(/\s+\* ([a-z0-9]{7}) /).flatten[0]
165
+
166
+ cmd = "git log --oneline"
167
+ cmd << " #{last_commit}..#{git_ref}" unless last_commit.nil?
168
+ result = %x{#{cmd}}
169
+ ok = $?.exitstatus == 0
170
+ if !ok
171
+ raise "Command failed. Aborting."
172
+ else
173
+ content_changelog = [
174
+ "#{name} (#{new_version}-1) unstable; urgency=low",
175
+ "",
176
+ result.split("\n").reject{|l| l =~ / v#{version}/}.map{|l| " * #{l}"}.join("\n"),
177
+ "",
178
+ " -- #{author_name} <#{author_email}> #{Time.now.strftime("%a, %d %b %Y %H:%M:%S %z")}",
179
+ "",
180
+ changelog
181
+ ].join("\n")
182
+
183
+ File.open(debian_file("changelog"), "w+") do |f|
184
+ f << content_changelog
185
+ end
186
+
187
+ @config['version'] = new_version
188
+ write_config
189
+
190
+ puts "Committing changelog and version file..."
191
+ files_to_commit = [debian_file('changelog'), @config['_path']]
192
+ sh "git add #{files_to_commit.join(" ")} && git commit -m 'v#{new_version}' #{files_to_commit.join(" ")}"
193
+ end
194
+ end
195
+
196
+ def build_debian_package(host)
197
+ puts "Building debian package on '#{host}'..."
198
+ Dir.chdir(root) do
199
+ Pkgr.mkdir("pkg")
200
+ case host
201
+ when 'localhost'
202
+ debian_steps.each do |step|
203
+ sh step
204
+ end
205
+ else
206
+ archive = "#{name}-#{version}"
207
+ sh "scp #{File.expand_path("../data/config/pre_boot.rb", __FILE__)} #{host}:/tmp/"
208
+ cmd = %Q{
209
+ git archive #{git_ref} --prefix=#{archive}/ | ssh #{host} 'cat - > /tmp/#{archive}.tar &&
210
+ set -x && rm -rf /tmp/#{archive} &&
211
+ cd /tmp && tar xf #{archive}.tar && cd #{archive} &&
212
+ cat config/boot.rb >> /tmp/pre_boot.rb && cp -f /tmp/pre_boot.rb config/boot.rb &&
213
+ #{debian_steps.join(" &&\n")}'
214
+ }
215
+ sh cmd
216
+ # Fetch the .deb, and put it in the `pkg` directory
217
+ sh "scp #{host}:/tmp/#{name}_#{version}*.deb pkg/"
218
+ end
219
+ end
220
+ end
221
+
222
+ def debian_steps
223
+ target_vendor = "vendor/bundle/ruby/1.9.1"
224
+ [
225
+ "sudo apt-get install #{debian_runtime_dependencies(true).join(" ")} -y",
226
+ "sudo apt-get install #{debian_build_dependencies(true).join(" ")} -y",
227
+ # Vendor bundler
228
+ "gem1.9.1 install bundler --no-ri --no-rdoc --version #{bundler_version} -i #{target_vendor}",
229
+ "GEM_HOME='#{target_vendor}' #{target_vendor}/bin/bundle install --deployment --without test development",
230
+ "rm -rf #{target_vendor}/{cache,doc}",
231
+ "dpkg-buildpackage -us -uc -d"
232
+ ]
233
+ end
234
+
235
+ private
236
+ def bundler_version
237
+ @config.fetch('bundler_version') { '1.1.3' }
238
+ end
239
+
240
+ def debian_file(filename)
241
+ file = File.join(Pkgr::DEBIAN_DIR, filename)
242
+ return nil unless File.exist?(file)
243
+ file
244
+ end
245
+ end
246
+ end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'yaml'
4
+
5
+ config = YAML.load_file(::File.expand_path("../../config/pkgr.yml", __FILE__))
6
+
7
+ require ::File.expand_path("../../config/boot", __FILE__)
8
+
9
+ supported_commands = ["server", "rake", "console"]
10
+ command = ARGV.shift
11
+
12
+ case command
13
+ when "rake"
14
+ ENV['RACK_ENV'] ||= "production"
15
+ ARGV << "-f" << ::File.expand_path("../../Rakefile", __FILE__)
16
+ require 'rake'
17
+ Rake.application.run
18
+ when "console"
19
+ APP_PATH = ::File.expand_path('../../config/application', __FILE__)
20
+ require ::File.expand_path('../../config/boot', __FILE__)
21
+ ARGV.push("production") if ARGV.empty?
22
+ ARGV.unshift("console")
23
+ require 'rails/commands'
24
+ when "server"
25
+ require 'thin'
26
+ rackup_file = ::File.expand_path('../../config.ru', __FILE__)
27
+ argv = ARGV
28
+ argv << ["-R", rackup_file] unless ARGV.include?("-R")
29
+ argv << ["-p", "8000"] unless ARGV.include?("-p")
30
+ argv << ["-e", "production"] unless ARGV.include?("-e")
31
+ argv << ["--tag", "#{config['name']}-#{config['version']}"] unless ARGV.include?("--tag")
32
+ Thin::Runner.new(argv.flatten).run!
33
+ else
34
+ STDERR.puts "You must choose one of the following commands: #{supported_commands.inspect}"
35
+ exit(1)
36
+ end
@@ -0,0 +1,15 @@
1
+ # This part of code is added by Pkgr, before the original content of the
2
+ # `config/boot.rb` file.
3
+ require 'rubygems'
4
+
5
+ # Attempts to use a vendored Bundler, if any
6
+ vendored_gems = File.expand_path(
7
+ '../../vendor/bundle/ruby/1.9.1/gems', __FILE__
8
+ )
9
+
10
+ vendored_bundler = Dir["#{vendored_gems}/bundler-*/lib"].sort.last
11
+
12
+ if !vendored_bundler.nil? && !$LOAD_PATH.include?(vendored_bundler)
13
+ $LOAD_PATH.unshift(vendored_bundler)
14
+ end
15
+
File without changes
@@ -0,0 +1,12 @@
1
+ Source: <%= name %>
2
+ Section: unknown
3
+ Priority: extra
4
+ Maintainer: <%= author_name %> <<%= author_email %>>
5
+ Build-Depends: <%= debian_build_dependencies.join(",") %>
6
+ Standards-Version: 3.7.3
7
+ Homepage: <%= homepage %>
8
+
9
+ Package: <%= name %>
10
+ Architecture: <%= architecture %>
11
+ Depends: <%= debian_runtime_dependencies.join(", ") %>
12
+ Description: <%= description %>
@@ -0,0 +1,17 @@
1
+ This package was debianized by Pkgr <http://crohr.me/pkgr> on <%= Time.now.to_s %>.
2
+
3
+ It was downloaded from <ssh://somewhere>
4
+
5
+ Upstream Author(s):
6
+
7
+ <%= author_name %> <<%=author_email %>>
8
+
9
+ Copyright:
10
+
11
+ Some copyright here
12
+
13
+ License:
14
+
15
+ <Put the license of the package here indented by 4 spaces>
16
+
17
+ The Debian packaging is public domain.
@@ -0,0 +1,4 @@
1
+ #
2
+ # Put your cron tasks here
3
+ #
4
+ # 0 4 * * * root [ -x /usr/bin/some_script ] && /usr/bin/some_script
@@ -0,0 +1,11 @@
1
+ # Defaults for <%= name %> initscript
2
+ # sourced by /etc/init.d/<%= name %>
3
+ # installed at /etc/default/<%= name %> by the maintainer scripts
4
+
5
+ #
6
+ # This is a POSIX shell fragment
7
+ #
8
+
9
+ # Additional options that are passed to the Daemon.
10
+ DAEMON_OPTS="server -d --pid $PIDFILE --user $NAME --group $NAME --log /var/log/$NAME/thin.log"
11
+
@@ -0,0 +1,2 @@
1
+ var/log/<%= name %>
2
+ var/db/<%= name %>
File without changes
@@ -0,0 +1,155 @@
1
+ #! /bin/sh
2
+ #
3
+ ### BEGIN INIT INFO
4
+ # Provides: <%= name %>
5
+ # Required-Start: $remote_fs $syslog
6
+ # Required-Stop: $remote_fs $syslog
7
+ # Default-Start: 2 3 4 5
8
+ # Default-Stop: 0 1 6
9
+ # Short-Description: Start <%= name %> app at boot time.
10
+ # Description: Enable service provided by <%= name %>.
11
+ ### END INIT INFO
12
+ #
13
+
14
+ PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
15
+ NAME="<%= name %>"
16
+ DAEMON=/usr/bin/$NAME
17
+ DESC=$NAME
18
+
19
+ test -x $DAEMON || exit 0
20
+
21
+ LOGDIR=/var/log/$NAME
22
+ PIDFILE=/var/run/$NAME.pid
23
+ DODTIME=5 # Time to wait for the server to die, in seconds
24
+ # If this value is set too low you might not
25
+ # let some servers to die gracefully and
26
+ # 'restart' will not work
27
+
28
+ # Include defaults if available
29
+ if [ -f /etc/default/$NAME ] ; then
30
+ . /etc/default/$NAME
31
+ fi
32
+
33
+ set -e
34
+
35
+
36
+ running_pid()
37
+ {
38
+ # Check if a given process status name matches a given name
39
+ pid=$1
40
+ name=$2
41
+ [ -z "$pid" ] && return 1
42
+ [ ! -d /proc/$pid ] && return 1
43
+ cmd=`cat /proc/$pid/status | grep Name: | cut -f 2`
44
+ # Is this the expected child?
45
+ [ "$cmd" != "$name" ] && return 1
46
+ return 0
47
+ }
48
+
49
+ running()
50
+ {
51
+ # Check if the process is running looking at /proc
52
+ # (works for all users)
53
+ # No pidfile, probably no daemon present
54
+ [ ! -f "$PIDFILE" ] && return 1
55
+ # Obtain the pid
56
+ pid=`cat $PIDFILE`
57
+ running_pid $pid $NAME || return 1
58
+ return 0
59
+ }
60
+
61
+ force_stop() {
62
+ # Forcefully kill the process
63
+ [ ! -f "$PIDFILE" ] && return
64
+ if running ; then
65
+ kill -15 $pid
66
+ # Is it really dead?
67
+ [ -n "$DODTIME" ] && sleep "$DODTIME"s
68
+ if running ; then
69
+ kill -9 $pid
70
+ [ -n "$DODTIME" ] && sleep "$DODTIME"s
71
+ if running ; then
72
+ echo "Cannot kill $NAME (pid=$pid)!"
73
+ exit 1
74
+ fi
75
+ fi
76
+ fi
77
+ rm -f $PIDFILE
78
+ return 0
79
+ }
80
+
81
+ case "$1" in
82
+ start)
83
+ echo -n "Starting $DESC: "
84
+ if running ; then
85
+ echo "already running."
86
+ else
87
+ $DAEMON $DAEMON_OPTS start
88
+ # Needed to let Thin handle stale pid file.
89
+ sleep 1
90
+ if running ; then
91
+ echo "OK."
92
+ else
93
+ echo "ERROR."
94
+ fi
95
+ fi
96
+ ;;
97
+ stop)
98
+ echo -n "Stopping $DESC: "
99
+ $DAEMON $DAEMON_OPTS stop
100
+ echo "OK."
101
+ ;;
102
+ force-stop)
103
+ echo -n "Forcefully stopping $DESC: "
104
+ force_stop
105
+ if ! running ; then
106
+ echo "OK."
107
+ else
108
+ echo "ERROR."
109
+ fi
110
+ ;;
111
+ #reload)
112
+ #
113
+ # If the daemon can reload its config files on the fly
114
+ # for example by sending it SIGHUP, do it here.
115
+ #
116
+ # If the daemon responds to changes in its config file
117
+ # directly anyway, make this a do-nothing entry.
118
+ #
119
+ # echo "Reloading $DESC configuration files."
120
+ # start-stop-daemon --stop --signal 1 --quiet --pidfile \
121
+ # /var/run/$NAME.pid --exec $DAEMON
122
+ #;;
123
+ force-reload)
124
+ #
125
+ # If the "reload" option is implemented, move the "force-reload"
126
+ # option to the "reload" entry above. If not, "force-reload" is
127
+ # just the same as "restart" except that it does nothing if the
128
+ # daemon isn't already running.
129
+ # check wether $DAEMON is running. If so, restart
130
+ if running ; then
131
+ $0 restart
132
+ fi
133
+ ;;
134
+ restart)
135
+ echo "Restarting $DESC..."
136
+ $0 stop && $0 start
137
+ ;;
138
+ status)
139
+ echo -n "$NAME is "
140
+ if running ; then
141
+ echo "running."
142
+ else
143
+ echo "not running."
144
+ exit 1
145
+ fi
146
+ ;;
147
+ *)
148
+ N=/etc/init.d/$NAME
149
+ # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
150
+ echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2
151
+ exit 1
152
+ ;;
153
+ esac
154
+
155
+ exit 0
@@ -0,0 +1,16 @@
1
+ <% config_files.each do |file| %>
2
+ config/<%= file %> etc/<%= name %>
3
+ <% end %>
4
+ config <%= pkg_prefix %>/<%= name %>
5
+ .bundle <%= pkg_prefix %>/<%= name %>
6
+ Gemfile <%= pkg_prefix %>/<%= name %>
7
+ Gemfile.lock <%= pkg_prefix %>/<%= name %>
8
+ config.ru <%= pkg_prefix %>/<%= name %>
9
+ Rakefile <%= pkg_prefix %>/<%= name %>
10
+ app <%= pkg_prefix %>/<%= name %>
11
+ bin <%= pkg_prefix %>/<%= name %>
12
+ db/* var/db/<%= name %>
13
+ lib <%= pkg_prefix %>/<%= name %>
14
+ public <%= pkg_prefix %>/<%= name %>
15
+ script <%= pkg_prefix %>/<%= name %>
16
+ vendor <%= pkg_prefix %>/<%= name %>
@@ -0,0 +1,5 @@
1
+ <% config_files.each do |file| %>
2
+ etc/<%= name %>/<%= file %> <%= pkg_prefix %>/<%= name %>/config/<%= file %>
3
+ <% end %>
4
+ var/log/<%= name %> <%= pkg_prefix %>/<%= name %>/log
5
+ var/db/<%= name %> <%= pkg_prefix %>/<%= name %>/db
@@ -0,0 +1,10 @@
1
+ # <%= name %> logs:
2
+ /var/log/<%= name %>/*.log {
3
+ daily
4
+ missingok
5
+ rotate 14
6
+ compress
7
+ delaycompress
8
+ notifempty
9
+ copytruncate
10
+ }
@@ -0,0 +1,59 @@
1
+ #!/bin/sh
2
+ # postinst script for $NAME
3
+ #
4
+ # see: dh_installdeb(1)
5
+
6
+ set -e
7
+
8
+ # summary of how this script can be called:
9
+ # * <postinst> `configure' <most-recently-configured-version>
10
+ # * <old-postinst> `abort-upgrade' <new version>
11
+ # * <conflictor's-postinst> `abort-remove' `in-favour' <package>
12
+ # <new-version>
13
+ # * <postinst> `abort-remove'
14
+ # * <deconfigured's-postinst> `abort-deconfigure' `in-favour'
15
+ # <failed-install-package> <version> `removing'
16
+ # <conflicting-package> <version>
17
+ # for details, see http://www.debian.org/doc/debian-policy/ or
18
+ # the debian-policy package
19
+
20
+ NAME="<%= name %>"
21
+ PREFIX="<%= prefix %>"
22
+ USER="<%= user %>"
23
+ GROUP="<%= group %>"
24
+
25
+ case "$1" in
26
+ configure)
27
+
28
+ if [ ! -f $PREFIX/$NAME/bin/$NAME.rb ]; then
29
+ mv $PREFIX/$NAME/bin/$NAME $PREFIX/$NAME/bin/$NAME.rb
30
+ fi
31
+ echo "#!/usr/bin/ruby1.9.1
32
+ require '$PREFIX/$NAME/bin/$NAME'
33
+ " > /usr/bin/$NAME && chmod a+x /usr/bin/$NAME
34
+ # Creating the user if it does not exist
35
+ if ! getent passwd $USER > /dev/null; then
36
+ adduser --no-create-home --system --group $GROUP
37
+ fi
38
+ chown -R $USER.$GROUP /etc/$NAME/
39
+ chown -R $USER.$GROUP /var/db/$NAME/
40
+ chown -R $USER.$GROUP /var/log/$NAME/
41
+ ;;
42
+
43
+ abort-upgrade|abort-remove|abort-deconfigure)
44
+ ;;
45
+
46
+ *)
47
+ echo "postinst called with unknown argument \`$1'" >&2
48
+ exit 1
49
+ ;;
50
+ esac
51
+
52
+ # dh_installdeb will replace this with shell code automatically
53
+ # generated by other debhelper scripts.
54
+
55
+ #DEBHELPER#
56
+
57
+ exit 0
58
+
59
+
@@ -0,0 +1,57 @@
1
+ #!/bin/sh
2
+ # prerm script for $NAME
3
+ #
4
+ # see: dh_installdeb(1)
5
+
6
+ set -e
7
+
8
+ # summary of how this script can be called:
9
+ # * <prerm> `remove'
10
+ # * <old-prerm> `upgrade' <new-version>
11
+ # * <new-prerm> `failed-upgrade' <old-version>
12
+ # * <conflictor's-prerm> `remove' `in-favour' <package> <new-version>
13
+ # * <deconfigured's-prerm> `deconfigure' `in-favour'
14
+ # <package-being-installed> <version> `removing'
15
+ # <conflicting-package> <version>
16
+ # for details, see http://www.debian.org/doc/debian-policy/ or
17
+ # the debian-policy package
18
+
19
+ NAME="<%= name %>"
20
+ PREFIX="<%= prefix %>"
21
+ USER="<%= user %>"
22
+ GROUP="<%= group %>"
23
+
24
+ cleanup()
25
+ {
26
+ /etc/init.d/$NAME stop || true
27
+ rm /usr/bin/$NAME
28
+ mv $PREFIX/$NAME/bin/$NAME.rb $PREFIX/$NAME/bin/$NAME
29
+ return 0;
30
+ }
31
+
32
+ case "$1" in
33
+ remove)
34
+ cleanup
35
+ deluser $USER || true
36
+ ;;
37
+ upgrade|deconfigure)
38
+ cleanup
39
+ ;;
40
+
41
+ failed-upgrade)
42
+ ;;
43
+
44
+ *)
45
+ echo "prerm called with unknown argument \`$1'" >&2
46
+ exit 1
47
+ ;;
48
+ esac
49
+
50
+ # dh_installdeb will replace this with shell code automatically
51
+ # generated by other debhelper scripts.
52
+
53
+ #DEBHELPER#
54
+
55
+ exit 0
56
+
57
+
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/make -f
2
+
3
+ export DH_VERBOSE=1
4
+
5
+
6
+ %:
7
+ dh $@
@@ -0,0 +1,31 @@
1
+ version: 0.0.0
2
+ name:
3
+ description:
4
+ # The git reference from which to build the package:
5
+ git_ref: HEAD
6
+ # The list of configuration files taht you want to see in /etc/{{name}}/
7
+ config_files:
8
+ - pkgr.yml
9
+ - database.yml
10
+ # The target architecture of the server on which your app will be built (must
11
+ # be the same as the one on which it is deployed):
12
+ architecture: amd64
13
+ # The list of dependencies required for your app to correctly run:
14
+ debian_runtime_dependencies:
15
+ - ${shlibs:Depends}
16
+ - ${misc:Depends}
17
+ - ruby1.9.1-full
18
+ - git-core
19
+ - libxml2
20
+ - libxslt1.1
21
+ # The list of dependencies required for your app to be packaged (i.e.
22
+ # dependencies of your app's gems + dependencies required to build the
23
+ # package):
24
+ debian_build_dependencies:
25
+ - debhelper (>= 7)
26
+ - dpkg-dev
27
+ - libmysqlclient15-dev
28
+ - libxml2-dev
29
+ - libxslt-dev
30
+ - libsqlite3-dev
31
+
@@ -0,0 +1,42 @@
1
+ # ROOT=. rake -I lib -f lib/pkgr/pkgr.rake pkgr:setup
2
+
3
+ require 'pkgr'
4
+ require 'fileutils'
5
+
6
+ ROOT = ENV.fetch('ROOT') { Rails.root }
7
+ CONFIG = ENV.fetch('CONFIG') { File.join(ROOT, "config/pkgr.yml") }
8
+ if File.exist?(CONFIG)
9
+ APP = Pkgr::App.new ROOT, CONFIG
10
+ APP.valid? || fail("There is an issue with the app you're trying to package: #{APP.errors.join(", ")}")
11
+ end
12
+
13
+ namespace :pkgr do
14
+
15
+ desc "Setup the required files for pkgr"
16
+ task :setup do
17
+ Pkgr.setup(ROOT)
18
+ end
19
+
20
+ if defined?(APP)
21
+ task :generate do
22
+ APP.generate_required_files
23
+ end
24
+
25
+ namespace :bump do
26
+ %w{patch minor major}.each do |version|
27
+ desc "Increments the #{version} version by one"
28
+ task version.to_sym do
29
+ APP.bump!(version.to_sym)
30
+ end
31
+ end
32
+ end
33
+
34
+ namespace :build do
35
+ desc "Builds the debian package"
36
+ task :deb do
37
+ build_host = ENV.fetch('HOST') { 'localhost' }
38
+ APP.build_debian_package(build_host)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ module Pkgr
2
+ class Railtie < Rails::Railtie
3
+ rake_tasks do
4
+ load File.expand_path("../pkgr.rake", __FILE__)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Pkgr
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,105 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pkgr
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Cyril Rohr
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-03 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '0.8'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '0.8'
30
+ - !ruby/object:Gem::Dependency
31
+ name: rspec
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: '2'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: '2'
46
+ description: Package your Rails apps as debian packages
47
+ email:
48
+ - cyril.rohr@gmail.com
49
+ executables: []
50
+ extensions: []
51
+ extra_rdoc_files:
52
+ - LICENSE
53
+ - README.md
54
+ files:
55
+ - lib/pkgr/app.rb
56
+ - lib/pkgr/data/bin/executable
57
+ - lib/pkgr/data/config/pre_boot.rb
58
+ - lib/pkgr/data/debian/changelog
59
+ - lib/pkgr/data/debian/compat.erb
60
+ - lib/pkgr/data/debian/control.erb
61
+ - lib/pkgr/data/debian/copyright.erb
62
+ - lib/pkgr/data/debian/cron.d
63
+ - lib/pkgr/data/debian/default.erb
64
+ - lib/pkgr/data/debian/dirs.erb
65
+ - lib/pkgr/data/debian/docs.erb
66
+ - lib/pkgr/data/debian/init.d.erb
67
+ - lib/pkgr/data/debian/install.erb
68
+ - lib/pkgr/data/debian/links.erb
69
+ - lib/pkgr/data/debian/logrotate.erb
70
+ - lib/pkgr/data/debian/postinst.erb
71
+ - lib/pkgr/data/debian/prerm.erb
72
+ - lib/pkgr/data/debian/rules.erb
73
+ - lib/pkgr/data/pkgr.yml
74
+ - lib/pkgr/pkgr.rake
75
+ - lib/pkgr/railtie.rb
76
+ - lib/pkgr/version.rb
77
+ - lib/pkgr.rb
78
+ - LICENSE
79
+ - README.md
80
+ homepage: http://github.com/crohr/pkgr
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --charset=UTF-8
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '1.9'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '1.3'
99
+ requirements: []
100
+ rubyforge_project:
101
+ rubygems_version: 1.8.21
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Package your Rails apps as debian packages
105
+ test_files: []