cany 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 575282993ba4ffbbf4a1f932a57658c6d570965e
4
+ data.tar.gz: 8bcf88c7b8cf69da3108189061c06229f15b739e
5
+ SHA512:
6
+ metadata.gz: 10d981813625901b4618e2d15679c0b898f064964f2780c8bbc6f2e2c1cadc9cbabdccfd5c138dd6d5c90183a5bfc8cca2d265465fc22c45c5f08a7c86aeffa9
7
+ data.tar.gz: da1ad37fd1fff55b7d7f0f9fa51840038bd44c5c0f4a57f0fb34bc0fc6b897b5a1414010857e0eddf01ac7d12230e88308a04dadea4e94764d25944e993cb309
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ *.iml
4
+ .idea
5
+ .bundle
6
+ .config
7
+ .yardoc
8
+ Gemfile.lock
9
+ InstalledFiles
10
+ _yardoc
11
+ coverage
12
+ doc/
13
+ lib/bundler/man
14
+ pkg
15
+ rdoc
16
+ spec/reports
17
+ tmp
18
+
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in cany.gemspec
4
+ gemspec
5
+
6
+ group :test do
7
+ gem 'deb_control', '~> 0.0.1'
8
+ gem 'timecop'
9
+ end
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Malte Swart
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,115 @@
1
+ # Cany
2
+
3
+ Cany is a toolkit to create easily distribution packages from your (ruby) application. The goal is to reduce the packaging work to managing the application meta data (specification).
4
+
5
+ The goal is to support all (common) package manager - all from the some specification, although at the moment is only dpkg implemented.
6
+
7
+ The difference to other packaging tools is that cany uses as much tools as possible to build packages in the recommended way.
8
+
9
+ **Warning:** The gem has successfully built packages. But there are known limitations or problems. We collecting knowledge with the current usage and appreciate your feedback. With the 1.0 we will start with semantic visioning. Until then every updates tries to be as much compatible as possible but the more important goal is to create a better architecture and design -- so be careful when updating this gem.
10
+
11
+
12
+ ## Installation
13
+
14
+ Cany is a rubygem, it needs **ruby >=1.9.3** to work. It is design to be lightweight, therefore a:
15
+
16
+ $ gem install cany
17
+
18
+ is enough to install and use it. But you can add is also to your application's Gemfile:
19
+
20
+ ```ruby
21
+ gem 'cany'
22
+ ```
23
+
24
+ And then execute:
25
+
26
+ $ bundle
27
+
28
+ To let bundle install it for you.
29
+
30
+
31
+ ## Write a Specification for your Application
32
+
33
+ Create a file ``<your application name>.canspec`` inside your application folder:
34
+
35
+ ```ruby
36
+ Cany::Specification.new do
37
+ name 'example-application' # This is used as package name - please you only ASCII letters, - and literals.
38
+ version '0.1' # Your application's version
39
+ description 'This example application is used to have a application for that this README can describe how it is packaged with cany' # A short description for you application. Should not longer than a few paragraphs
40
+ maintainer_name 'Hans Otto' # The person/organisation maintaining the package
41
+ maintainer_email 'hans.otto@example.org' # A eMail address to contact the maintainer
42
+ website 'http://example.org/cany' # A website to get more information about the application
43
+ licence 'MIT' # Your Licence
44
+
45
+ # Use common build tasks to build your application - describing how your application needs to be build
46
+ # The ordering is important, see the recipes documentation for more information about the recipes itself and there recommended ordering
47
+ use :bundler
48
+ use :rails
49
+ end
50
+ ```
51
+
52
+
53
+ ## Recipes
54
+
55
+ Cany uses different recipes to share different packaging tasks above multiple applications.
56
+
57
+ ### Bundler
58
+
59
+ All common applications need a bunch of gems. Bundle is the common tool to manage these gems. Because for most of the gems there exists no packages, we decide that the best approach is to ship the installed gems with the application.
60
+
61
+ This recipe is designed to use as first one. The installs bundler and uses the ``Gemfile.lock`` to install the referenced gems to ``vendor/bundle``.
62
+
63
+ ### Rails
64
+
65
+ This recipe is used to install a ruby on rails application. The recipes installs the different files/directories.
66
+
67
+ ### Thin
68
+
69
+ This recipe configures thin and install an init script to launch the application. It assumes that ``thin`` is listed in your Gemfile.
70
+
71
+
72
+ ### Own Adjustments
73
+
74
+ There are applications were the known recipes are not sufficient to build it. You can define blocks inside the canspec that are runs like normal recipes and allow you to do specific tasks.
75
+
76
+ The following example installs an additional folder (of an Ruby on Rails applications):
77
+
78
+ ```ruby
79
+ Cany::Sepcification.new do
80
+ # meta data and recipe loading
81
+ binary do
82
+ install 'additional_subdir', "/usr/share/#{spec.name}"
83
+ end
84
+ end
85
+ ```
86
+
87
+ Take a look at the ``Recipe`` class for helper you can use.
88
+
89
+
90
+ ## Use Your Specification to Create Packages
91
+
92
+ ### dpkg
93
+
94
+ To create dpkg packages (used by debian and its derivatives) run from your application directory with your canspec:
95
+
96
+ $ cany dpkg-create
97
+
98
+ It creates a debian subdirectory containing all needed files/information to build a dpkg package in the debian way. To create the package itself cany relies on the debian packaging tools. The build your package without signing the created files with GPG run
99
+
100
+ $ dpkg-buildpackage -us -uc
101
+
102
+ Afterwards you should have ``*.deb`` package in the directory containing your application directory.
103
+
104
+
105
+ ## Contributing
106
+
107
+ If you have problems create an issue. Feedback is also welcome - you can write me on email or contact me on freenode (@mswart).
108
+
109
+ If you have a change which should be included into cany:
110
+
111
+ 1. Fork it
112
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
113
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
114
+ 4. Push to the branch (`git push origin my-new-feature`)
115
+ 5. Create new Pull Request
@@ -0,0 +1,5 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task default: :spec
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- coding: utf-8 -*-
3
+ #require 'bundler/setup'
4
+
5
+ require 'cany'
6
+ require 'cany/dpkg/creator'
7
+ require 'cany/dpkg/builder'
8
+
9
+ tasks = {
10
+ 'dpkg-create' => Cany::Dpkg::Creator,
11
+ 'dpkg-builder' => Cany::Dpkg::Builder
12
+ }
13
+
14
+ unless tasks.include? ARGV.first
15
+ puts 'Unknown subaction - choose from ' + tasks.keys.join(', ')
16
+ exit 1
17
+ end
18
+
19
+ tasks[ARGV.shift].new(Cany::setup '.').run *ARGV
@@ -0,0 +1,24 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'cany/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'cany'
8
+ spec.version = Cany::VERSION
9
+ spec.authors = ['Malte Swart']
10
+ spec.email = %w(mswart@devtation.de)
11
+ spec.description = %q{Canning your ruby applications}
12
+ spec.summary = %q{Canning your ruby applications}
13
+ spec.homepage = 'https://github.com/mswart/cany'
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = %w(lib)
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.3'
22
+ spec.add_development_dependency 'rake'
23
+ spec.add_development_dependency 'rspec'
24
+ end
@@ -0,0 +1,29 @@
1
+ require 'cany/version'
2
+ require 'cany/specification'
3
+ require 'cany/recipe'
4
+ require 'cany/recipes/bundler'
5
+ require 'cany/recipes/rails'
6
+ require 'cany/recipes/web_server'
7
+ require 'cany/recipes/thin'
8
+ require 'cany/dpkg'
9
+ require 'cany/dpkg/creator'
10
+ require 'cany/dpkg/builder'
11
+ require 'cany/dpkg/deb_helper_recipe'
12
+
13
+ module Cany
14
+ class MissingSpecification < Exception
15
+ end
16
+
17
+ class MultipleSpecifications < Exception
18
+ end
19
+
20
+ def self.setup(directory='.')
21
+ specs = Dir[directory + '/*.' + Specification::EXT]
22
+ raise MissingSpecification, "No #{Specification::EXT} found in #{directory}" if specs.size == 0
23
+ raise MultipleSpecifications, "Multiple #{Specification::EXT} found in #{directory}" if specs.size > 1
24
+ file = specs.first
25
+ spec = eval File::read(file), binding, file
26
+ spec.base_dir = directory
27
+ spec
28
+ end
29
+ end
@@ -0,0 +1,4 @@
1
+ module Cany
2
+ module Dpkg
3
+ end
4
+ end
@@ -0,0 +1,37 @@
1
+ module Cany
2
+ module Dpkg
3
+ # This class does the real job. It is called for every dpkg build step to build the package.
4
+ # An instance is created on every execution. The package specification is passed as option to
5
+ # the initializer. Afterwards the run method is called to execute the wanted build step. The
6
+ # first parameter specifies the build step name (clean, build, binary).
7
+ # This method uses recipes instances to do the job itself.
8
+ class Builder
9
+ attr_reader :spec
10
+ def initialize(spec)
11
+ @spec = spec
12
+ end
13
+
14
+ def debian(*args)
15
+ File.join spec.base_dir, 'debian', *args
16
+ end
17
+
18
+ # This method is called to do the actual work
19
+ # @api public
20
+ # @param [String] build_step_name The name of the dpkg build step (clean, build, binary)
21
+ def run(build_step_name)
22
+ setup_recipes
23
+ @recipes.first.send build_step_name.to_s
24
+ end
25
+
26
+ # @api private
27
+ # This method creates recipe instances for all required recipes from the given spec.
28
+ def setup_recipes
29
+ @recipes = []
30
+ @recipes << DebHelperRecipe.new(spec, nil)
31
+ spec.recipes.reverse.each do |name|
32
+ @recipes.unshift Recipe.from_name(name).new(spec, @recipes.first)
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,145 @@
1
+ require 'optparse'
2
+
3
+ module Cany
4
+ module Dpkg
5
+ class Creator
6
+ attr_reader :spec
7
+ def initialize(spec)
8
+ @spec = spec
9
+ @options = {}
10
+ end
11
+
12
+ def debian(*args)
13
+ File.join spec.base_dir, 'debian', *args
14
+ end
15
+
16
+ def ruby_exe
17
+ @options[:ruby_exe] || 'ruby'
18
+ end
19
+
20
+ def ruby_deb
21
+ @options[:ruby_deb] || 'ruby'
22
+ end
23
+
24
+ def parse_opts(*args)
25
+ @options = {}
26
+
27
+ OptionParser.new do|opts|
28
+ opts.on('--ruby-exe RUBY_EXE', 'Choose the ruby interpreter name (default is ruby)') do |exe|
29
+ @options[:ruby_exe] = exe
30
+ end
31
+
32
+ opts.on('--ruby-deb RUBY_DEB', 'Choose the ruby package name (default is ruby)') do |deb|
33
+ @options[:ruby_deb] = deb
34
+ end
35
+
36
+ opts.on('-r', '--ruby RUBY_EXE_DEB', 'Set ruby interpreter and package name') do |name|
37
+ @options[:ruby_exe] = name
38
+ @options[:ruby_deb] = name
39
+ end
40
+
41
+ opts.on('-h', '--help', 'Display this screen') do
42
+ puts opts
43
+ exit
44
+ end
45
+ end.parse *args
46
+ end
47
+
48
+ def run(*args)
49
+ parse_opts *args
50
+
51
+ Dir.mkdir debian
52
+ create_compact
53
+ create_source_format
54
+ create_source_control
55
+ create_copyright
56
+ create_rules
57
+ create_changelog
58
+ end
59
+
60
+ def create_source_format
61
+ Dir.mkdir debian 'source'
62
+ File.open(debian('source', 'format'), 'w') { |f| f.write '3.0 (native)' }
63
+ end
64
+
65
+ def create_compact
66
+ File.open debian('compat'), 'w' do |f|
67
+ f.write '8'
68
+ end
69
+ end
70
+
71
+ def create_source_control
72
+ require 'bundler'
73
+ lock_path = File.join(spec.base_dir, 'Gemfile.lock')
74
+ extra_libs = {
75
+ pg: ['libpq-dev', 'libpq5']
76
+ }
77
+ src_deps = ['debhelper (>= 7.0.50~)', ruby_deb, ruby_deb + '-dev']
78
+ bin_deps = ['${shlibs:Depends}', '${misc:Depends}', ruby_deb]
79
+ if File.exists? lock_path
80
+ lock = Bundler::LockfileParser.new File.read lock_path
81
+ lock.specs.each do |spec|
82
+ if extra_libs.has_key? spec.name.to_sym
83
+ src, bin = extra_libs[spec.name.to_sym]
84
+ src_deps << src
85
+ bin_deps << bin
86
+ end
87
+ end
88
+ end
89
+ File.open debian('control'), 'w' do |f|
90
+ # write source package fields:
91
+ f.write("Source: #{spec.name}\n")
92
+ f.write("Section: ruby\n")
93
+ f.write("Priority: optional\n")
94
+ f.write("Maintainer: #{spec.maintainer_name} <#{spec.maintainer_email}>\n")
95
+ f.write("Standards-Version: 3.9.2\n")
96
+ f.write("Homepage: #{spec.website}\n")
97
+ f.write("Build-Depends: #{src_deps.join(', ')}\n")
98
+
99
+ # write binary package fields:
100
+ f.write("\n")
101
+ f.write("Package: #{spec.name}\n")
102
+ f.write("Architecture: any\n")
103
+ f.write("Depends: #{bin_deps.join(', ')}\n")
104
+ f.write("Description: #{spec.description}\n")
105
+ end
106
+ end
107
+
108
+ def create_copyright
109
+ File.open debian('copyright'), 'w' do |f|
110
+ f.write("Format: http://dep.debian.net/deps/dep5\n")
111
+ f.write("Upstream-Name: #{spec.name}\n\n")
112
+
113
+ f.write("Files: *\n")
114
+ f.write("Copyright: #{Time.now.year} #{spec.maintainer_name}\n")
115
+ f.write("Licence: #{spec.licence}\n [LICENCE TEXT]\n")
116
+ end
117
+ end
118
+
119
+ def create_rules
120
+ File.open debian('rules'), 'w' do |f|
121
+ f.write("#!/usr/bin/make -f\n")
122
+ f.write("export PATH := debian/bin:${PATH}\n")
123
+ f.write("export GEM_PATH := debian/gems:${GEM_PATH}\n")
124
+ # call cany for every target:
125
+ f.write("%:\n")
126
+ f.write("\t#{ruby_exe} -cS cany >/dev/null || #{ruby_exe} -S gem install --no-ri --no-rdoc --install-dir debian/gems --bindir debian/bin $${CANY_GEM:-cany}\n")
127
+ f.write("\t#{ruby_exe} -S cany dpkg-builder $@\n")
128
+ f.write("\noverride_dh_prep:\n")
129
+
130
+ f.chmod(0755)
131
+ end
132
+ end
133
+
134
+ def create_changelog
135
+ File.open debian('changelog'), 'w' do |f|
136
+ f.write "#{spec.name} (#{spec.version}-1) unstable; urgency=low\n"
137
+ f.write "\n"
138
+ f.write " * Build with cany\n"
139
+ f.write "\n"
140
+ f.write " -- #{spec.maintainer_name} <#{spec.maintainer_email}> #{Time.now.strftime "%a, %d %b %Y %H:%M:%S %z" }"
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end