diff --git a/scripts/build.ce b/scripts/build.ce index e6bc4b9b..85cc3984 100644 --- a/scripts/build.ce +++ b/scripts/build.ce @@ -1,6 +1,4 @@ -// cell build – Compile all .cm and .ce files to bytecode - -var io = use('cellfs') +var fd = use('fd') var js = use('js') var time = use('time') var qop = use('qop') @@ -19,10 +17,10 @@ function compile_file(src_path, dest_path, is_core) { if (is_core) { return } else { - src_content = io.slurp(src_path) + src_content = fd.slurp(src_path) } - io.mkdir(dest_path.substring(0, dest_path.lastIndexOf('/'))) + fd.mkdir(dest_path.substring(0, dest_path.lastIndexOf('/'))) var mod_name = src_path .replace(/\.(cm|ce)$/, '') @@ -32,7 +30,7 @@ function compile_file(src_path, dest_path, is_core) { var compiled = js.compile(src_path, wrapped) var blob = js.compile_blob(compiled) - io.slurpwrite(dest_path, blob) + fd.slurpwrite(dest_path, blob) compiled_count++ // log.console("Compiled " + src_path + " -> " + dest_path) } catch(e) { @@ -42,14 +40,14 @@ function compile_file(src_path, dest_path, is_core) { } // 1. Local files -var local_files = io.globfs(['**/*.cm', '**/*.ce', '!**/*.git', '!**/*.cell', '!**/subprojects'], '') +var local_files = fd.globfs(['**/*.cm', '**/*.ce', '!**/*.git', '!**/*.cell', '!**/subprojects'], '') for (var file of local_files) { var dest = build_root + '/local/' + file + '.o' compile_file(file, dest, false) } // 2. Modules -var module_files = io.globfs(['**/*.cm', '**/*.ce'], '.cell/modules') +var module_files = fd.globfs(['**/*.cm', '**/*.ce'], '.cell/modules') for (var file of module_files) { // file is relative to .cell/modules, e.g. "prosperon/draw2d.cm" var dest = build_root + '/modules/' + file + '.o' diff --git a/scripts/compile.ce b/scripts/compile.ce index b2e03a9a..e1df81a3 100644 --- a/scripts/compile.ce +++ b/scripts/compile.ce @@ -1,16 +1,13 @@ var os = use('os') -var io = use('cellfs') +var fd = use('fd') -// 2. Prepare output directory -if (!io.exists('.cell')) { - io.mkdir('.cell') -} +if (!fd.is_dir('.cell')) + fd.mkdir('.cell') var shop = use('shop') var config = shop.load_config() -// 3. Find source files -var files = io.enumerate('.', true) +var files = fd.enumerate('.', true) var objects = [] for (var i = 0; i < files.length; i++) { @@ -23,13 +20,11 @@ for (var i = 0; i < files.length; i++) { var use_name = 'js_local_' + safe_path + '_use' var obj_file = '.cell/build/' + file + '.o' - var obj_dir = io.realdir(obj_file) var last_slash = file.lastIndexOf('/') if (last_slash != -1) { var dir = '.cell/build/' + file.substring(0, last_slash) - if (!io.exists(dir)) { + if (!fd.is_dir(dir)) obj_file = '.cell/build/' + safe_path + '.o' - } } else { obj_file = '.cell/build/' + file + '.o' } @@ -37,10 +32,10 @@ for (var i = 0; i < files.length; i++) { objects.push(obj_file) var needs_compile = true - if (io.exists(obj_file)) { + if (fd.is_file(obj_file)) { try { - var src_stat = io.stat(file) - var obj_stat = io.stat(obj_file) + var src_stat = fd.stat(file) + var obj_stat = fd.stat(obj_file) if (obj_stat.modtime >= src_stat.modtime) { needs_compile = false } @@ -84,9 +79,8 @@ if (os.platform() == 'macOS') { } // Ensure .cell/local exists -if (!io.exists('.cell/local')) { - io.mkdir('.cell/local') -} +if (!fd.is_dir('.cell/local')) + fd.mkdir('.cell/local') var lib_name = '.cell/local/local' + lib_ext log.console("Linking " + lib_name) diff --git a/scripts/fd.c b/scripts/fd.c index d419db3c..2f715714 100644 --- a/scripts/fd.c +++ b/scripts/fd.c @@ -441,6 +441,94 @@ JSC_SCALL(fd_slurpwrite, return JS_NULL; ) +// Helper function for recursive enumeration +static void visit_directory(JSContext *js, JSValue results, int *result_count, const char *curr_path, const char *rel_prefix, int recurse) { + if (!curr_path) return; + +#ifdef _WIN32 + WIN32_FIND_DATA ffd; + char search_path[PATH_MAX]; + snprintf(search_path, sizeof(search_path), "%s\\*", curr_path); + HANDLE hFind = FindFirstFile(search_path, &ffd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (strcmp(ffd.cFileName, ".") == 0 || strcmp(ffd.cFileName, "..") == 0) continue; + char item_rel[PATH_MAX]; + if (rel_prefix && strlen(rel_prefix) > 0) { + snprintf(item_rel, sizeof(item_rel), "%s/%s", rel_prefix, ffd.cFileName); + } else { + strcpy(item_rel, ffd.cFileName); + } + JS_SetPropertyUint32(js, results, (*result_count)++, JS_NewString(js, item_rel)); + + if (recurse) { + struct stat st; + char child_path[PATH_MAX]; + snprintf(child_path, sizeof(child_path), "%s\\%s", curr_path, ffd.cFileName); + if (stat(child_path, &st) == 0 && S_ISDIR(st.st_mode)) { + visit_directory(js, results, result_count, child_path, item_rel, recurse); + } + } + } while (FindNextFile(hFind, &ffd) != 0); + FindClose(hFind); + } +#else + DIR *d = opendir(curr_path); + if (d) { + struct dirent *dir; + while ((dir = readdir(d)) != NULL) { + if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) continue; + char item_rel[PATH_MAX]; + if (rel_prefix && strlen(rel_prefix) > 0) { + snprintf(item_rel, sizeof(item_rel), "%s/%s", rel_prefix, dir->d_name); + } else { + strcpy(item_rel, dir->d_name); + } + JS_SetPropertyUint32(js, results, (*result_count)++, JS_NewString(js, item_rel)); + + if (recurse) { + struct stat st; + char child_path[PATH_MAX]; + snprintf(child_path, sizeof(child_path), "%s/%s", curr_path, dir->d_name); + if (stat(child_path, &st) == 0 && S_ISDIR(st.st_mode)) { + visit_directory(js, results, result_count, child_path, item_rel, recurse); + } + } + } + closedir(d); + } +#endif +} + +JSC_CCALL(fd_enumerate, + const char *path = NULL; + int recurse = 0; + + if (argc > 0 && JS_IsString(argv[0])) { + path = JS_ToCString(js, argv[0]); + } else { + path = "."; + } + + if (argc > 1) { + recurse = JS_ToBool(js, argv[1]); + } + + JSValue results = JS_NewArray(js); + int result_count = 0; + + struct stat st; + if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) { + visit_directory(js, results, &result_count, path, "", recurse); + } + + if (path != NULL && strcmp(path, ".") != 0) { + JS_FreeCString(js, path); + } + + return results; +) + static const JSCFunctionListEntry js_fd_funcs[] = { MIST_FUNC_DEF(fd, open, 2), MIST_FUNC_DEF(fd, write, 2), @@ -461,6 +549,7 @@ static const JSCFunctionListEntry js_fd_funcs[] = { MIST_FUNC_DEF(fd, readdir, 1), MIST_FUNC_DEF(fd, is_file, 1), MIST_FUNC_DEF(fd, is_dir, 1), + MIST_FUNC_DEF(fd, enumerate, 2), }; JSValue js_fd_use(JSContext *js) { diff --git a/scripts/fd.cm b/scripts/fd.cm new file mode 100644 index 00000000..f9309185 --- /dev/null +++ b/scripts/fd.cm @@ -0,0 +1,63 @@ +var fd = this +var wildstar = use('wildstar') + +// Helper to join paths +function join_paths(base, rel) { + base = base.replace(/\/+$/, "") + rel = rel.replace(/^\/+/, "") + if (!base) return rel + if (!rel) return base + return base + "/" + rel +} + +fd.globfs = function(globs, dir) { + if (dir == null) dir = "." + var results = [] + + function check_neg(path) { + for (var g of globs) { + if (g.startsWith("!") && wildstar.match(g.substring(1), path, wildstar.WM_WILDSTAR)) return true; + } + return false; + } + + function check_pos(path) { + for (var g of globs) { + if (!g.startsWith("!") && wildstar.match(g, path, wildstar.WM_WILDSTAR)) return true; + } + return false; + } + + function visit(curr_full, rel_prefix) { + if (rel_prefix && check_neg(rel_prefix)) return + + var list = fd.readdir(curr_full) + if (!list) return + + for (var item of list) { + var item_rel = rel_prefix ? rel_prefix + "/" + item : item + + var child_full = join_paths(curr_full, item) + var st = fd.stat(child_full) + + if (st.isDirectory) { + if (!check_neg(item_rel)) { + visit(child_full, item_rel) + } + } else { + if (!check_neg(item_rel) && check_pos(item_rel)) { + results.push(item_rel) + } + } + } + } + + var st = fd.stat(dir) + if (st && st.isDirectory) { + visit(dir, "") + } + + return results +} + +return fd \ No newline at end of file