2025-08-01 12:52:57 +02:00
|
|
|
require 'yaml'
|
|
|
|
require 'tmpdir'
|
|
|
|
|
|
|
|
require 'system'
|
|
|
|
require 'ostruct'
|
|
|
|
require 'fileutils'
|
|
|
|
require 'open3'
|
|
|
|
|
|
|
|
# make for: the user, system, package
|
|
|
|
|
|
|
|
# as regular user, if dependencies provided
|
|
|
|
# user: $HOME/.local
|
|
|
|
# as super user
|
|
|
|
# system: /
|
|
|
|
# package: /pkg/$name/$version/
|
|
|
|
|
|
|
|
module Make
|
|
|
|
def self.rostruct(obj)
|
|
|
|
case obj
|
|
|
|
when Hash
|
|
|
|
OpenStruct.new(obj.transform_values { |v| rostruct(v) })
|
|
|
|
when Array
|
|
|
|
obj.map { |v| rostruct(v) }
|
|
|
|
else
|
|
|
|
obj
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Context
|
|
|
|
attr_accessor :name, :use_cache, :environment, :steps, :packages, :repository
|
|
|
|
attr_accessor :target
|
|
|
|
|
|
|
|
def initialize(options: OpenStruct.new)
|
|
|
|
@target = options.target || :user
|
|
|
|
|
|
|
|
@name = options.name
|
|
|
|
@use_cache = options.use_cache || false
|
|
|
|
|
2025-08-01 20:11:48 +02:00
|
|
|
#System.detect_os
|
|
|
|
# rbenv: brew install rbenv && rbenv install 3.0.0
|
|
|
|
# asdf: asdf install ruby 3.0.0
|
|
|
|
|
2025-08-01 12:52:57 +02:00
|
|
|
makefile_path = "#{ENV["DAT_ROOT"]}/recipes/#{@name}.yml"
|
2025-08-01 20:11:48 +02:00
|
|
|
unless File.file?(makefile_path)
|
|
|
|
makefile_path = "#{ENV["DAT_ROOT"]}/recipes/#{@name}/#{System.detect_os}.yml"
|
|
|
|
end
|
|
|
|
|
2025-08-01 12:52:57 +02:00
|
|
|
puts "recipe at: #{makefile_path}"
|
|
|
|
makefile = YAML.load_file(makefile_path)
|
|
|
|
|
|
|
|
# puts makefile_path
|
|
|
|
# puts makefile
|
|
|
|
|
|
|
|
@packages = makefile["packages"] || []
|
|
|
|
@repository = Make.rostruct(makefile["repository"] || OpenStruct.new)
|
|
|
|
@steps = makefile["steps"] || []
|
|
|
|
|
|
|
|
@environment = ENV.to_h.merge(
|
|
|
|
"PREFIX" => get_prefix
|
|
|
|
)
|
|
|
|
|
|
|
|
environment = makefile["environment"]
|
|
|
|
|
|
|
|
if environment != nil
|
|
|
|
@environment = environment.merge(@environment)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def get_prefix
|
|
|
|
case @target
|
|
|
|
when :user
|
|
|
|
"#{ENV["HOME"]}/.local"
|
|
|
|
when :package
|
|
|
|
"/pkg/#{@name}/#{@repository.branch}"
|
|
|
|
when :system
|
|
|
|
"/"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# Root project directory
|
|
|
|
def rpd
|
|
|
|
puts @repository
|
|
|
|
if @use_cache
|
|
|
|
path = "#{ENV["HOME"]}/.cache/dat/build/#{@name}/#{@repository.branch}"
|
|
|
|
FileUtils.mkdir_p(path)
|
|
|
|
yield path
|
|
|
|
else
|
|
|
|
Dir.mktmpdir do |tmp_path|
|
|
|
|
yield tmp_path
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def local_repo
|
|
|
|
"#{ENV["HOME"]}/.cache/dat/repo/#{@name}.git"
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_s
|
|
|
|
vars = instance_variables.map do |var|
|
|
|
|
"#{var.to_s.delete('@')}: #{instance_variable_get(var).inspect}"
|
|
|
|
end
|
|
|
|
"Context(#{vars.join(', ')})"
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
class Builder
|
|
|
|
attr_accessor :context, :cwd
|
|
|
|
|
|
|
|
def initialize(context)
|
|
|
|
@context = context
|
|
|
|
end
|
|
|
|
|
|
|
|
def execute(command)
|
|
|
|
if command.strip.start_with?("cd ")
|
|
|
|
eval_cmd = command.sub(/^cd /, 'echo ')
|
|
|
|
# new_dir = `#{eval_cmd}`.strip
|
|
|
|
new_dir, stderr, status = Open3.capture3(@context.environment, eval_cmd)
|
|
|
|
begin
|
|
|
|
puts "Dir: #{Dir.pwd}"
|
|
|
|
# new_dir = File.expand_path(new_dir)
|
|
|
|
new_dir = new_dir.strip
|
|
|
|
puts "Exists #{new_dir} => #{Dir.exist?(new_dir)}"
|
|
|
|
Dir.chdir(new_dir)
|
|
|
|
puts "Changed directory to #{Dir.pwd}"
|
|
|
|
rescue Errno::ENOENT
|
|
|
|
puts "Directory not found: #{new_dir}"
|
|
|
|
end
|
|
|
|
else
|
|
|
|
system(@context.environment, command)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def build
|
|
|
|
install
|
|
|
|
@context.rpd do | path |
|
|
|
|
@cwd = path
|
|
|
|
checkout
|
|
|
|
puts "path: #{path}"
|
|
|
|
Dir.chdir(path)
|
|
|
|
|
|
|
|
@context.steps.each do |command|
|
|
|
|
|
|
|
|
# system(env, command)
|
|
|
|
execute(command)
|
|
|
|
# need to be refreshed
|
|
|
|
# rehash # hash -r # https://chatgpt.com/c/6880b3d6-b190-8330-9623-0458254d2881
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def checkout
|
|
|
|
repo_path = @context.local_repo
|
|
|
|
repo_url = @context.repository.url
|
|
|
|
branch = @context.repository.branch
|
|
|
|
|
|
|
|
puts "Local bare git repo path: #{repo_path}"
|
|
|
|
|
|
|
|
if Dir.exist?(repo_path) && !Dir.empty?(repo_path)
|
|
|
|
puts "Bare repo exists, fetching updates..."
|
|
|
|
Dir.chdir(repo_path) do
|
|
|
|
system("git fetch origin")
|
|
|
|
end
|
|
|
|
else
|
|
|
|
puts "Cloning bare repository..."
|
|
|
|
FileUtils.mkdir_p(repo_path)
|
|
|
|
system("git clone --bare #{repo_url} #{repo_path}")
|
|
|
|
end
|
|
|
|
|
|
|
|
system("git --git-dir=#{repo_path} --work-tree=#{@cwd} checkout -f #{branch}")
|
|
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
def install
|
|
|
|
System.install(context.packages)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
# dat make -t pkg --cache --name dry-run
|
|
|
|
# dat make --name dry-run
|
|
|
|
def self.command(options)
|
|
|
|
context = Context.new(options: options)
|
|
|
|
builder = Builder.new(context)
|
|
|
|
builder.build
|
|
|
|
end
|
|
|
|
end
|