Massive refactoring. See more in git log.
This refactoring includes: - the use of baguette-crystal-base (Baguette::Log, Baguette::Context for verbosity and logfile) - moving configure, build, install and splits backends into dedicated files - removing a lot of code from Package::Context (it was a mess, still kinda is) - fix 32-bit integer bug from APK backend - some API changes in packaging backends to remove the context instance it was replaced by two parameters: package directory and architecture - Baguette, APK and PkgUtils now share (kinda) the same coding style
This commit is contained in:
parent
e0d3c6bf7e
commit
8392363d49
@ -5,7 +5,7 @@ abstract class Package::Backend::Packaging
|
||||
def initialize(@name)
|
||||
end
|
||||
|
||||
abstract def package(context : Context, package : Package) : Bool
|
||||
abstract def package(pkgdir : String, architecture : String, package : Package) : Bool
|
||||
def self.install(packages : Array(String))
|
||||
raise "'install' unimplemented for this backend, yet"
|
||||
end
|
||||
@ -14,13 +14,4 @@ abstract class Package::Backend::Packaging
|
||||
end
|
||||
end
|
||||
|
||||
class Package::Backend::Splitter
|
||||
def initialize(&block : Proc(Recipe, Package))
|
||||
@callback = block
|
||||
end
|
||||
|
||||
def create_split(recipe : Recipe) : Package
|
||||
@callback.call recipe
|
||||
end
|
||||
end
|
||||
|
||||
require "./backends/*"
|
@ -1,23 +1,25 @@
|
||||
require "../backends.cr"
|
||||
|
||||
class ApkBackend < Package::Backend::Packaging
|
||||
class Package::Backend::Packaging::APK < Package::Backend::Packaging
|
||||
def initialize
|
||||
@name = "apk"
|
||||
end
|
||||
|
||||
def package(context : Package::Context, package : Package::Package) : Bool
|
||||
def package(pkgdir : String, architecture : String, package : ::Package::Package) : Bool
|
||||
# FIXME: This needs to have access to architecture (from Context?)
|
||||
# to work properly.
|
||||
old_cwd = Dir.current
|
||||
|
||||
File.write "#{package.fake_root_directory}/.PKGINFO", ApkBackend.pkginfo package
|
||||
APK.pkginfo package, "#{package.fake_root_directory}/.PKGINFO"
|
||||
|
||||
# Create data.tar.gz here.
|
||||
package_target = "#{context.packages_directory}/#{context.architecture}/#{package.name}-#{package.version}-r#{package.release}.apk"
|
||||
package_target = "#{pkgdir}/"
|
||||
package_target += "#{architecture}/"
|
||||
package_target += "#{package.name}-#{package.version}-r#{package.release}.apk"
|
||||
Dir.mkdir_p File.dirname package_target
|
||||
|
||||
# FIXME: This shouldn’t have to be in users’ PATH. libexec?
|
||||
r = context.run package.fake_root_directory, "#{OWN_LIBEXEC_DIR}/assemble-apk.sh", [
|
||||
r = Do.run package.fake_root_directory, "#{OWN_LIBEXEC_DIR}/assemble-apk.sh", [
|
||||
package_target
|
||||
]
|
||||
|
||||
@ -25,34 +27,32 @@ class ApkBackend < Package::Backend::Packaging
|
||||
end
|
||||
|
||||
# This generated file content is specific to the Apk package manager.
|
||||
def self.pkginfo(package)
|
||||
def self.pkginfo(package : ::Package::Package, file_name : String)
|
||||
du = `du -sk #{package.fake_root_directory}`
|
||||
size = du.sub(/[ \t].*/, "").to_i * 1024
|
||||
size = du.sub(/[ \t].*/, "").to_u64 * 1024_u64
|
||||
|
||||
lines = [] of String
|
||||
|
||||
lines << "# Generated by `packaging`."
|
||||
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" # This’ll need to be imported from Context.
|
||||
lines << "builddate = #{Time.utc.to_unix}"
|
||||
File.open file_name, "w" do |file|
|
||||
file.puts "# Generated by `packaging`."
|
||||
file.puts "pkgname = #{package.name}"
|
||||
file.puts "pkgver = #{package.version}-r#{package.release}"
|
||||
file.puts "url = #{package.url || ""} "
|
||||
file.puts "size = #{size}"
|
||||
file.puts "origin = #{package.recipe.name}"
|
||||
file.puts "buildtype = host" # This’ll need to be imported from Context.
|
||||
file.puts "builddate = #{Time.utc.to_unix}"
|
||||
|
||||
package.dependencies.each do |atom|
|
||||
lines << "depend = #{atom.to_s}"
|
||||
file.puts "depend = #{atom.to_s}"
|
||||
end
|
||||
|
||||
package.provides.each do |atom|
|
||||
lines << "provides = #{atom.to_s}"
|
||||
file.puts "provides = #{atom.to_s}"
|
||||
end
|
||||
|
||||
package.conflicts.each do |atom|
|
||||
lines << "conflicts = #{atom.to_s}"
|
||||
file.puts "conflicts = #{atom.to_s}"
|
||||
end
|
||||
end
|
||||
|
||||
lines.join("\n") + "\n"
|
||||
end
|
||||
|
||||
# Install programs.
|
||||
|
@ -3,38 +3,43 @@ require "openssl"
|
||||
require "../backends.cr"
|
||||
|
||||
|
||||
class BaguetteBackend < Package::Backend::Packaging
|
||||
class Package::Backend::Packaging::Baguette < Package::Backend::Packaging
|
||||
def initialize
|
||||
@name = "package"
|
||||
end
|
||||
|
||||
# TODO: checksums + security
|
||||
def package(context : Package::Context, package : Package::Package) : Bool
|
||||
def package(pkgdir : String, architecture : String, package : ::Package::Package) : Bool
|
||||
# Fake root example: /tmp/packages/<uuid>/root-xz-dev
|
||||
fake_root = package.fake_root_directory
|
||||
|
||||
data_archive_path = "#{fake_root}/data.tar"
|
||||
compressed_data_archive_path = "#{fake_root}/data.tar.zst"
|
||||
control_spec_file_path = "#{fake_root}/control.spec"
|
||||
manifest_file_path = "#{fake_root}/manifest"
|
||||
# Temporary archive, before compression.
|
||||
data_archive_path = "#{fake_root}/data.tar" # All archive data.
|
||||
# Content of the final tarball.
|
||||
compressed_data_archive_path = "#{fake_root}/data.tar.zst" # Compressed version (in final tarball).
|
||||
control_spec_file_path = "#{fake_root}/control.spec" # Spec file, with package informations.
|
||||
manifest_file_path = "#{fake_root}/manifest" # List of all the included files.
|
||||
|
||||
package_target = "#{context.packages_directory}/#{package.name}-#{package.version}-#{package.release}.baguette"
|
||||
package_target = "#{pkgdir}/"
|
||||
package_target += "#{architecture}/"
|
||||
package_target += "#{package.name}-#{package.version}-#{package.release}.baguette"
|
||||
Dir.mkdir_p File.dirname package_target
|
||||
|
||||
context.detail "Archiving package content"
|
||||
context.run fake_root, "tar", ["cvf", data_archive_path, "."]
|
||||
::Baguette::Log.detail "Archiving package content"
|
||||
Do.run fake_root, "tar", ["cvf", data_archive_path, "."]
|
||||
|
||||
context.detail "Compressing the archive"
|
||||
::Baguette::Log.detail "Compressing the archive"
|
||||
# produces data.tar.zst
|
||||
context.run fake_root, "zstd", ["--ultra", data_archive_path]
|
||||
Do.run fake_root, "zstd", ["--ultra", data_archive_path]
|
||||
|
||||
context.detail "Generating control.spec"
|
||||
::Baguette::Log.detail "Generating control.spec"
|
||||
generate_spec package, control_spec_file_path
|
||||
|
||||
context.detail "Generating manifest"
|
||||
generate_manifest context, package, manifest_file_path
|
||||
::Baguette::Log.detail "Generating manifest"
|
||||
generate_manifest package, manifest_file_path
|
||||
|
||||
context.detail "Assembling '#{package_target}'"
|
||||
r = context.run fake_root, "tar", [
|
||||
::Baguette::Log.detail "Assembling '#{package_target}'"
|
||||
r = Do.run fake_root, "tar", [
|
||||
"cf", package_target,
|
||||
# WARNING: relative paths are necessary.
|
||||
"control.spec", "manifest", "data.tar.zst"
|
||||
@ -43,12 +48,11 @@ class BaguetteBackend < Package::Backend::Packaging
|
||||
r.exit_status == 0
|
||||
end
|
||||
|
||||
def generate_spec(package : Package::Package, file_name : String)
|
||||
def generate_spec(package : ::Package::Package, file_name : String)
|
||||
du = `du -sk #{package.fake_root_directory}`
|
||||
size = du.sub(/[ \t].*/, "").to_u64 * 1024_u64
|
||||
|
||||
file = File.open file_name, "w"
|
||||
|
||||
File.open file_name, "w" do |file|
|
||||
file.puts "name: #{package.name}"
|
||||
file.puts "version: #{package.version}"
|
||||
file.puts "release: #{package.release}"
|
||||
@ -63,11 +67,10 @@ class BaguetteBackend < Package::Backend::Packaging
|
||||
file.puts "dependencies: #{package.dependencies.join ", "}"
|
||||
file.puts "conflicts: #{package.conflicts.join ", "}"
|
||||
file.puts "provides: #{package.provides.join ", "}"
|
||||
|
||||
file.close
|
||||
end
|
||||
end
|
||||
|
||||
def generate_manifest(context : Package::Context, package : Package::Package, file_name : String)
|
||||
def generate_manifest(package : ::Package::Package, file_name : String)
|
||||
old_pwd = Dir.current
|
||||
|
||||
manifest = File.open(file_name, "w").not_nil!
|
||||
|
23
src/backends/build.cr
Normal file
23
src/backends/build.cr
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
class Package::Backend::Build
|
||||
|
||||
def self.make : Backend::Building
|
||||
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 = Do.sh "make -j#{context.build_cores} #{recipe.options["make"]? || ""}"
|
||||
|
||||
if child.exit_status == 0
|
||||
BuildStatus::Success
|
||||
else
|
||||
BuildStatus::Failed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
47
src/backends/configure.cr
Normal file
47
src/backends/configure.cr
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
class Package::Backend::Configure
|
||||
|
||||
def self.autotools : Backend::Building
|
||||
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 = Do.sh "./configure --prefix=#{recipe.prefix} #{recipe.options["configure"]? || ""}"
|
||||
|
||||
if child.exit_status == 0
|
||||
BuildStatus::Success
|
||||
else
|
||||
BuildStatus::Failed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.cmake : Backend::Building
|
||||
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"]}",
|
||||
"-- -j#{context.build_cores}"
|
||||
]
|
||||
|
||||
child = Do.sh "cmake . #{options.join " "}"
|
||||
if child.exit_status == 0
|
||||
BuildStatus::Success
|
||||
else
|
||||
BuildStatus::Failed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
23
src/backends/install.cr
Normal file
23
src/backends/install.cr
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
class Package::Backend::Install
|
||||
def self.make : Backend::Building
|
||||
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 = Do.sh "make install 'DESTDIR=#{recipe.fake_root_directory}' #{recipe.options["make install"]? || ""}"
|
||||
|
||||
if child.exit_status == 0
|
||||
BuildStatus::Success
|
||||
else
|
||||
BuildStatus::Failed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -1,13 +1,21 @@
|
||||
require "../backends.cr"
|
||||
require "baguette-crystal-base"
|
||||
|
||||
class PkgutilsBackend < Package::Backend::Packaging
|
||||
# This packaging backend only helps to create a package containing the data.
|
||||
# This serves as the simplest example of packaging system:
|
||||
# no extra data nor structure in the final archive.
|
||||
|
||||
class Package::Backend::Packaging::Pkgutils < Package::Backend::Packaging
|
||||
def initialize
|
||||
@name = "pkgutils"
|
||||
end
|
||||
|
||||
def package(context : Package::Context, package : Package::Package) : Bool
|
||||
puts "#{package.fake_root_directory} -> #{context.packages_directory}/#{package.name}##{package.version}-#{package.release}.pkg.tar.xz"
|
||||
pp! r = context.run package.fake_root_directory, "tar", ["cJf", "#{context.packages_directory}/#{package.name}##{package.version}.pkg.tar.xz", "."]
|
||||
def package(pkgdir : String, architecture : String, package : ::Package::Package) : Bool
|
||||
package_file = pkgdir + "/" + architecture + "/"
|
||||
package_file += "#{package.name}-#{package.version}-#{package.release}.pkg.tar.xz"
|
||||
|
||||
::Baguette::Log.info "#{package.fake_root_directory} -> #{package_file}"
|
||||
pp! r = Do.run package.fake_root_directory, "tar", ["cJf", package_file, "."]
|
||||
|
||||
r.exit_status == 0
|
||||
end
|
||||
|
75
src/backends/splitter.cr
Normal file
75
src/backends/splitter.cr
Normal file
@ -0,0 +1,75 @@
|
||||
|
||||
class Package::Backend::Splitter
|
||||
def initialize(&block : Proc(Recipe, Package))
|
||||
@callback = block
|
||||
end
|
||||
|
||||
def create_split(recipe : Recipe) : Package
|
||||
@callback.call recipe
|
||||
end
|
||||
|
||||
# Package::Backend::Splitter = create new package
|
||||
# takes (then stores) the given block
|
||||
# this block takes a recipe as a parameter and create a new package
|
||||
# the new package:
|
||||
# keep prefixes
|
||||
# new name = split name (-man, -src, ...)
|
||||
# split files
|
||||
|
||||
# Man-pages and documentation
|
||||
def self.man(prefixes : Array(String)) : Splitter
|
||||
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
|
||||
split.recipe.require_stripping = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Developer's files: headers, pkgconfig files, *.a.
|
||||
def self.dev(prefixes : Array(String)) : Splitter
|
||||
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
|
||||
# Any prefix containing "/include/"
|
||||
split.file_patterns.not_nil! << Regex.new(".*/include/.*.h(pp)?")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Source files: prefix containing "src".
|
||||
def self.src(prefixes : Array(String)) : Splitter
|
||||
Backend::Splitter.new do |recipe|
|
||||
Package.new(recipe, true).tap do |split|
|
||||
prefixes = (prefixes + [recipe.prefix]).uniq
|
||||
|
||||
split.name = "#{recipe.name}-src"
|
||||
split.files = prefixes.map do |prefix|
|
||||
[
|
||||
"#{prefix}/lib/share/src",
|
||||
"#{prefix}/src",
|
||||
"#{prefix}/usr/src",
|
||||
"#{prefix}/usr/local/src"
|
||||
]
|
||||
end.flatten
|
||||
split.recipe.require_stripping = false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
242
src/context.cr
242
src/context.cr
@ -1,14 +1,8 @@
|
||||
require "colorize"
|
||||
|
||||
require "specparser"
|
||||
|
||||
require "./exception.cr"
|
||||
|
||||
require "./config.cr"
|
||||
|
||||
require "./backends/baguette.cr"
|
||||
require "./backends/apk.cr"
|
||||
require "./backends/pkgutils.cr"
|
||||
require "./backends.cr"
|
||||
|
||||
class Package::Context
|
||||
@ -29,157 +23,37 @@ class Package::Context
|
||||
|
||||
# prefixes for `packaging` running environment and child processes
|
||||
# = where to search for binaries and libraries for the build
|
||||
property prefixes = ["/usr", "/", "/usr/baguette"]
|
||||
property prefixes = ["/usr/baguette", "/usr", "/"]
|
||||
|
||||
# By default, building a package only uses one core
|
||||
property build_cores = 1
|
||||
|
||||
# list of environment variables we want to have when building
|
||||
property environment = {} of String => String
|
||||
|
||||
property verbosity = 0
|
||||
#property environment = {} of String => String
|
||||
|
||||
property recipe : Recipe? = nil
|
||||
|
||||
|
||||
def initialize
|
||||
@packaging_backends << ApkBackend.new
|
||||
@packaging_backends << BaguetteBackend.new
|
||||
@packaging_backends << PkgutilsBackend.new
|
||||
# Add package backends: baguette (package-tools) and apk.
|
||||
# They implement the Backend::Packaging abstract class:
|
||||
# init (@name) + package (context, package) method
|
||||
@packaging_backends << Backend::Packaging::Baguette.new
|
||||
@packaging_backends << Backend::Packaging::APK.new
|
||||
@packaging_backends << Backend::Packaging::Pkgutils.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
|
||||
# Add building backends: configuration, build and install.
|
||||
@building_backends << Backend::Configure.autotools
|
||||
@building_backends << Backend::Configure.cmake
|
||||
@building_backends << Backend::Build.make
|
||||
@building_backends << Backend::Install.make
|
||||
|
||||
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"]}",
|
||||
"-- -j#{context.build_cores}"
|
||||
]
|
||||
|
||||
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 -j#{context.build_cores} #{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
|
||||
|
||||
# Package::Backend::Splitter = create new package
|
||||
# takes (then stores) the given block
|
||||
# this block takes a recipe as a parameter and create a new package
|
||||
# the new package:
|
||||
# keep prefixes
|
||||
# new name = split name (-man, -src, ...)
|
||||
# split files
|
||||
|
||||
# Man-pages and documentation
|
||||
@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
|
||||
split.recipe.require_stripping = false
|
||||
end
|
||||
end
|
||||
|
||||
# Developer's files: headers, pkgconfig files, *.a.
|
||||
@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
|
||||
# Any prefix containing "/include/"
|
||||
split.file_patterns.not_nil! << Regex.new(".*/include/.*/")
|
||||
end
|
||||
end
|
||||
|
||||
# Source files: prefix containing "src".
|
||||
@splitter_backends << Backend::Splitter.new do |recipe|
|
||||
Package.new(recipe, true).tap do |split|
|
||||
prefixes = (@prefixes + [recipe.prefix]).uniq
|
||||
|
||||
split.name = "#{recipe.name}-src"
|
||||
split.files = prefixes.map do |prefix|
|
||||
[
|
||||
"#{prefix}/lib/share/src",
|
||||
"#{prefix}/src",
|
||||
"#{prefix}/usr/src",
|
||||
"#{prefix}/usr/local/src"
|
||||
]
|
||||
end.flatten
|
||||
split.recipe.require_stripping = false
|
||||
end
|
||||
end
|
||||
# Split = new package from a recipe, each one with different files being included.
|
||||
@splitter_backends << Backend::Splitter.man @prefixes
|
||||
@splitter_backends << Backend::Splitter.dev @prefixes
|
||||
@splitter_backends << Backend::Splitter.src @prefixes
|
||||
end
|
||||
|
||||
def packaging_backend=(name : String)
|
||||
@ -190,84 +64,8 @@ class Package::Context
|
||||
@selected_packaging_backend = backend
|
||||
end
|
||||
|
||||
def run(chdir, command, args)
|
||||
output = Process::Redirect::Inherit
|
||||
|
||||
if @verbosity < -1
|
||||
output = Process::Redirect::Close
|
||||
else
|
||||
# log sub-commands outputs
|
||||
logfile_path = "#{@working_directory}/#{@recipe.not_nil!.working_uuid}.log"
|
||||
output = File.open logfile_path, "a"
|
||||
STDOUT.puts "logging command " +
|
||||
"#{command} #{args}".colorize(:light_magenta).to_s
|
||||
STDOUT.puts "in " + logfile_path.colorize(:blue).mode(:bright).to_s
|
||||
|
||||
output.puts ""
|
||||
output.puts ""
|
||||
output.puts "logging command $ #{command}"
|
||||
output.puts " parameters $ #{args}"
|
||||
end
|
||||
|
||||
c = Process.run command, args, chdir: chdir, output: output, error: output, env: @environment
|
||||
|
||||
case output
|
||||
when File
|
||||
output.close
|
||||
end
|
||||
|
||||
c
|
||||
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
|
||||
|
||||
# Log file moves during splits.
|
||||
def mv(f1 : String, f2 : String)
|
||||
run "mv", [ f1, f2 ]
|
||||
end
|
||||
|
||||
# Log directory creations during splits.
|
||||
def mkdir_p(dir : String)
|
||||
run "mkdir", [ "-p", dir ]
|
||||
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
|
||||
@selected_packaging_backend.package @packages_directory, @architecture, package
|
||||
end
|
||||
|
||||
def read_recipe(filename : String)
|
||||
@ -320,8 +118,8 @@ class Package::Context
|
||||
end
|
||||
|
||||
key, value = match
|
||||
@environment[key] = value
|
||||
if @verbosity > 0
|
||||
Do.environment[key] = value
|
||||
if Baguette::Context.verbosity > 2
|
||||
STDOUT.puts "environment: #{key} => #{value}"
|
||||
end
|
||||
end
|
||||
|
66
src/do.cr
66
src/do.cr
@ -1,9 +1,75 @@
|
||||
|
||||
class Baguette::Context
|
||||
#class_property logfile_path = "#{@working_directory}/#{@recipe.not_nil!.working_uuid}.log"
|
||||
class_property logfile_path = "/tmp/package-create.log"
|
||||
class_property no_logfile = false
|
||||
end
|
||||
|
||||
class Do < Process
|
||||
class_property environment = {} of String => String
|
||||
|
||||
def self.require_cmd(cmd : String)
|
||||
unless Process.run("which", [ cmd ]).success?
|
||||
STDERR.puts "#{cmd} isn't installed"
|
||||
exit 1
|
||||
end
|
||||
end
|
||||
|
||||
def self.run(chdir, command, args)
|
||||
output = Process::Redirect::Inherit
|
||||
|
||||
if Baguette::Context.no_logfile
|
||||
output = Process::Redirect::Close
|
||||
else
|
||||
# log sub-commands outputs
|
||||
STDOUT.puts "logging command " +
|
||||
"#{command} #{args}".colorize(:light_magenta).to_s
|
||||
STDOUT.puts "in " + Baguette::Context.logfile_path.colorize(:blue).mode(:bright).to_s
|
||||
|
||||
File.open Baguette::Context.logfile_path, "a" do |file|
|
||||
file.puts ""
|
||||
file.puts ""
|
||||
file.puts "logging command $ #{command}"
|
||||
file.puts " parameters $ #{args}"
|
||||
end
|
||||
end
|
||||
|
||||
c = Process.run command, args, chdir: chdir, output: output, error: output, env: @@environment
|
||||
|
||||
case output
|
||||
when File
|
||||
output.close
|
||||
end
|
||||
|
||||
c
|
||||
end
|
||||
|
||||
def self.run(command, args)
|
||||
self.run nil, command, args
|
||||
end
|
||||
|
||||
def self.run(command)
|
||||
self.run nil, command, nil
|
||||
end
|
||||
|
||||
def self.sh(command)
|
||||
self.run nil, "sh", ["-x", "-e", "-c", command]
|
||||
end
|
||||
|
||||
def self.captured_sh(command)
|
||||
output = IO::Memory.new
|
||||
child = Process.run "sh", ["-x", "-e", "-c", command], output: output
|
||||
|
||||
{child, output}
|
||||
end
|
||||
|
||||
# Log file moves during splits.
|
||||
def self.mv(f1 : String, f2 : String)
|
||||
self.run "mv", [ f1, f2 ]
|
||||
end
|
||||
|
||||
# Log directory creations during splits.
|
||||
def self.mkdir_p(dir : String)
|
||||
self.run "mkdir", [ "-p", dir ]
|
||||
end
|
||||
end
|
||||
|
@ -28,7 +28,7 @@ class Package::Instructions
|
||||
def run(context : Context, recipe : Recipe) : BuildStatus
|
||||
if size > 0
|
||||
each do |command|
|
||||
child = context.run recipe.building_directory, "sh", ["-x", "-c", command]
|
||||
child = Do.run recipe.building_directory, "sh", ["-x", "-c", command]
|
||||
|
||||
if child.exit_status != 0
|
||||
return BuildStatus::Failed
|
||||
|
@ -1,6 +1,7 @@
|
||||
require "option_parser"
|
||||
require "file_utils"
|
||||
require "colorize"
|
||||
require "baguette-crystal-base"
|
||||
|
||||
require "./context.cr"
|
||||
require "./recipe.cr"
|
||||
@ -70,11 +71,11 @@ OptionParser.parse do |parser|
|
||||
}
|
||||
|
||||
parser.on("-v", "--verbose", "Runs more verbosely.") {
|
||||
context.verbosity += 1
|
||||
Baguette::Context.verbosity += 1
|
||||
}
|
||||
|
||||
parser.on("-q", "--quiet", "Runs more quietely.") {
|
||||
context.verbosity -= 1
|
||||
Baguette::Context.verbosity -= 1
|
||||
}
|
||||
|
||||
parser.on("-n", "--ignore-dependencies", "Do not try to install build-dependencies.") {
|
||||
@ -172,7 +173,7 @@ begin
|
||||
recipes.each do |recipe|
|
||||
latest_build_dir = recipe.building_directory
|
||||
|
||||
context.title recipe.name
|
||||
Baguette::Log.title recipe.name
|
||||
|
||||
recipe.download
|
||||
|
||||
|
@ -216,13 +216,13 @@ class Package::Recipe
|
||||
|
||||
unless File.exists? filename
|
||||
if url.scheme == "file"
|
||||
@context.info "Copying '#{url.filename}'"
|
||||
Baguette::Log.info "Copying '#{url.filename}'"
|
||||
|
||||
FileUtils.cp "#{recipe_directory}/#{url.filename}", filename
|
||||
else
|
||||
@context.info "Downloading '#{url.filename}'"
|
||||
Baguette::Log.info "Downloading '#{url.filename}'"
|
||||
|
||||
status = @context.run @context.sources_directory, "wget", [ url.to_s, "-O", filename ]
|
||||
status = Do.run @context.sources_directory, "wget", [ url.to_s, "-O", filename ]
|
||||
|
||||
raise DownloadError.new self, url unless status.success?
|
||||
end
|
||||
@ -231,15 +231,15 @@ class Package::Recipe
|
||||
end
|
||||
|
||||
def extract
|
||||
@context.mkdir_p building_directory
|
||||
Do.mkdir_p building_directory
|
||||
|
||||
sources.each do |url|
|
||||
basename = url.filename
|
||||
|
||||
if basename.match /\.(tar\.(gz|xz|bz2|lzma)|tgz)$/
|
||||
@context.info "Extracting '#{url.filename}'"
|
||||
Baguette::Log.info "Extracting '#{url.filename}'"
|
||||
|
||||
status = @context.run(
|
||||
status = Do.run(
|
||||
building_directory,
|
||||
"bsdtar", [
|
||||
"xf",
|
||||
@ -249,9 +249,9 @@ class Package::Recipe
|
||||
|
||||
raise ExtractionError.new self, url unless status.success?
|
||||
elsif basename.match /\.patch$/
|
||||
@context.info "Applying '#{url.filename}'"
|
||||
Baguette::Log.info "Applying '#{url.filename}'"
|
||||
|
||||
status = @context.run(
|
||||
status = Do.run(
|
||||
"#{building_directory}/#{dirname}",
|
||||
"patch", [
|
||||
"-i", "#{@context.sources_directory}/#{url.filename}"
|
||||
@ -260,7 +260,7 @@ class Package::Recipe
|
||||
|
||||
raise ExtractionError.new self, url unless status.success?
|
||||
else
|
||||
@context.info "Copying '#{url.filename}'"
|
||||
Baguette::Log.info "Copying '#{url.filename}'"
|
||||
|
||||
directory = if url.scheme == "file"
|
||||
@recipe_directory
|
||||
@ -282,7 +282,7 @@ class Package::Recipe
|
||||
# goes somehow wrong.
|
||||
# - Make things thread-safe. (those ENV[]= calls are definitely not)
|
||||
def build
|
||||
@context.mkdir_p fake_root_directory
|
||||
Do.mkdir_p fake_root_directory
|
||||
|
||||
ENV["PKG"] = fake_root_directory
|
||||
|
||||
@ -290,7 +290,7 @@ class Package::Recipe
|
||||
old_dir = Dir.current
|
||||
|
||||
instructions.to_a.each do |instruction|
|
||||
@context.info "Building ('#{instruction.phase}' phase)"
|
||||
Baguette::Log.info "Building ('#{instruction.phase}' phase)"
|
||||
|
||||
if instruction.run(@context, self).failed?
|
||||
raise BuildError.new self, "Building (#{instruction.phase} phase) failed."
|
||||
@ -312,7 +312,7 @@ class Package::Recipe
|
||||
end
|
||||
|
||||
private def do_strip
|
||||
@context.info "Stripping binaries"
|
||||
Baguette::Log.info "Stripping binaries"
|
||||
|
||||
FileUtils.find_files(fake_root_directory) do |path|
|
||||
file_output = `file #{path}`
|
||||
@ -327,7 +327,7 @@ class Package::Recipe
|
||||
end
|
||||
|
||||
if strip_opt
|
||||
@context.detail "stripping #{path}"
|
||||
Baguette::Log.detail "stripping #{path}"
|
||||
|
||||
Process.run "strip", [strip_opt, path]
|
||||
end
|
||||
@ -357,7 +357,7 @@ class Package::Recipe
|
||||
end
|
||||
|
||||
if files_to_split.size > 0
|
||||
@context.info "Splitting " + "'#{package.name}'".colorize(:light_red).underline.to_s
|
||||
Baguette::Log.info "Splitting " + "'#{package.name}'".colorize(:light_red).underline.to_s
|
||||
end
|
||||
|
||||
# FIXME: What do we do if those are not on the filesystem?
|
||||
@ -365,11 +365,11 @@ class Package::Recipe
|
||||
origin = "#{fake_root_directory}#{file}"
|
||||
destination = "#{package.fake_root_directory}#{file}"
|
||||
|
||||
@context.detail "Moving '#{file}' to split"
|
||||
Baguette::Log.detail "Moving '#{file}' to split"
|
||||
|
||||
@context.mkdir_p File.dirname destination
|
||||
Do.mkdir_p File.dirname destination
|
||||
|
||||
@context.mv(
|
||||
Do.mv(
|
||||
"#{fake_root_directory}#{file}",
|
||||
"#{package.fake_root_directory}#{file}"
|
||||
)
|
||||
@ -394,7 +394,7 @@ class Package::Recipe
|
||||
next
|
||||
end
|
||||
|
||||
@context.info "Assembling " + "'#{package.name}'".colorize(:light_red).underline.to_s
|
||||
Baguette::Log.info "Assembling " + "'#{package.name}'".colorize(:light_red).underline.to_s
|
||||
|
||||
unless @context.package package
|
||||
raise PackagingError.new self, package
|
||||
@ -408,7 +408,7 @@ class Package::Recipe
|
||||
|
||||
def watch
|
||||
if script = @watch_script
|
||||
status, output = @context.captured_sh script
|
||||
status, output = Do.captured_sh script
|
||||
|
||||
output = output.to_s
|
||||
.gsub(/^[ \t\n]*/, "").gsub(/[ \t\n]*$/, "")
|
||||
|
@ -44,7 +44,7 @@ class Action
|
||||
|
||||
latest_build_dir = recipe.building_directory
|
||||
|
||||
context.title recipe.name
|
||||
Do.title recipe.name
|
||||
|
||||
# recipe.download
|
||||
# recipe.extract
|
||||
|
Reference in New Issue
Block a user