#!/usr/bin/env lua
TOOLSHELF = os.getenv("TOOLSHELF")
--[[========================================================================]]--
--[[ Emulators ]]--
E_UAE = {
name = 'E-UAE',
source = 'http://www.rcdrummond.net/uae/e-uae-0.8.29-WIP4/e-uae-0.8.29-WIP4.tar.bz2'
}
QEMU = {
name = 'QEMU',
source = 'http://wiki.qemu-project.org/download/qemu-1.6.2.tar.bz2'
}
VICE = {
name = 'VICE',
source = 'http://downloads.sourceforge.net/project/vice-emu/releases/vice-2.4.tar.gz',
}
--[[ Emulator Modes ]]--
E_UAE_Amiga_500 = {
name = 'E-UAE/Amiga 500',
emulator = E_UAE,
start_command = 'uae -s bogomem_size=4 -s cpu_speed=max -s floppy_speed=800 -s "filesystem2=rw,DH0:Funicular:${SYSTEM_IMAGE},1"',
dist_command = 'uae -s bogomem_size=4 -s cpu_speed=max -s floppy_speed=800 -s "floppy0=${DIST_IMAGE}" -s "filesystem2=rw,DH0:Funicular:${SYSTEM_IMAGE},1"',
distboot_command = 'uae -s bogomem_size=4 -s cpu_speed=max -s floppy_speed=800 -s "floppy0=${DIST_IMAGE}"',
setup_command = 'uae -s bogomem_size=4 -s cpu_speed=max -s floppy_speed=800 -s "filesystem2=rw,DH0:Funicular:${SYSTEM_IMAGE},1" -s "floppy0=${SETUP_IMAGE}"',
install_command = 'echo "No install step. Installation will happen during setup."',
}
QEMU_i386 = {
name = 'QEMU/i386',
emulator = QEMU,
start_command = 'qemu-system-i386 -hda "${SYSTEM_IMAGE}"',
dist_command = 'qemu-system-i386 -hda "${SYSTEM_IMAGE}" -fda "${DIST_IMAGE}"',
distboot_command = 'qemu-system-i386 -fda "${DIST_IMAGE}" -boot order=a',
setup_command = 'qemu-system-i386 -hda "${SYSTEM_IMAGE}" -cdrom "${SETUP_IMAGE}"',
install_command = 'qemu-system-i386 -hda "${SYSTEM_IMAGE}" -cdrom "${INSTALL_IMAGE}" -boot order=d',
}
VICE_x64 = {
name = 'VICE/x64',
emulator = VICE,
start_command = 'x64 -config vicerc -iecdevice8 -device8 1 -fs8 ${SYSTEM_IMAGE}',
setup_command = 'x64 -config vicerc -iecdevice8 -device8 1 -fs8 ${SYSTEM_IMAGE}',
install_command = 'echo "No install step. Installation will happen during setup."',
}
VICE_xvic = {
name = 'VICE/xvic',
emulator = VICE,
start_command = 'xvic -config vicerc -iecdevice8 -device8 1 -fs8 ${SYSTEM_IMAGE}',
setup_command = 'xvic -config vicerc -iecdevice8 -device8 1 -fs8 ${SYSTEM_IMAGE}',
install_command = 'echo "No install step. Installation will happen during setup."',
}
--[[ Architectures ]]--
Amiga_500 = {
name = "Amiga 500",
emulator_mode = E_UAE_Amiga_500,
create_system_image = function(funicular, size)
execute(funicular, "mkdir -p ${SYSTEM_IMAGE}")
end,
create_dist_image = function(funicular, size)
-- TODO: this is a little restrictive
if size ~= '880' then
print "Only supported sizes: 880"
os.exit(1)
end
execute(funicular, "dd if=/dev/zero of=${DIST_IMAGE} bs=1K count=" .. size)
end
}
i386 = {
name = "i386",
emulator_mode = QEMU_i386,
create_system_image = function(funicular, size)
execute(funicular, "dd if=/dev/zero of=${SYSTEM_IMAGE} bs=1M count=" .. size)
end,
create_dist_image = function(funicular, size)
-- TODO: this is a little restrictive
if size ~= '360' and size ~= '720' and size ~= '1440' then
print "Only supported sizes: 360, 720 and 1440"
os.exit(1)
end
execute(funicular, "dd if=/dev/zero of=${DIST_IMAGE} bs=1K count=" .. size)
end
}
Commodore_64 = {
name = "Commodore 64",
emulator_mode = VICE_x64,
create_system_image = function(funicular, size)
execute(funicular, "mkdir -p ${SYSTEM_IMAGE}")
end,
create_dist_image = function(funicular, size)
execute(funicular, "dd if=/dev/zero of=${DIST_IMAGE} bs=256 count=683")
end
}
VIC_20 = {
name = "VIC 20",
emulator_mode = VICE_xvic,
create_system_image = function(funicular, size)
execute(funicular, "mkdir -p ${SYSTEM_IMAGE}")
end,
create_dist_image = function(funicular, size)
execute(funicular, "dd if=/dev/zero of=${DIST_IMAGE} bs=256 count=683")
end
}
--[[ Platforms ]]--
Commodore_64_Platform = {
name = "Commodore 64 Platform",
architecture = Commodore_64,
install_image = 'blank.d64',
setup_command = "sh ./populate.sh",
}
VIC_20_Platform = {
name = "VIC 20 Platform",
architecture = VIC_20,
install_image = 'blank.d64',
setup_command = "sh ./populate.sh",
}
AmigaDOS_1_3 = {
name = "AmigaDOS 1.3",
architecture = Amiga_500,
install_image = 'Workbench_1.3.adf',
setup_command = "sh ./populate.sh",
}
NetBSD_6 = {
name = "NetBSD 6.1.4",
architecture = i386,
install_image = 'NetBSD-6.1.4-i386.iso',
setup_command = "genisoimage -R -J -D -joliet-long -o ${SETUP_IMAGE} staging_area",
}
FreeDOS_1_1 = {
name = "FreeDOS 1.1",
architecture = i386,
install_image = 'fd11src.iso',
install_image_url = 'http://www.freedos.org/download/download/fd11src.iso',
setup_command = "genisoimage -R -J -D -joliet-long -o ${SETUP_IMAGE} staging_area",
}
--[[========================================================================]]--
dump_table = function(prefix, t)
local k, v
for k, v in pairs(t) do
if type(v) == 'table' then
dump_table(prefix .. k .. '.', v)
elseif type(v) == 'function' then
print(prefix .. k .. ' = function()')
else
print(prefix .. k .. ' = ' .. v)
end
end
end
function exists(filename)
local file = io.open(filename, "r")
if file == nil then
return false
end
io.close(file)
return true
end
function basename(filename)
return filename:match("^.+/(.-)$")
end
function execute(funicular, command)
command = command:gsub("${SETUP_IMAGE}", funicular.setup_image or '')
command = command:gsub("${SYSTEM_IMAGE}", funicular.system_image or '')
command = command:gsub("${INSTALL_IMAGE}", funicular.install_image or
funicular.platform.install_image or '')
command = command:gsub("${DIST_IMAGE}", funicular.dist_image or '')
print(command)
local exit_code = os.execute(command)
if exit_code ~= 0 then
os.exit(1)
end
end
function fetch_distfile(funicular, url)
filename = 'distfiles/' .. basename(url)
if not exists(filename) then
execute(funicular, 'wget ' .. url .. ' -O ' .. filename)
end
end
function is_docked(funicular, url)
local command = 'toolshelf.py resolve ' .. url
print(command)
local exit_code = os.execute(command)
return (exit_code == 0)
end
function checkout_hg_repo(funicular, url)
filename = 'distrepos/' .. basename(url)
if not exists(filename) then
if TOOLSHELF ~= nil then
if not is_docked(funicular, url) then
execute(funicular, 'toolshelf.py tether ' .. url)
end
th = '`toolshelf.py resolve ' .. url .. '`'
execute(funicular, 'hg clone ' .. th .. ' ' .. filename)
else
execute(funicular, 'hg clone ' .. url .. ' ' .. filename)
end
else
if TOOLSHELF ~= nil then
execute(funicular, 'cd ' .. filename .. ' && hg pull -u')
end
end
end
function checkout_git_repo(funicular, url)
filename = 'distrepos/' .. basename(url)
if not exists(filename) then
execute(funicular, 'git clone ' .. url .. ' ' .. filename)
end
end
commands = {
dump = function(funicular, arg)
dump_table('', funicular)
end,
init = function(funicular, arg)
size = arg[2]
if size == nil then
print "Usage: funicular init <size-in-megabytes>"
os.exit(1)
end
if exists(funicular.system_image) then
print(funicular.system_image .. " already exists! Delete it first.")
return
end
print("init... size: " .. size)
funicular.platform.architecture.create_system_image(funicular, size)
end,
initdist = function(funicular, arg)
size = arg[2]
if size == nil then
print "Usage: funicular initdist <size-in-kilobytes>"
os.exit(1)
end
if exists(funicular.dist_image) then
print(funicular.dist_image .. " already exists! Delete it first.")
return
end
print("initdist... size: " .. size)
funicular.platform.architecture.create_dist_image(funicular, size)
end,
install = function(funicular, arg)
print("installing " .. funicular.platform.name .. " onto system image...")
if funicular.install_instructions then
print [[
=========================
INSTALLATION INSTRUCTIONS
=========================
]]
print(funicular.install_instructions)
end
execute(funicular, funicular.platform.architecture.emulator_mode.install_command)
end,
setup = function(funicular, arg)
print("creating setup image for " .. funicular.platform.name .. "...")
execute(funicular, 'mkdir -p distfiles')
for url in string.gmatch(funicular.distfiles or "", "[^%s]+") do
fetch_distfile(funicular, url)
end
execute(funicular, 'mkdir -p distrepos')
for url in string.gmatch(funicular.distrepos_hg or "", "[^%s]+") do
checkout_hg_repo(funicular, url)
end
for url in string.gmatch(funicular.distrepos_git or "", "[^%s]+") do
checkout_git_repo(funicular, url)
end
execute(funicular, 'rm -rf staging_area')
execute(funicular, 'mkdir -p staging_area')
for url in string.gmatch(funicular.distfiles or "", "[^%s]+") do
local source_name = basename(url)
local dest_name = source_name
if funicular.name_map and funicular.name_map[source_name] then
dest_name = funicular.name_map[source_name]
end
execute(funicular, 'cp -p distfiles/' .. source_name .. ' staging_area/' .. dest_name)
end
for url in string.gmatch(funicular.distrepos_hg or "", "[^%s]+") do
if funicular.toolshelf_inside then
execute(funicular, 'cd distrepos && tar zcf ../staging_area/bitbucket.org,catseye,' ..
basename(url) .. '-master.tar.gz ' .. basename(url))
else
local source_name = basename(url)
local dest_name = source_name
if funicular.name_map and funicular.name_map[source_name] then
dest_name = funicular.name_map[source_name]
end
execute(funicular, 'cd distrepos && tar zcf ../staging_area/' ..
dest_name .. '.tgz ' .. source_name)
end
end
for url in string.gmatch(funicular.distrepos_git or "", "[^%s]+") do
if funicular.toolshelf_inside then
execute(funicular, 'cd distrepos && tar zcf ../staging_area/github.com,catseye,' ..
basename(url) .. '-master.tar.gz ' .. basename(url))
else
execute(funicular, 'cd distrepos && tar zcf ../staging_area/' ..
basename(url) .. '.tgz ' .. basename(url))
end
end
if exists('skel') then
execute(funicular, 'cp -Rp skel/* staging_area/')
-- execute(funicular, 'chmod 755 staging_area/*.sh')
end
execute(funicular, funicular.platform.setup_command or 'echo "no platform setup command"')
if funicular.setup_instructions then
print [[
==================
SETUP INSTRUCTIONS
==================
]]
print(funicular.setup_instructions)
end
execute(funicular, funicular.platform.architecture.emulator_mode.setup_command)
end,
start = function(funicular, arg)
print("starting " .. funicular.platform.architecture.emulator_mode.emulator.name .. "...")
if funicular.dist_image and exists(funicular.dist_image) then
if funicular.dist_instructions then
print [[
=========================
DISTRIBUTION INSTRUCTIONS
=========================
]]
print(funicular.dist_instructions)
end
execute(funicular, funicular.platform.architecture.emulator_mode.dist_command)
else
execute(funicular, funicular.platform.architecture.emulator_mode.start_command)
end
end,
distboot = function(funicular, arg)
if not funicular.dist_image or not exists(funicular.dist_image) then
print "No distribution image defined or created."
return
end
print("distbooting " .. funicular.platform.architecture.emulator_mode.emulator.name .. "...")
execute(funicular, funicular.platform.architecture.emulator_mode.distboot_command)
end,
backup = function(funicular, arg)
bup = arg[2]
if bup == nil then
print "Usage: funicular backup <backup-basename>"
os.exit(1)
end
bup_img_gz = bup .. '.img.gz'
if exists(bup_img_gz) then
print(bup_img_gz .. ' already exists! Delete it or pick a different name.')
os.exit(1)
end
-- special case is special
if funicular.system_image == 'dh0' then
bup_img_gz = bup .. '.tar.gz'
execute(funicular, "tar zcf " .. bup_img_gz .. " ${SYSTEM_IMAGE}")
else
execute(funicular, "ls -lah ${SYSTEM_IMAGE}")
execute(funicular, "cp ${SYSTEM_IMAGE} " .. bup .. ".img")
execute(funicular, "gzip " .. bup .. ".img")
end
execute(funicular, "ls -lah " .. bup_img_gz)
end,
restore = function(funicular, arg)
local force = false
bup = arg[2]
if bup == '-f' then
force = true
bup = arg[3]
end
if bup == nil then
print "Usage: funicular restore [-f] <backup-basename>"
os.exit(1)
end
bup = bup:gsub("^(.-)\.img\.gz$", "%1")
bup_img_gz = bup .. '.img.gz'
-- special case is special
if funicular.system_image == 'dh0' then
bup_img_gz = bup .. '.tar.gz'
end
if not exists(bup_img_gz) then
print(bup_img_gz .. ' does not exist.')
os.exit(1)
end
if force then
execute(funicular, "rm -rf ${SYSTEM_IMAGE}")
end
if exists(funicular.system_image) then
print(funicular.system_image .. ' still exists, please delete it first.')
os.exit(1)
end
-- special case is special
if funicular.system_image == 'dh0' then
execute(funicular, "tar zxf " .. bup_img_gz)
else
execute(funicular, "ls -lah " .. bup_img_gz)
execute(funicular, "cp " .. bup_img_gz .. " ${SYSTEM_IMAGE}.gz")
execute(funicular, "gunzip ${SYSTEM_IMAGE}.gz")
end
end,
}
--[[-- MAIN --]]--
local command = arg[1]
if command == nil or commands[command] == nil then
print [[Usage: funicular <command>
where <command> is one of:
init
install
setup
start
initdist
distboot
backup
restore]]
os.exit(1)
end
local result, error = loadfile("Funicularfile")
if result == nil then
print("No valid Funicularfile found in this directory.")
os.exit(1)
end
local funicular = result()
command = commands[command]
command(funicular, arg)