use encoding::json; use fmt; use fs; use io; use os; use os::exec; use path; use strings; type modfile = struct { dependencies: ([]dependency | void), ftype: fs::mode, ident: modident, path: str, }; type modfile_error = (fs::error | version_error); // Frees resources related to a [[modfile]]. fn modfile_free(file: *modfile) void = { free(file.path); modident_free(&file.ident); match (file.dependencies) { case let deps: []dependency => dependency_free_all(deps); case => void; }; }; // Constructs a [[modfile]] from a directory entry. The return value must be // freed with [[modfile_free]]. fn modfile_load( path: str, dirent: *fs::dirent ) (modfile | void | modfile_error) = { if (dirent.name == "." || dirent.name == ".." || dirent.name == "mod-list.json" || dirent.name == "mod-settings.dat") return void; let filepath = path::init(path, dirent.name)!; let file = modfile { dependencies = void, ftype = dirent.ftype, ident = modident_parse(dirent.name), path = strings::dup(path::string(&filepath))!, }; // Modfiles must have versions if (file.ident.1 is void) { if (!modfile_read_info(&file)) { modfile_free(&file); fmt::errorln("Unable to get info for", dirent.name)!; return void; }; }; return file; }; // Extracts and parses a modfile's info.json properties. fn modfile_read_info(mod: *modfile) bool = { // Get info.json contents const json = if (fs::isdir(mod.ftype) || fs::islink(mod.ftype)) { const info_path = path::init(mod.path, "info.json")!; let file = os::open(path::string(&info_path))!; yield json::load(file)! as json::object; } else if (fs::isfile(mod.ftype)) { const info_path = path::init(mod.ident.0, "info.json")!; // Extract info.json from zip file let cmd = exec::cmd("unzip", "-p", mod.path, path::string(&info_path))!; let pipe = exec::pipe(); exec::addfile(&cmd, os::stdout_file, pipe.1)!; let proc = exec::start(&cmd)!; io::close(pipe.1)!; let data = io::drain(pipe.0)!; defer free(data); io::close(pipe.0)!; exec::wait(&proc)!; yield json::loadstr(strings::fromutf8(data)!)! as json::object; } else { return false; }; defer json::finish(json); // Ident const name = json::get(&json, "name") as *json::value; const name = *name as str; const version = json::get(&json, "version") as *json::value; const version = version_parse(*version as str)!; modident_free(&mod.ident); mod.ident = (strings::dup(name)!, version); // Dependencies mod.dependencies = match (json::get(&json, "dependencies")) { case let deps: *json::value => const deps = *deps as []json::value; let output: []dependency = []; for (let dep &.. deps) { // TODO: Error handling const dep_str = *dep as str; append(output, dependency_parse(dep_str)!)!; }; yield output; }; return true; };