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/recipe.cr

176 lines
3.7 KiB
Crystal
Raw Normal View History

2019-07-02 03:50:50 +02:00
require "uuid"
require "uri"
require "file_utils"
require "./context.cr"
require "./package.cr"
require "./instructions.cr"
require "./sources.cr"
# 🤔
class URI
def basename
File.basename path
end
end
class Package::Recipe
@context : Context
# Core recipe informations.
getter name : String
getter version : String
getter release = 1
2019-07-02 03:50:50 +02:00
property url : String?
property description : String = ""
# Informations not specific to individual packages.
getter sources : Sources
getter packages : Array(Package)
property packager : String?
property maintainer : String?
getter contributors = Array(String).new
# Relations to other packages.
# FIXME: `dependencies` needs splitting between run-time and build-time.
getter dependencies = Array(String).new
getter provides = Array(String).new
getter conflicts = Array(String).new
# Build instructions, helpers and other build-only data.
setter dirname : String? # matching getter defined manually later.
getter instructions = Instructions.new
2019-07-02 03:50:50 +02:00
def initialize(@context, @name, @version)
@sources = Sources.new
@packages = [] of Package
2019-07-02 03:50:50 +02:00
@working_uuid = UUID.random
end
def self.new(context, name, version)
instance = Recipe.allocate.tap &.initialize(context, name, version)
instance.packages << Package.new instance
instance
end
2019-07-02 03:50:50 +02:00
def working_directory
2019-07-03 05:23:48 +02:00
"#{@context.working_directory}/#{@working_uuid}"
2019-07-02 03:50:50 +02:00
end
def building_directory
"#{working_directory}/build"
end
def fake_root_directory
2019-07-04 07:51:00 +02:00
@packages[0].fake_root_directory
2019-07-02 03:50:50 +02:00
end
2019-07-02 08:47:11 +02:00
def dirname
@dirname || "#{name}-#{version}"
end
2019-07-02 03:50:50 +02:00
def download
sources.map do |url|
unless File.exists? url.basename
2019-07-02 19:45:33 +02:00
@context.run @context.sources_directory, "wget", [ url.to_s, "-O", url.basename ]
2019-07-02 03:50:50 +02:00
end
end
end
def extract
Dir.mkdir_p building_directory
sources.map do |url|
basename = url.basename
2019-07-02 19:45:33 +02:00
@context.run building_directory, "tar", [ "xvf", @context.sources_directory + "/" + url.basename ]
2019-07-02 03:50:50 +02:00
end
end
# TODO:
# - Export packaging directory in $PKG.
# - Add (pre|post)-(configure|build|install) instructions.
# - Have some instructions be non-critical, like the (pre|post] ones.
# - Be careful about return values, flee from everything if something
# goes somehow wrong.
# - Make things thread-safe. (those ENV[]= calls are definitely not)
def build
2019-07-02 08:47:11 +02:00
success = true
2019-07-02 03:50:50 +02:00
Dir.mkdir_p fake_root_directory
ENV["PKG"] = fake_root_directory
2019-07-02 19:45:33 +02:00
# Safety precautions.
2019-07-02 08:47:11 +02:00
old_dir = Dir.current
instructions.to_a.each do |instruction|
2019-07-02 19:45:33 +02:00
if instruction.run(@context, self).failed?
2019-07-03 03:48:31 +02:00
break BuildStatus::Failed
2019-07-02 08:47:11 +02:00
end
2019-07-02 03:50:50 +02:00
end
2019-07-02 08:47:11 +02:00
Dir.cd old_dir
2019-07-02 03:50:50 +02:00
ENV["PKG"] = nil
2019-07-02 08:47:11 +02:00
2019-07-04 07:51:00 +02:00
do_splits
2019-07-02 08:47:11 +02:00
success
2019-07-02 03:50:50 +02:00
end
2019-07-04 07:51:00 +02:00
private def do_splits
@packages.each do |package|
next if package == @packages[0]
files = package.files
next if files.nil? # Should only happen to @packages[0].
# TODO: ↑ add public APIs that ensure it.
Dir.mkdir_p package.fake_root_directory
# FIXME: What do we do if those are not on the filesystem?
files.each do |file|
puts "#{package.fake_root_directory}#{File.dirname file}"
Dir.mkdir_p "#{package.fake_root_directory}#{File.dirname file}"
FileUtils.mv(
"#{fake_root_directory}#{file}",
"#{package.fake_root_directory}#{file}"
)
puts file
@context.run "find", [
"#{package.fake_root_directory}/#{file}"
]
end
end
end
# TODO:
# - Errors management. Stop at first failure?
# - Splits. This should be done between #build and #package.
2019-07-02 03:50:50 +02:00
def package
@packages.find do |package|
! @context.package package
end
2019-07-02 03:50:50 +02:00
end
def clean
FileUtils.rm_rf building_directory
FileUtils.rm_rf fake_root_directory
end
def to_s
"#{name}-#{version}"
end
end