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 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
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env ruby
2
+ if (File.exists?("#{__FILE__}-#{ARGV[0]}"))
3
+ $0 += " " + ARGV[0]
4
+ load("#{__FILE__}-#{ARGV.shift}")
5
+ exit(0)
6
+ end
7
+
8
+ puts("Unknown devball command #{ARGV[0]}")
9
+ exit(1)
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,9 @@
1
+ module DevBall
2
+ module PkgSpec
3
+ class SimpleDir < Base
4
+ def step_extract()
5
+ system("cp", "-r", ball_file_name, build_dir_name) || raise(ExtractFailed, "Failed to copy ball into build.")
6
+ end
7
+ end
8
+ end
9
+ 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
+