171 lines
4.9 KiB
Plaintext
171 lines
4.9 KiB
Plaintext
var shop = use('shop')
|
|
var http = use('http')
|
|
var miniz = use('miniz')
|
|
var io = use('io')
|
|
var crypto = use('crypto')
|
|
var text = use('text')
|
|
var toml = use('toml')
|
|
var time = use('time')
|
|
|
|
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 (!io.exists(cache_dir))
|
|
io.mkdir(cache_dir)
|
|
if (!io.exists(modules_dir))
|
|
io.mkdir(modules_dir)
|
|
|
|
// Load or create lock file
|
|
var lock = {}
|
|
if (io.exists(lock_path)) {
|
|
var lock_content = io.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 (!io.exists(cache_path)) {
|
|
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 = io.slurpbytes(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]))
|
|
io.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
|
|
io.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 (io.exists(module_path)) {
|
|
log.console(`${mod}: removing old version...`)
|
|
io.rmdir(module_path)
|
|
}
|
|
|
|
// Create module directory
|
|
io.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 (!io.exists(dir))
|
|
io.mkdir(dir)
|
|
}
|
|
}
|
|
|
|
// Extract and write file
|
|
var data = reader.slurp(reader.get_filename(i))
|
|
io.slurpwrite(filepath, data)
|
|
}
|
|
|
|
log.console(`${mod}: extracted to ${module_path}`)
|
|
}
|
|
}
|
|
|
|
if (uses[arg[0]])
|
|
uses[arg[0]]()
|
|
else
|
|
console.log(`Command ${arg[0]} not understood.`) |