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
|
|
|
|
|
2019-07-03 04:24:33 +02:00
|
|
|
# Core recipe informations.
|
|
|
|
getter name : String
|
|
|
|
getter version : String
|
|
|
|
getter release = 1
|
2019-07-02 03:50:50 +02:00
|
|
|
|
2019-07-03 04:24:33 +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-23 16:41:34 +02:00
|
|
|
getter options = Hash(String, String).new
|
2019-07-02 03:50:50 +02:00
|
|
|
|
|
|
|
def initialize(@context, @name, @version)
|
|
|
|
@sources = Sources.new
|
2019-07-03 03:17:01 +02:00
|
|
|
@packages = [] of Package
|
2019-07-02 03:50:50 +02:00
|
|
|
|
|
|
|
@working_uuid = UUID.random
|
|
|
|
end
|
|
|
|
|
2019-07-03 03:17:01 +02:00
|
|
|
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-20 13:30:09 +02:00
|
|
|
def download : Bool
|
|
|
|
sources
|
|
|
|
.compact_map do |url|
|
|
|
|
unless File.exists? url.basename
|
|
|
|
@context.run @context.sources_directory, "wget", [ url.to_s, "-O", url.basename ]
|
|
|
|
end
|
2019-07-02 03:50:50 +02:00
|
|
|
end
|
2019-07-20 13:30:09 +02:00
|
|
|
.map(&.success?)
|
|
|
|
.reduce(true) { |a, b| a && b }
|
2019-07-02 03:50:50 +02:00
|
|
|
end
|
|
|
|
|
2019-07-20 13:30:09 +02:00
|
|
|
def extract : Bool
|
2019-07-02 03:50:50 +02:00
|
|
|
Dir.mkdir_p building_directory
|
|
|
|
|
2019-07-20 13:30:09 +02:00
|
|
|
sources
|
|
|
|
.map do |url|
|
|
|
|
basename = url.basename
|
2019-07-02 03:50:50 +02:00
|
|
|
|
2019-07-20 13:30:09 +02:00
|
|
|
@context.run building_directory, "tar", [ "xvf", @context.sources_directory + "/" + url.basename ]
|
|
|
|
end
|
|
|
|
.map(&.success?)
|
|
|
|
.reduce true { |a, b| a && b }
|
2019-07-02 03:50:50 +02:00
|
|
|
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)
|
2019-07-20 13:30:09 +02:00
|
|
|
def build : Bool
|
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
|
2019-07-20 13:52:24 +02:00
|
|
|
(@packages + auto_splits).each do |package|
|
2019-07-04 07:51:00 +02:00
|
|
|
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.
|
|
|
|
|
|
|
|
# FIXME: What do we do if those are not on the filesystem?
|
|
|
|
files.each do |file|
|
2019-07-04 23:18:54 +02:00
|
|
|
origin = "#{fake_root_directory}#{file}"
|
|
|
|
destination ="#{package.fake_root_directory}#{file}"
|
|
|
|
|
|
|
|
next unless File.exists? origin
|
|
|
|
|
|
|
|
Dir.mkdir_p File.dirname destination
|
2019-07-04 07:51:00 +02:00
|
|
|
|
|
|
|
FileUtils.mv(
|
|
|
|
"#{fake_root_directory}#{file}",
|
|
|
|
"#{package.fake_root_directory}#{file}"
|
|
|
|
)
|
|
|
|
|
|
|
|
puts file
|
|
|
|
@context.run "find", [
|
|
|
|
"#{package.fake_root_directory}/#{file}"
|
|
|
|
]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-20 13:52:24 +02:00
|
|
|
def auto_splits : Array(Package)
|
|
|
|
@context.splitter_backends.compact_map do |backend|
|
|
|
|
backend.create_split self
|
2019-07-04 23:18:54 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-07-03 03:17:01 +02:00
|
|
|
# TODO:
|
|
|
|
# - Errors management. Stop at first failure?
|
|
|
|
# - Splits. This should be done between #build and #package.
|
2019-07-20 13:30:09 +02:00
|
|
|
def package : Bool
|
|
|
|
# This tries to build them all and stops at the first failure
|
|
|
|
# (failures are currently reported by Context#package)
|
2019-07-20 13:52:24 +02:00
|
|
|
(@packages + auto_splits)
|
2019-07-20 13:30:09 +02:00
|
|
|
.find do |package|
|
|
|
|
if package.automatic && ! File.exists? package.fake_root_directory
|
|
|
|
next
|
|
|
|
end
|
|
|
|
|
|
|
|
! @context.package package
|
2019-07-04 23:18:54 +02:00
|
|
|
end
|
2019-07-20 13:30:09 +02:00
|
|
|
.== nil
|
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
|
|
|
|
|