This repository has been archived on 2022-01-17. You can view files and clone it, but cannot push or open issues/pull-requests.
packaging/src/context.cr

283 lines
6.7 KiB
Crystal
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

require "colorize"
require "specparser"
require "./exception.cr"
require "./config.cr"
require "./backends/weird.cr"
require "./backends/apk.cr"
require "./backends/pkgutils.cr"
require "./backends.cr"
# FIXME: Where should this go? We cant just leave it here. :(
def pkginfo(package)
du = `du -sk #{package.fake_root_directory}`
size = du.sub(/[ \t].*/, "").to_i * 1024
lines = [] of String
lines << "# Generated by `package`."
lines << "pkgname = #{package.name}"
lines << "pkgver = #{package.version}-r#{package.release}"
lines << "url = #{package.url || ""} "
lines << "size = #{size}"
lines << "origin = #{package.recipe.name}"
lines << "buildtype = host" # Thisll need to be imported from Context.
lines << "builddate = #{Time.utc.to_unix}"
package.dependencies.each do |atom|
lines << "depend = #{atom.to_s}"
end
package.provides.each do |atom|
lines << "provides = #{atom.to_s}"
end
package.conflicts.each do |atom|
lines << "conflicts = #{atom.to_s}"
end
lines.join("\n") + "\n"
end
class Package::Context
property working_directory = "/tmp/package"
property sources_directory = Dir.current
property packages_directory = Dir.current
getter packaging_backends = [] of Backend::Packaging
getter building_backends = [] of Backend::Building
getter splitter_backends = [] of Backend::Splitter
# Directories where ports can be found.
getter repositories = [] of String
# Well, this will need configuration, auto-detection and conversion,
# but itll be kind of enough for now.
property architecture = "x86_64"
property prefixes = ["/usr", "/", "/usr/weirdos"]
property environment = {} of String => String
property verbosity = 0
def initialize
@packaging_backends << ApkBackend.new
@packaging_backends << WeirdBackend.new
@packaging_backends << PkgutilsBackend.new
@selected_packaging_backend = @packaging_backends[0]
@building_backends << Backend::Building.new "configure", "autotools" do |context, recipe|
next BuildStatus::Pass unless Dir.exists? recipe.dirname
Dir.cd recipe.dirname
unless File.exists? "configure"
next BuildStatus::Pass
end
child = context.sh "./configure --prefix=#{recipe.prefix} #{recipe.options["configure"]? || ""}"
if child.exit_status == 0
BuildStatus::Success
else
BuildStatus::Failed
end
end
@building_backends << Backend::Building.new "configure", "cmake" do |context, recipe|
next BuildStatus::Pass unless Dir.exists? recipe.dirname
Dir.cd recipe.dirname
next BuildStatus::Pass unless File.exists? "CMakeLists.txt"
options = [
"-DCMAKE_INSTALL_PREFIX='#{recipe.prefix}'",
"-DCMAKE_BUILD_TYPE=Release #{recipe.options["cmake"]}"
]
child = context.sh "cmake . #{options.join " "}"
if child.exit_status == 0
BuildStatus::Success
else
BuildStatus::Failed
end
end
@building_backends << Backend::Building.new "build", "make" do |context, recipe|
next BuildStatus::Pass unless Dir.exists? recipe.dirname
Dir.cd recipe.dirname
unless File.exists? "Makefile"
next BuildStatus::Pass
end
child = context.sh "make #{recipe.options["make"]? || ""}"
if child.exit_status == 0
BuildStatus::Success
else
BuildStatus::Failed
end
end
@building_backends << Backend::Building.new "install", "make" do |context, recipe|
next BuildStatus::Pass unless Dir.exists? recipe.dirname
Dir.cd recipe.dirname
unless File.exists? "Makefile"
next BuildStatus::Pass
end
child = context.sh "make install 'DESTDIR=#{recipe.fake_root_directory}' #{recipe.options["make install"]? || ""}"
if child.exit_status == 0
BuildStatus::Success
else
BuildStatus::Failed
end
end
@splitter_backends << Backend::Splitter.new do |recipe|
Package.new(recipe, true).tap do |split|
prefixes = (@prefixes + [recipe.prefix]).uniq
split.name = "#{recipe.name}-man"
split.files = prefixes.map do |prefix|
"#{prefix}/share/man"
end
end
end
@splitter_backends << Backend::Splitter.new do |recipe|
Package.new(recipe, true).tap do |split|
prefixes = (@prefixes + [recipe.prefix]).uniq
split.name = "#{recipe.name}-dev"
split.files = prefixes.map do |prefix|
[
"#{prefix}/include",
"#{prefix}/lib/pkgconfig"
]
end.flatten
split.file_patterns = prefixes.map do |prefix|
Regex.new("^" + prefix + ".*\\.a$")
end
end
end
end
def packaging_backend=(name : String)
@selected_packaging_backend = @packaging_backends.find(&.name.==(name)).not_nil!
end
def packaging_backend=(backend : Backend::Packaging)
@selected_packaging_backend = backend
end
def run(chdir, command, args)
output = Process::Redirect::Inherit
if @verbosity < -1
output = Process::Redirect::Close
end
Process.run command, args, chdir: chdir, output: output, error: output, env: @environment
end
def run(command, args)
run nil, command, args
end
def run(command)
run nil, command, nil
end
def sh(command)
run nil, "sh", ["-x", "-e", "-c", command]
end
def captured_sh(command)
output = IO::Memory.new
child = Process.run "sh", ["-x", "-e", "-c", command], output: output
{child, output}
end
# Output functions.
def title(s)
return if @verbosity < -3
puts ">> ".colorize(:green).mode(:bright).to_s +
s.colorize(:white).mode(:bright).to_s
STDOUT.flush
end
def info(s)
return if @verbosity < -2
puts ":: ".colorize(:green).to_s + s.colorize(:white).to_s
STDOUT.flush
end
def detail(s)
return if @verbosity < -1
puts ("+ " + s).colorize(:cyan)
STDOUT.flush
end
def package(package : Package) : Bool
@selected_packaging_backend.package self, package
end
def read_recipe(filename : String)
Recipe.new self, filename
end
def find_recipe(name : String) : Recipe?
recipe_file_name = ""
repo = @repositories.find do |repo|
repo_dir_name = "#{repo}/#{name}"
recipe_file_name = "#{repo_dir_name}/recipe.spec"
if Dir.exists?(repo_dir_name) && File.exists?(recipe_file_name)
next true
end
end
read_recipe recipe_file_name if repo
end
def read_configuration(filename : String)
specs = SpecParser.parse(filename)
specs.assignments.each do |key, value|
case key
when "packages-directory"
@packages_directory = value.as_s
when "sources-directory"
@sources_directory = value.as_s
when "prefixes"
@prefixes = value.as_a_or_s
when "environment"
value.as_a_or_s.each do |entry|
match = entry.split(':').map(
&.gsub(/^[ \t]*/, "").gsub(/[ \t]*$/, ""))
if match.size != 2
STDERR.puts "WARNING: misformed environment definition: #{entry}"
next
end
key, value = match
@environment[key] = value
end
when "package-manager"
self.packaging_backend = value.as_s
end
end
end
end