devball 0.3

Sign up to get free protection for your applications and to get access to all the features.
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
+