Files
cell/scripts/mod.ce
2025-11-24 23:08:40 -06:00

177 lines
5.0 KiB
Plaintext

var shop = use('shop')
var http = use('http')
var miniz = use('miniz')
var fd = use('fd')
var crypto = use('crypto')
var text = use('text')
var toml = use('toml')
var time = use('time')
function slurpwrite(path, data) {
var f = fd.open(path, "w")
f.write(data)
f.close()
}
var uses = {}
uses.download = function()
{
var mods = shop.load_config().dependencies
var cache_dir = '.cell/cache'
var modules_dir = '.cell/modules'
var lock_path = '.cell/lock.toml'
// Ensure directories exist
if (!fd.stat(cache_dir).isDirectory)
fd.mkdir(cache_dir)
if (!fd.stat(modules_dir).isDirectory)
fd.mkdir(modules_dir)
// Load or create lock file
var lock = {}
if (fd.stat(lock_path).isFile) {
var lock_content = fd.slurp(lock_path)
lock = toml.decode(lock_content)
}
if (!lock.modules) lock.modules = {}
for (var mod in mods) {
var cache_path = cache_dir + '/' + mod + '.zip'
var module_path = modules_dir + '/' + mod
var zip
var need_download = false
var remote_commit = null
// Check remote commit if this is a git repository
var api_url = shop.get_api_url(mods[mod])
if (api_url) {
log.console(`${mod}: checking remote commit...`)
try {
var api_response = http.fetch(api_url)
remote_commit = shop.extract_commit_hash(mods[mod], text(api_response))
if (remote_commit) {
log.console(`${mod}: remote commit = ${remote_commit}`)
}
} catch (e) {
log.console(`${mod}: failed to check remote commit`)
}
}
// Check if module exists in lock file
if (!lock.modules[mod] || !lock.modules[mod].hash) {
log.console(`${mod}: not in lock file, will download`)
need_download = true
} else if (!fd.stat(cache_path).isDirectory) {
log.console(`${mod}: cache missing, will download`)
need_download = true
} else if (remote_commit && (!lock.modules[mod].commit || lock.modules[mod].commit != remote_commit)) {
log.console(`${mod}: remote has new commit`)
log.console(` local: ${lock.modules[mod].commit || 'unknown'}`)
log.console(` remote: ${remote_commit}`)
need_download = true
}
if (!need_download) {
// Verify cached file hash
log.console(`${mod}: verifying cached version`)
zip = fd.slurp(cache_path)
var hash = crypto.hash(zip)
var hash_b32 = text(hash, "t")
if (hash_b32 != lock.modules[mod].hash) {
log.console(`${mod}: hash mismatch, will redownload`)
log.console(` expected: ${lock.modules[mod].hash}`)
log.console(` actual: ${hash_b32}`)
need_download = true
} else {
log.console(`${mod}: hash verified`)
}
}
if (need_download) {
// Download the module
log.console(`downloading ${mod} at ${mods[mod]}`)
log.console(shop.get_download_url(mods[mod]))
zip = http.fetch(shop.get_download_url(mods[mod]))
slurpwrite(cache_path, zip)
log.console(`${mod}: downloaded ${zip.length} bytes`)
// Calculate and store hash
var hash = crypto.hash(zip)
var hash_b32 = text(hash, "t")
lock.modules[mod] = {
hash: hash_b32,
url: mods[mod],
downloaded: time.text()
}
// Store commit hash if available
if (remote_commit) {
lock.modules[mod].commit = remote_commit
}
log.console(`${mod}: hash = ${hash_b32}`)
// Save updated lock file
slurpwrite(lock_path, toml.encode(lock))
}
// Extract the module
var reader = miniz.read(zip)
var count = reader.count()
log.console(`extracting ${mod} (${count} files)...`)
// Remove existing module directory if it exists (for clean updates)
if (fd.stat(module_path).isDirectory) {
log.console(`${mod}: removing old version...`)
fd.rmdir(module_path)
}
// Create module directory
fd.mkdir(module_path)
// Extract each file
for (var i = 0; i < count; i++) {
if (reader.is_directory(i))
continue
var filename = reader.get_filename(i)
// Strip the module name prefix if present
var prefix = mod + '/'
if (filename.indexOf(prefix) == 0)
filename = filename.substring(prefix.length)
// Skip if filename is empty after stripping
if (!filename)
continue
var filepath = module_path + '/' + filename
// Create subdirectories if needed
var parts = filename.split('/')
if (parts.length > 1) {
var dir = module_path
for (var j = 0; j < parts.length - 1; j++) {
dir = dir + '/' + parts[j]
if (!fd.stat(dir).isDirectory)
fd.mkdir(dir)
}
}
// Extract and write file
var data = reader.slurp(reader.get_filename(i))
slurpwrite(filepath, data)
}
log.console(`${mod}: extracted to ${module_path}`)
}
}
if (uses[arg[0]])
uses[arg[0]]()
else
log.console(`Command ${arg[0]} not understood.`)