devball 0.3
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.
- data/README +14 -0
- data/bin/devball +9 -0
- data/bin/devball-build +118 -0
- data/bin/devball-pull +66 -0
- data/bin/devball-push +46 -0
- data/lib/devball/initialization.rb +35 -0
- data/lib/devball/pkgspec/base.rb +342 -0
- data/lib/devball/pkgspec/djb.rb +73 -0
- data/lib/devball/pkgspec/gem.rb +98 -0
- data/lib/devball/pkgspec/pecl.rb +35 -0
- data/lib/devball/pkgspec/simple_dir.rb +9 -0
- data/lib/devball/pkgspec/tarball.rb +33 -0
- data/lib/devball/pkgspec/test.rb +0 -0
- metadata +67 -0
data/README
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
DevBall Builder
|
2
|
+
---
|
3
|
+
This is a tool for building a devball. A devball is a self-contained set of packages that can be portably be moved from one binary-compatible machine to another.
|
4
|
+
|
5
|
+
Usage
|
6
|
+
---
|
7
|
+
- Create a directory with pkgspecs and the accompanying tarballs/gem files/etc.
|
8
|
+
- Run "devball build {path}" to build the packages and setup the devball directory
|
9
|
+
- Use "devball push -p {rsync target} -n {build name}" to push your devball into an rsync repository
|
10
|
+
- Use "devball pull -p {rsync target} -n {build name}" to pull a devball down from an rsync repository
|
11
|
+
|
12
|
+
Examples
|
13
|
+
---
|
14
|
+
(To be added)
|
data/bin/devball
ADDED
data/bin/devball-build
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Builds our package environment based on the .pkgspec files in packages
|
3
|
+
|
4
|
+
require 'devball/initialization'
|
5
|
+
|
6
|
+
module DevBall
|
7
|
+
should_clean = false
|
8
|
+
clean_build_dirs = true
|
9
|
+
explicit_packages = nil
|
10
|
+
build = true
|
11
|
+
force = false
|
12
|
+
only = false
|
13
|
+
|
14
|
+
$build_dir = "/tmp/devball-build"
|
15
|
+
|
16
|
+
configure do |opts|
|
17
|
+
opts.on("-b", "--build-dir BUILD_DIR", "Specify where to use as a scratch directory for building. Defaults to /tmp/devball-build") do |build_dir|
|
18
|
+
$build_dir = build_dir
|
19
|
+
end
|
20
|
+
opts.on("-c", "--clean-install", "Remove built devball directory before starting.") do
|
21
|
+
should_clean = true
|
22
|
+
end
|
23
|
+
opts.on("-L", "--leave-build-dirs", "Leave intermediate build directories alone after installing (for debugging)") do
|
24
|
+
clean_build_dirs = false
|
25
|
+
end
|
26
|
+
opts.on("-N", "--no-build", "Don't actually build the devball, just list what would be built.") do
|
27
|
+
build = false
|
28
|
+
end
|
29
|
+
opts.on("-o", "--only PKGNAME,PKGNAME,PKGNAME...", "Only build the packages specified on the command line (but not their deps)") do |pkgnames|
|
30
|
+
only = true
|
31
|
+
explicit_packages = pkgnames.collect do |pkgname|
|
32
|
+
if (regex_match = /^\/(.*)\/$/.match(pkgname))
|
33
|
+
Regexp.new(regex_match[1])
|
34
|
+
else
|
35
|
+
pkgname
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
opts.on("-f", "--force", "Build ALL packages, even if they're already installed in the devball.") do
|
40
|
+
force = true
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
packages = PkgSpec::Base.load_packages($package_dir, explicit_packages, only);
|
45
|
+
if (!force)
|
46
|
+
packages.delete_if {|pkg| File.directory?("#{$install_base}/packages/#{pkg}") }
|
47
|
+
end
|
48
|
+
puts("Installing packages: #{packages.join(', ')}")
|
49
|
+
puts("Into #{$install_base}")
|
50
|
+
|
51
|
+
exit(0) if (!build)
|
52
|
+
|
53
|
+
if (!system("mkdir", "-p", $build_dir))
|
54
|
+
puts("Could not create build directory.")
|
55
|
+
exit(150)
|
56
|
+
end
|
57
|
+
|
58
|
+
if (File.exists?($install_base) && should_clean)
|
59
|
+
system("rm", "-rf", "#{$install_base}/*")
|
60
|
+
end
|
61
|
+
|
62
|
+
if (!system("mkdir", "-p", $install_base))
|
63
|
+
puts("Could not create target directory.")
|
64
|
+
puts("You will probably need to create the directory and set permissions yourself by running:")
|
65
|
+
puts("sudo mkdir -p #{$install_base}")
|
66
|
+
puts("sudo chown #{ENV['USER']}: #{$install_base}")
|
67
|
+
exit(250)
|
68
|
+
end
|
69
|
+
|
70
|
+
# commonly needed environment variables.
|
71
|
+
ENV['CFLAGS'] = (ENV['CFLAGS'] || "") + " -I#{$install_base}/include -fPIC"
|
72
|
+
ENV['CXXFLAGS'] = (ENV['CXXFLAGS'] || "") + " -I#{$install_base}/include -fPIC"
|
73
|
+
ENV['LDFLAGS'] = (ENV['LDFLAGS'] || "") + " -L#{$install_base}/lib -fPIC"
|
74
|
+
ENV['PATH'] = "#{$install_base}/bin:" + (ENV['PATH'] || "")
|
75
|
+
ENV['RUBYOPT'] = '' # clear this out. It blows stuff up.
|
76
|
+
|
77
|
+
packages.each {|package|
|
78
|
+
package.remove_build()
|
79
|
+
related_pkgs = []
|
80
|
+
begin
|
81
|
+
puts("Extracting #{package}")
|
82
|
+
package.step_extract()
|
83
|
+
puts("Patching #{package}")
|
84
|
+
package.step_patch()
|
85
|
+
puts("Setting environment for #{package}")
|
86
|
+
package.step_environment_setup()
|
87
|
+
puts("Configuring #{package}")
|
88
|
+
package.step_configure()
|
89
|
+
puts("Building #{package}")
|
90
|
+
package.step_build()
|
91
|
+
puts("Installing #{package}")
|
92
|
+
package.remove_install()
|
93
|
+
begin
|
94
|
+
FileUtils.mkdir_p(package.package_install_dir) # precreate the package directory so it always exists.
|
95
|
+
related_pkgs = package.step_install()
|
96
|
+
rescue Exception
|
97
|
+
puts("Error installing #{package}. Cleaning up the install dir.")
|
98
|
+
package.remove_install()
|
99
|
+
system("rm", "-rf", package.package_install_dir)
|
100
|
+
raise
|
101
|
+
end
|
102
|
+
ensure
|
103
|
+
if (clean_build_dirs)
|
104
|
+
puts("Removing build directory for #{package}")
|
105
|
+
package.remove_build()
|
106
|
+
end
|
107
|
+
end
|
108
|
+
puts("Setting up links for #{package}")
|
109
|
+
package.step_setup_links()
|
110
|
+
if (related_pkgs.kind_of?(Array))
|
111
|
+
related_pkgs.each {|related|
|
112
|
+
PkgSpec::Base.find(related).step_setup_links()
|
113
|
+
}
|
114
|
+
end
|
115
|
+
}
|
116
|
+
|
117
|
+
puts("Done installing packages #{packages.join(', ')}.")
|
118
|
+
end
|
data/bin/devball-pull
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Pushed a built devball to an rsync target for later fetching by devball-pull
|
3
|
+
|
4
|
+
require 'devball/initialization'
|
5
|
+
|
6
|
+
module DevBall
|
7
|
+
config = {
|
8
|
+
# :path => nil,
|
9
|
+
# :username => nil,
|
10
|
+
# :build_name => nil,
|
11
|
+
# :no_push => nil,
|
12
|
+
}
|
13
|
+
|
14
|
+
configure do |opts|
|
15
|
+
opts.banner += "\n Will pull from {TARGET_PATH}{BUILD_NAME}."
|
16
|
+
|
17
|
+
opts.on("-n", "--name BUILD_NAME", "Name the build for pushing to rsync server.") do |build_name|
|
18
|
+
config[:build_name] = build_name
|
19
|
+
end
|
20
|
+
opts.on("-p", "--path TARGET_PATH", "Push to the rsync path specified with the build name specified in -n.") do |rsync_server|
|
21
|
+
config[:path] = rsync_server
|
22
|
+
end
|
23
|
+
opts.on("-u", "--username USERNAME", "Username to use when connecting to rsync.") do |username|
|
24
|
+
config[:username] = username
|
25
|
+
end
|
26
|
+
opts.on("-N", "--no-pull", "Don't actually pull, just tell me where it'll be pushing to.") do
|
27
|
+
config[:no_pull] = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
config = $config[:rsync][:pull].merge(config) if ($config[:rsync] && $config[:rsync][:pull])
|
32
|
+
|
33
|
+
if (!config[:build_name] || !config[:path])
|
34
|
+
puts("You must specify a build name and rsync path to push to.")
|
35
|
+
exit(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
if (config[:username])
|
39
|
+
config[:path] = config[:path].gsub(%r{^rsync://}, "rsync://#{config[:username]}@")
|
40
|
+
end
|
41
|
+
|
42
|
+
puts("Pulling devball from rsync path #{config[:path]}#{config[:build_name]}")
|
43
|
+
exit(0) if config[:no_pull]
|
44
|
+
|
45
|
+
if (!system("mkdir", "-p", $install_base))
|
46
|
+
puts("Could not create target directory.")
|
47
|
+
puts("You will probably need to create the directory and set permissions yourself by running:")
|
48
|
+
puts("sudo mkdir -p #{$install_base}")
|
49
|
+
puts("sudo chown #{ENV['USER']}: #{$install_base}")
|
50
|
+
exit(250)
|
51
|
+
end
|
52
|
+
|
53
|
+
system("rsync", "-a", "--delete", "#{config[:path]}#{config[:build_name]}", "#{$install_base}")
|
54
|
+
|
55
|
+
# now take the list of packages we pulled down, load their package objects, and setup links.
|
56
|
+
packages = PkgSpec::Base.load_packages($package_dir, nil, false);
|
57
|
+
Dir["#{$install_base}/packages/*"].each {|pkg_name|
|
58
|
+
pkg_name = %r{/([^/]+)$}.match(pkg_name)[1]
|
59
|
+
package = PkgSpec::Base.find(pkg_name)
|
60
|
+
if (!package)
|
61
|
+
raise "Unknown package #{pkg_name} pulled from devball server."
|
62
|
+
end
|
63
|
+
puts("Setting up links for #{pkg_name}")
|
64
|
+
package.step_setup_links()
|
65
|
+
}
|
66
|
+
end
|
data/bin/devball-push
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Pushed a built devball to an rsync target for later fetching by devball-pull
|
3
|
+
|
4
|
+
require 'devball/initialization'
|
5
|
+
|
6
|
+
module DevBall
|
7
|
+
config = {
|
8
|
+
# :path => nil,
|
9
|
+
# :username => nil,
|
10
|
+
# :build_name => nil,
|
11
|
+
# :no_push => nil,
|
12
|
+
}
|
13
|
+
|
14
|
+
configure do |opts|
|
15
|
+
opts.banner += "\n Will push to {TARGET_PATH}{BUILD_NAME}.\n Must have a built devball to push anything."
|
16
|
+
|
17
|
+
opts.on("-n", "--name BUILD_NAME", "Name the build for pushing to rsync server.") do |build_name|
|
18
|
+
config[:build_name] = build_name
|
19
|
+
end
|
20
|
+
opts.on("-p", "--path TARGET_PATH", "Push to the rsync path specified with the build name specified in -n.") do |rsync_server|
|
21
|
+
config[:path] = rsync_server
|
22
|
+
end
|
23
|
+
opts.on("-u", "--username USERNAME", "Username to use when connecting to rsync.") do |username|
|
24
|
+
config[:username] = username
|
25
|
+
end
|
26
|
+
opts.on("-N", "--no-push", "Don't actually push, just tell me where it'll be pushing to.") do
|
27
|
+
config[:no_push] = true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
config = $config[:rsync][:push].merge(config) if ($config[:rsync] && $config[:rsync][:push])
|
32
|
+
|
33
|
+
if (!config[:build_name] || !config[:path])
|
34
|
+
puts("You must specify a build name and rsync path to push to.")
|
35
|
+
exit(1)
|
36
|
+
end
|
37
|
+
|
38
|
+
if (config[:username])
|
39
|
+
config[:path] = config[:path].gsub(%r{^rsync://}, "rsync://#{config[:username]}@")
|
40
|
+
end
|
41
|
+
|
42
|
+
puts("Pushing devball to rsync path #{config[:path]}#{config[:build_name]}")
|
43
|
+
exit(0) if config[:no_push]
|
44
|
+
|
45
|
+
system("rsync", "-a", "--delete", "#{$install_base}/packages", "#{config[:path]}#{config[:build_name]}")
|
46
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'yaml'
|
3
|
+
require 'devball/pkgspec/base'
|
4
|
+
|
5
|
+
module DevBall
|
6
|
+
# Loads all the config options relevant to all devball commands. Yields
|
7
|
+
# an optparse object for the specific command to add options to.
|
8
|
+
def self.configure(argv = ARGV)
|
9
|
+
$install_base = nil
|
10
|
+
|
11
|
+
opts = OptionParser.new do |opts|
|
12
|
+
opts.banner = "Usage: #{$0} [options] package_dir"
|
13
|
+
|
14
|
+
opts.on_tail("-h", "--help", "Show help screen") do
|
15
|
+
puts opts
|
16
|
+
exit(0)
|
17
|
+
end
|
18
|
+
|
19
|
+
yield opts
|
20
|
+
end
|
21
|
+
|
22
|
+
opts.parse! argv
|
23
|
+
|
24
|
+
$package_dir = ARGV.shift || raise(ArgumentError, "No package bundle directory named.")
|
25
|
+
$package_name = File.basename($package_dir)
|
26
|
+
|
27
|
+
$config = {}
|
28
|
+
if (File.exists? "#{$package_dir}/config.yaml")
|
29
|
+
$config = YAML.load_file("#{$package_dir}/config.yaml")
|
30
|
+
$package_name = $config[:package_name] || $package_name
|
31
|
+
end
|
32
|
+
|
33
|
+
$install_base = "/#{$package_name}"
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,342 @@
|
|
1
|
+
# defines a bunch of helper functions as well as the main steps for building a package
|
2
|
+
# These steps are:
|
3
|
+
# - step_extract
|
4
|
+
# - step_patch
|
5
|
+
# - step_environment_setup
|
6
|
+
# - step_configure
|
7
|
+
# - step_build
|
8
|
+
# - step_install
|
9
|
+
# - step_setup_links
|
10
|
+
# There are also two that are involved in removing the resulting files.
|
11
|
+
# - remove_build
|
12
|
+
# - remove_install
|
13
|
+
# Derived classes should also describe their dependency tree through the
|
14
|
+
# PkgSpec::Base.depends_on function.
|
15
|
+
require 'fileutils'
|
16
|
+
module DevBall
|
17
|
+
module PkgSpec
|
18
|
+
class Error < Exception; end
|
19
|
+
class Undefined < Error; end
|
20
|
+
class PackageLoadError < Error; end
|
21
|
+
class ExtractFailed < Error; end
|
22
|
+
class ConfigureFailed < Error; end
|
23
|
+
class BuildFailed < Error; end
|
24
|
+
class InstallFailed < Error; end
|
25
|
+
class RemoveFailed < Error; end
|
26
|
+
|
27
|
+
# Autoload arbitrary devball pkgspec-types through const_missing
|
28
|
+
def self.const_missing(name)
|
29
|
+
autoloading = (Thread.current[:autoloading] ||= {})
|
30
|
+
if (autoloading[name])
|
31
|
+
raise NameError, "uninitialized constant DevBall::PkgSpec::#{name} (autoload already tried to find it)"
|
32
|
+
end
|
33
|
+
autoloading[name] = true
|
34
|
+
|
35
|
+
begin
|
36
|
+
filename = name.to_s.gsub(/^[A-Z]/) {|a| a.downcase }.gsub(/[A-Z]/) {|a| "_#{a.downcase}" }
|
37
|
+
require 'devball/pkgspec/' + filename
|
38
|
+
if (!const_defined?(name))
|
39
|
+
raise NameError, "uninitialized constant DevBall::PkgSpec::#{name} (autoload found file but file did not define class)"
|
40
|
+
end
|
41
|
+
return const_get(name)
|
42
|
+
rescue LoadError
|
43
|
+
raise NameError, "uninitialized constant DevBall::PkgSpec::#{name} (autoload failed to find matching file)"
|
44
|
+
ensure
|
45
|
+
autoloading[name] = false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Base
|
50
|
+
class <<self
|
51
|
+
def load_packages(dir, explicit, only_explicit = false)
|
52
|
+
# load all the packagespecs
|
53
|
+
@packages ||= {}
|
54
|
+
@install_packages ||= {}
|
55
|
+
Dir["#{dir}/*.pkgspec"].each {|f|
|
56
|
+
load "#{Dir.getwd}/#{f}"
|
57
|
+
}
|
58
|
+
|
59
|
+
def explicit.include?(str)
|
60
|
+
each {|i|
|
61
|
+
if (i === str)
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
}
|
65
|
+
return false
|
66
|
+
end
|
67
|
+
|
68
|
+
@packages_inorder = @install_packages.collect {|name, pkg|
|
69
|
+
if (deps = pkg.recursive_depends_on)
|
70
|
+
[deps, name].flatten
|
71
|
+
else
|
72
|
+
name
|
73
|
+
end
|
74
|
+
}.flatten.uniq.collect {|pkgname|
|
75
|
+
if (!only_explicit || explicit.include?(pkgname))
|
76
|
+
@packages[pkgname] || raise(Error, "Unknown package #{pkgname} in package list (#{@packages.keys.join(",")})")
|
77
|
+
else
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
}.compact
|
81
|
+
return @packages_inorder
|
82
|
+
end
|
83
|
+
attr :packages_inorder
|
84
|
+
|
85
|
+
def find(name)
|
86
|
+
@packages ||= {}
|
87
|
+
|
88
|
+
return @packages[name]
|
89
|
+
end
|
90
|
+
|
91
|
+
def depends_on(*deps)
|
92
|
+
@deps ||= []
|
93
|
+
@deps.push(*deps) if (deps.length > 0)
|
94
|
+
|
95
|
+
deps = []
|
96
|
+
if (superclass && superclass.respond_to?(:depends_on))
|
97
|
+
deps.push(*superclass.depends_on)
|
98
|
+
end
|
99
|
+
deps.push(*@deps)
|
100
|
+
deps
|
101
|
+
end
|
102
|
+
|
103
|
+
def register_package(klass, name, required)
|
104
|
+
@packages ||= {}
|
105
|
+
@packages[name] = klass
|
106
|
+
if (required)
|
107
|
+
@install_packages ||= {}
|
108
|
+
@install_packages[name] = klass
|
109
|
+
end
|
110
|
+
end
|
111
|
+
attr :ball
|
112
|
+
def set_ball(name, required = true)
|
113
|
+
@ball = name
|
114
|
+
@instance = self.new
|
115
|
+
PkgSpec::Base.register_package(@instance, @instance.package_name, required)
|
116
|
+
end
|
117
|
+
# defines it as a library that is only required if somethind depended on it.
|
118
|
+
def set_lib_ball(name)
|
119
|
+
set_ball(name, false)
|
120
|
+
end
|
121
|
+
|
122
|
+
attr :patches
|
123
|
+
def set_patch(*patches)
|
124
|
+
@patches ||= []
|
125
|
+
@patches += patches
|
126
|
+
end
|
127
|
+
end
|
128
|
+
def ball
|
129
|
+
return self.class.ball
|
130
|
+
end
|
131
|
+
def depends_on
|
132
|
+
return self.class.depends_on
|
133
|
+
end
|
134
|
+
def recursive_depends_on
|
135
|
+
return self.class.depends_on.collect {|dep|
|
136
|
+
pkg = PkgSpec::Base.find(dep) || raise(PackageLoadError, "Package #{to_s} depends on #{dep} which doesn't exist.")
|
137
|
+
[pkg.recursive_depends_on, dep]
|
138
|
+
}.flatten
|
139
|
+
end
|
140
|
+
|
141
|
+
def ball_file_name()
|
142
|
+
return "#{$package_dir}/#{ball}"
|
143
|
+
end
|
144
|
+
# extracts the ball to the correct place in the builddir
|
145
|
+
def step_extract()
|
146
|
+
raise Undefined, "Behaviour undefined for extracting the ball"
|
147
|
+
end
|
148
|
+
|
149
|
+
def step_patch()
|
150
|
+
if (File.directory?(build_dir_name) && self.class.patches && self.class.patches.length)
|
151
|
+
orig = Dir.getwd
|
152
|
+
Dir.chdir(build_dir_name) {|dir|
|
153
|
+
self.class.patches.each {|patch|
|
154
|
+
system("patch -p1 < #{orig}/#{$package_dir}/#{patch}") || raise(PatchFailed, "Patch #{patch} failed to apply. Errno #{$?}")
|
155
|
+
}
|
156
|
+
}
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# get the name of the ball without extention
|
161
|
+
def ball_version()
|
162
|
+
ball().gsub(/^(.*)\.(gem|tar\.gz|tgz|tar\.bz2)$/, '\1')
|
163
|
+
end
|
164
|
+
|
165
|
+
# get the name of the ball without version. Cuts off after the first hyphen
|
166
|
+
def ball_name()
|
167
|
+
ball_version().gsub(/^([^\-]+)$/, '\1')
|
168
|
+
end
|
169
|
+
|
170
|
+
# get the name of the subdirectory the ball was extracted to
|
171
|
+
# provides a default implementation that uses ball() and takes off known extensions
|
172
|
+
# on the assumption that its name will be derived from the ball name that way.
|
173
|
+
# If that's not true, it should be overriden
|
174
|
+
def build_dir_name()
|
175
|
+
return "#{$build_dir}/#{ball_version}"
|
176
|
+
end
|
177
|
+
|
178
|
+
# get the name of the package without any version information. Default
|
179
|
+
# implementation bases it on the class name.
|
180
|
+
def package_name()
|
181
|
+
package_name = self.class.name.to_s
|
182
|
+
package_name = package_name.gsub(/^(.+?)(Package)?$/, '\1')
|
183
|
+
return package_name
|
184
|
+
end
|
185
|
+
def to_s()
|
186
|
+
package_name()
|
187
|
+
end
|
188
|
+
|
189
|
+
# Returns the directory the package will be installed in.
|
190
|
+
def package_install_dir()
|
191
|
+
return "#{$install_base}/packages/#{package_name}"
|
192
|
+
end
|
193
|
+
|
194
|
+
# configure options to pass to ./configure. The default step_configure function
|
195
|
+
# uses this, but derived versions don't have to, but whatever they do should
|
196
|
+
# have the same effect as the prefix set by the hash this returns.
|
197
|
+
# if this is overloaded, you should merge your options with super()
|
198
|
+
def configure_params()
|
199
|
+
return {:prefix=>package_install_dir}
|
200
|
+
end
|
201
|
+
|
202
|
+
def step_environment_setup()
|
203
|
+
end
|
204
|
+
|
205
|
+
def configure_script_name()
|
206
|
+
"./configure"
|
207
|
+
end
|
208
|
+
|
209
|
+
# do the configure step. The only requirement is that this end up installing things
|
210
|
+
# in /$install_base/packages/#{package_name}. The default implementation runs ./configure in
|
211
|
+
# the build dir with the results of configure_params.
|
212
|
+
def step_configure()
|
213
|
+
Dir.chdir(build_dir_name) {|dir|
|
214
|
+
params = configure_params.collect {|key, val|
|
215
|
+
if (val)
|
216
|
+
"--#{key}=#{val}"
|
217
|
+
else
|
218
|
+
"--#{key}"
|
219
|
+
end
|
220
|
+
}
|
221
|
+
if (!system(configure_script_name, *params))
|
222
|
+
raise ConfigureFailed, "Configuration failed with error: #{$?}"
|
223
|
+
end
|
224
|
+
}
|
225
|
+
end
|
226
|
+
|
227
|
+
# targets for the build call to make to use
|
228
|
+
def build_targets()
|
229
|
+
return ["all"]
|
230
|
+
end
|
231
|
+
|
232
|
+
def build_concurrent?()
|
233
|
+
return true
|
234
|
+
end
|
235
|
+
|
236
|
+
# do the build step. Default implementation is to simply run make in the build dir.
|
237
|
+
def step_build()
|
238
|
+
Dir.chdir(build_dir_name) {|dir|
|
239
|
+
args = []
|
240
|
+
args.push("-j4") if build_concurrent?
|
241
|
+
args += build_targets
|
242
|
+
if (!system("make", *args))
|
243
|
+
raise BuildFailed, "Build failed with error: #{$?}"
|
244
|
+
end
|
245
|
+
}
|
246
|
+
end
|
247
|
+
|
248
|
+
def install_targets()
|
249
|
+
return ["install"]
|
250
|
+
end
|
251
|
+
|
252
|
+
# do the install step. Default implementation is to simply run "make install" in the build dir
|
253
|
+
def step_install()
|
254
|
+
Dir.chdir(build_dir_name) {|dir|
|
255
|
+
if (!system("make", *install_targets))
|
256
|
+
raise InstallFailed, "Install failed with error: #{$?}"
|
257
|
+
end
|
258
|
+
}
|
259
|
+
return []
|
260
|
+
end
|
261
|
+
|
262
|
+
# Returns any explicit filename translations that should be performed on a file when linking
|
263
|
+
# it into the right place in the tree.
|
264
|
+
def link_mappings()
|
265
|
+
return {}
|
266
|
+
end
|
267
|
+
|
268
|
+
def install_service_links(base_from)
|
269
|
+
Dir[File.join(base_from, "*")].each {|service|
|
270
|
+
supervise_dir = File.join("/var#{$install_base}/supervise", File.basename(service))
|
271
|
+
begin
|
272
|
+
File.delete(File.join(service, "supervise"))
|
273
|
+
rescue; end
|
274
|
+
File.symlink(supervise_dir, File.join(service, "supervise"))
|
275
|
+
if (File.directory?(File.join(service, "log")))
|
276
|
+
begin
|
277
|
+
File.delete(File.join(service, "log", "supervise"))
|
278
|
+
rescue; end
|
279
|
+
File.symlink("#{supervise_dir}-log", File.join(service, "log", "supervise"))
|
280
|
+
end
|
281
|
+
}
|
282
|
+
end
|
283
|
+
|
284
|
+
# internal implementation of setting the links up for a given directory.
|
285
|
+
# pass nil into subdir to suppress recursion.
|
286
|
+
def install_links(base_from, base_into, subdir)
|
287
|
+
recurse = subdir
|
288
|
+
subdir = "" if !subdir
|
289
|
+
Dir[File.join(base_from, subdir, "*")].each {|file|
|
290
|
+
stat = File.lstat(file)
|
291
|
+
if (stat.directory? && recurse)
|
292
|
+
FileUtils.mkdir_p(File.join(base_into, subdir, File.basename(file)))
|
293
|
+
install_links(base_from, base_into, File.join(subdir, File.basename(file)))
|
294
|
+
end
|
295
|
+
if (!stat.directory?)
|
296
|
+
target = File.join(base_into, subdir, File.basename(file))
|
297
|
+
begin
|
298
|
+
File.delete(target)
|
299
|
+
rescue
|
300
|
+
end
|
301
|
+
File.symlink(file, target)
|
302
|
+
end
|
303
|
+
}
|
304
|
+
end
|
305
|
+
|
306
|
+
# Build the appropriate links for the package so it can be run properly from /nexopia
|
307
|
+
def step_setup_links()
|
308
|
+
install_links(package_install_dir, "#{$install_base}", nil)
|
309
|
+
FileUtils.mkdir_p("#{$install_base}/bin")
|
310
|
+
install_links(File.join(package_install_dir, "bin"), "#{$install_base}/bin", "")
|
311
|
+
install_links(File.join(package_install_dir, "sbin"), "#{$install_base}/bin", "")
|
312
|
+
install_links(File.join(package_install_dir, "libexec"), "#{$install_base}/bin", "")
|
313
|
+
FileUtils.mkdir_p("#{$install_base}/lib")
|
314
|
+
install_links(File.join(package_install_dir, "lib"), "#{$install_base}/lib", "")
|
315
|
+
FileUtils.mkdir_p("#{$install_base}/include")
|
316
|
+
install_links(File.join(package_install_dir, "include"), "#{$install_base}/include", "")
|
317
|
+
FileUtils.mkdir_p("#{$install_base}/man")
|
318
|
+
install_links(File.join(package_install_dir, "man"), "#{$install_base}/man", "")
|
319
|
+
FileUtils.mkdir_p("#{$install_base}/etc")
|
320
|
+
install_links(File.join(package_install_dir, "etc"), "#{$install_base}/etc", "")
|
321
|
+
|
322
|
+
FileUtils.mkdir_p("#{$install_base}/service-privileged")
|
323
|
+
install_service_links(File.join(package_install_dir, "service-privileged"))
|
324
|
+
install_links(File.join(package_install_dir, "service-privileged"), "#{$install_base}/service-privileged", "")
|
325
|
+
FileUtils.mkdir_p("#{$install_base}/service-required")
|
326
|
+
install_service_links(File.join(package_install_dir, "service-required"))
|
327
|
+
install_links(File.join(package_install_dir, "service-required"), "#{$install_base}/service-required", "")
|
328
|
+
FileUtils.mkdir_p("#{$install_base}/service-optional")
|
329
|
+
install_service_links(File.join(package_install_dir, "service-optional"))
|
330
|
+
install_links(File.join(package_install_dir, "service-optional"), "#{$install_base}/service-optional", "")
|
331
|
+
end
|
332
|
+
|
333
|
+
def remove_build()
|
334
|
+
system("rm", "-rf", build_dir_name) || raise(RemoveFailed, "Could not delete existing build directory.")
|
335
|
+
end
|
336
|
+
|
337
|
+
def remove_install()
|
338
|
+
system("rm", "-rf", package_install_dir) || raise(RemoveFailed, "Could not delete installed directory.")
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'ftools'
|
2
|
+
|
3
|
+
module DevBall
|
4
|
+
module PkgSpec
|
5
|
+
class Djb < Tarball
|
6
|
+
def extract_dir_name()
|
7
|
+
return build_dir_name
|
8
|
+
end
|
9
|
+
def package_build_dir_name()
|
10
|
+
return extract_dir_name + "/#{type}/#{ball_version}"
|
11
|
+
end
|
12
|
+
|
13
|
+
# use this to set the type of the package in djb's world (ie. admin)
|
14
|
+
def self.set_type(type)
|
15
|
+
@type = type
|
16
|
+
end
|
17
|
+
def self.type()
|
18
|
+
return @type
|
19
|
+
end
|
20
|
+
def type()
|
21
|
+
return self.class.type
|
22
|
+
end
|
23
|
+
|
24
|
+
def step_configure()
|
25
|
+
# look for makefiles and turn off -static flags in them. (ugh)
|
26
|
+
if (RUBY_PLATFORM =~ /darwin/)
|
27
|
+
Dir[package_build_dir_name() + "/**/Makefile"].each {|makefile|
|
28
|
+
File.rename(makefile, makefile + ".old")
|
29
|
+
File.open(makefile + ".old", "r") {|fin|
|
30
|
+
File.open(makefile, "w") {|fout|
|
31
|
+
fin.each {|line|
|
32
|
+
fout.puts(line.gsub(/\-static/, ''))
|
33
|
+
}
|
34
|
+
}
|
35
|
+
}
|
36
|
+
}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def step_build()
|
41
|
+
Dir.chdir(package_build_dir_name()) {|dir|
|
42
|
+
# build source
|
43
|
+
system("package/compile") || raise(BuildFailed, "Build of djb package failed: #{$?}")
|
44
|
+
# build man pages
|
45
|
+
Dir.chdir("man") {|dir|
|
46
|
+
Dir["*.?"].each {|manfile|
|
47
|
+
system("gzip", manfile)
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
end
|
52
|
+
|
53
|
+
def step_install()
|
54
|
+
# get commands from command/ and put them in the package install dir's bin directory
|
55
|
+
Dir.chdir(package_build_dir_name) {|dir|
|
56
|
+
# install the commands as specified by package/commands.
|
57
|
+
commands = IO.readlines("package/commands")
|
58
|
+
FileUtils.mkdir_p(package_install_dir + "/bin")
|
59
|
+
commands.each {|command|
|
60
|
+
FileUtils.copy("compile/" + command.chomp, package_install_dir + "/bin")
|
61
|
+
}
|
62
|
+
# install the man pages
|
63
|
+
Dir["man/*.?.gz"].each {|manpage|
|
64
|
+
mantype = /(.+)\.([0-8])\.gz/.match(manpage)
|
65
|
+
FileUtils.mkdir_p(package_install_dir + "/man/man#{mantype[2]}")
|
66
|
+
FileUtils.copy(manpage, package_install_dir + "/man/man#{mantype[2]}")
|
67
|
+
}
|
68
|
+
}
|
69
|
+
return []
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module DevBall
|
2
|
+
module PkgSpec
|
3
|
+
class Gem < Base
|
4
|
+
if ENV['RUBINIUS']
|
5
|
+
depends_on "Rubinius"
|
6
|
+
elsif ENV['REE']
|
7
|
+
depends_on "Ruby"
|
8
|
+
else
|
9
|
+
depends_on "RubyGems"
|
10
|
+
end
|
11
|
+
|
12
|
+
def step_extract()
|
13
|
+
# whether the gem is a local file or fetched from rubyforge, we don't extract it.
|
14
|
+
end
|
15
|
+
|
16
|
+
def step_configure()
|
17
|
+
# gems are all three steps in one at install time.
|
18
|
+
end
|
19
|
+
|
20
|
+
def step_build()
|
21
|
+
# gems are all three steps in one at install time.
|
22
|
+
end
|
23
|
+
|
24
|
+
def configure_params()
|
25
|
+
return {} # no need for prefix
|
26
|
+
end
|
27
|
+
|
28
|
+
# override to specify a different gem repository. Default returns nil and indicates to use the standard rubyforge repo.
|
29
|
+
def gem_repository()
|
30
|
+
return nil
|
31
|
+
end
|
32
|
+
|
33
|
+
def step_install()
|
34
|
+
Dir.chdir($package_dir) {|dir|
|
35
|
+
params = configure_params.collect {|key, val|
|
36
|
+
if (val)
|
37
|
+
"--#{key}=#{val}"
|
38
|
+
else
|
39
|
+
"--#{key}"
|
40
|
+
end
|
41
|
+
}
|
42
|
+
|
43
|
+
if (params.length)
|
44
|
+
params.unshift("--")
|
45
|
+
end
|
46
|
+
|
47
|
+
if (gem_repository)
|
48
|
+
params.unshift(gem_repository)
|
49
|
+
params.unshift("--source")
|
50
|
+
end
|
51
|
+
|
52
|
+
if (ENV['RUBINIUS'])
|
53
|
+
# params = ["rbx", "gem", "install", "--install-dir=/nexopia/packages/Rubinius/lib/rubinius/gems/1.8", ball, *params].collect {|i| %Q{"#{i}"} }
|
54
|
+
params = ["rbx", "gem", "install", ball, *params].collect {|i| %Q{"#{i}"} }
|
55
|
+
else
|
56
|
+
params = ["gem", "install", ball, *params].collect {|i| %Q{"#{i}"} }
|
57
|
+
end
|
58
|
+
# and here this gets complicated, since gems don't return an error code if they fail. They just talk about it on their output.
|
59
|
+
success = false
|
60
|
+
errors = []
|
61
|
+
open("|#{params.join(' ')} 2>&1", "r") {|io|
|
62
|
+
io.each {|line|
|
63
|
+
puts(line)
|
64
|
+
if (match = /ERROR:\s+(.+)$/.match(line))
|
65
|
+
errors.push(match[1])
|
66
|
+
end
|
67
|
+
if (match = /^[0-9]+ gems? installed/.match(line))
|
68
|
+
success = true
|
69
|
+
end
|
70
|
+
if (match = /^Successfully installed/.match(line))
|
71
|
+
success = true
|
72
|
+
end
|
73
|
+
}
|
74
|
+
}
|
75
|
+
if (!success)
|
76
|
+
raise(InstallFailed, "Could not install gem: #{errors.join(', ')}")
|
77
|
+
end
|
78
|
+
}
|
79
|
+
if (ENV['JRUBY'])
|
80
|
+
return "JRuby"
|
81
|
+
elsif (ENV['Rubinius'])
|
82
|
+
return "Rubinius"
|
83
|
+
else
|
84
|
+
return "Ruby"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def step_uninstall()
|
89
|
+
if (ENV['RUBINIUS'])
|
90
|
+
system("rbx", "gem", "uninstall", ball())
|
91
|
+
else
|
92
|
+
system("gem", "uninstall", ball())
|
93
|
+
end
|
94
|
+
super()
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DevBall
|
2
|
+
module PkgSpec
|
3
|
+
class Pecl < Base
|
4
|
+
depends_on "Php"
|
5
|
+
|
6
|
+
def step_extract()
|
7
|
+
end
|
8
|
+
|
9
|
+
def step_configure()
|
10
|
+
# pecl is all three steps in one at install time.
|
11
|
+
end
|
12
|
+
|
13
|
+
def step_build()
|
14
|
+
# gems is all three steps in one at install time.
|
15
|
+
end
|
16
|
+
|
17
|
+
def step_install()
|
18
|
+
Dir.chdir($package_dir) {|dir|
|
19
|
+
if(!system("pecl", "install", ball()))
|
20
|
+
raise(InstallFailed, "Could not install pecl package: #{$?}")
|
21
|
+
end
|
22
|
+
if(!system("pecl", "list-files", "apc")) # pecl install doesn't seem to always return an error code if it fails, so double check
|
23
|
+
raise(InstallFailed, "Could not install pecl package: #{$?}")
|
24
|
+
end
|
25
|
+
}
|
26
|
+
return ["Php"]
|
27
|
+
end
|
28
|
+
|
29
|
+
def step_uninstall()
|
30
|
+
system("pecl", "uninstall", ball())
|
31
|
+
super()
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DevBall
|
2
|
+
module PkgSpec
|
3
|
+
class Tarball < Base
|
4
|
+
# overload if this package is known to extract in a funny way (ie. no top level directory included).
|
5
|
+
# default is to extract directly in the build directory.
|
6
|
+
def extract_dir_name()
|
7
|
+
File.dirname(build_dir_name)
|
8
|
+
end
|
9
|
+
|
10
|
+
def step_extract()
|
11
|
+
# figure out what type of ball it is:
|
12
|
+
ext = ball_file_name.match(/(\.tar|\.tar\.gz|\.tgz|\.tar\.bz2)$/)
|
13
|
+
if (!ext)
|
14
|
+
raise ExtractFailed, "Could not determine type of tarball."
|
15
|
+
end
|
16
|
+
ext = ext[1]
|
17
|
+
args = "xvf"
|
18
|
+
case ext
|
19
|
+
when ".tar.gz", ".tgz":
|
20
|
+
args = "z" + args
|
21
|
+
when ".tar.bz2"
|
22
|
+
args = "j" + args
|
23
|
+
end
|
24
|
+
|
25
|
+
wd = Dir.getwd
|
26
|
+
FileUtils.mkdir_p(extract_dir_name)
|
27
|
+
Dir.chdir(extract_dir_name) {|dir|
|
28
|
+
system("tar", "-#{args}", "#{wd}/#{ball_file_name}") || raise(ExtractFailed, "Could not extract tarball, error #{$?}")
|
29
|
+
}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
File without changes
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: devball
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: "0.3"
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Graham Batty
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-03-04 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: graham at nexopia dot com
|
18
|
+
executables:
|
19
|
+
- devball-build
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README
|
24
|
+
files:
|
25
|
+
- bin/devball
|
26
|
+
- bin/devball-build
|
27
|
+
- bin/devball-pull
|
28
|
+
- bin/devball-push
|
29
|
+
- lib/devball
|
30
|
+
- lib/devball/initialization.rb
|
31
|
+
- lib/devball/pkgspec
|
32
|
+
- lib/devball/pkgspec/base.rb
|
33
|
+
- lib/devball/pkgspec/djb.rb
|
34
|
+
- lib/devball/pkgspec/gem.rb
|
35
|
+
- lib/devball/pkgspec/pecl.rb
|
36
|
+
- lib/devball/pkgspec/simple_dir.rb
|
37
|
+
- lib/devball/pkgspec/tarball.rb
|
38
|
+
- lib/devball/pkgspec/test.rb
|
39
|
+
- README
|
40
|
+
has_rdoc: true
|
41
|
+
homepage: http://github.com/nexopia/devball
|
42
|
+
post_install_message:
|
43
|
+
rdoc_options: []
|
44
|
+
|
45
|
+
require_paths:
|
46
|
+
- lib
|
47
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: "0"
|
52
|
+
version:
|
53
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0"
|
58
|
+
version:
|
59
|
+
requirements: []
|
60
|
+
|
61
|
+
rubyforge_project:
|
62
|
+
rubygems_version: 1.3.1
|
63
|
+
signing_key:
|
64
|
+
specification_version: 2
|
65
|
+
summary: A tool for building a self-contained set of packages that can be portably be moved from one binary-compatible machine to another.
|
66
|
+
test_files: []
|
67
|
+
|