fix blob
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
sdl_video = "main"
|
sdl_video = "main"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
extramath = "https://gitea.pockle.world/john/extramath@master"
|
extramath = "gitea.pockle.world/john/extramath@master"
|
||||||
[system]
|
[system]
|
||||||
ar_timer = 60
|
ar_timer = 60
|
||||||
actor_memory = 0
|
actor_memory = 0
|
||||||
@@ -16,4 +16,4 @@ main = true
|
|||||||
[actors.prosperon]
|
[actors.prosperon]
|
||||||
main = true
|
main = true
|
||||||
[actors.accio]
|
[actors.accio]
|
||||||
main=true
|
main = true
|
||||||
2
Makefile
2
Makefile
@@ -11,7 +11,7 @@ release: FORCE
|
|||||||
meson install -C build_release
|
meson install -C build_release
|
||||||
|
|
||||||
sanitize: FORCE
|
sanitize: FORCE
|
||||||
meson setup -Db_sanitize=address -Db_sanitize=memory -Db_sanitize=leak -Db_sanitize=undefined build_sani
|
meson setup -Db_sanitize=address -Db_sanitize=memory -Db_sanitize=leak build_sani
|
||||||
meson install -C build_sani
|
meson install -C build_sani
|
||||||
|
|
||||||
thread: FORCE
|
thread: FORCE
|
||||||
|
|||||||
27
scripts/fd.c
27
scripts/fd.c
@@ -223,10 +223,36 @@ JSC_SCALL(fd_mv,
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
JSC_SCALL(fd_symlink,
|
||||||
|
if (argc < 2)
|
||||||
|
ret = JS_ThrowTypeError(js, "fd.symlink requires 2 arguments: target and link path");
|
||||||
|
else if (!JS_IsString(argv[1]))
|
||||||
|
ret = JS_ThrowTypeError(js, "second argument must be a string (link path)");
|
||||||
|
else {
|
||||||
|
const char *link_path = JS_ToCString(js, argv[1]);
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (!CreateSymbolicLinkA(link_path, str, SYMBOLIC_LINK_FLAG_DIRECTORY)) {
|
||||||
|
// Try file
|
||||||
|
if (!CreateSymbolicLinkA(link_path, str, 0)) {
|
||||||
|
ret = JS_ThrowInternalError(js, "could not create symlink %s -> %s: %lu", link_path, str, GetLastError());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (symlink(str, link_path) != 0)
|
||||||
|
ret = JS_ThrowInternalError(js, "could not create symlink %s -> %s: %s", link_path, str, strerror(errno));
|
||||||
|
#endif
|
||||||
|
JS_FreeCString(js, link_path);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
// Helper function for recursive removal
|
// Helper function for recursive removal
|
||||||
static int remove_recursive(const char *path) {
|
static int remove_recursive(const char *path) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
#ifdef _WIN32
|
||||||
if (stat(path, &st) != 0)
|
if (stat(path, &st) != 0)
|
||||||
|
#else
|
||||||
|
if (lstat(path, &st) != 0)
|
||||||
|
#endif
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
if (S_ISDIR(st.st_mode)) {
|
if (S_ISDIR(st.st_mode)) {
|
||||||
@@ -565,6 +591,7 @@ static const JSCFunctionListEntry js_fd_funcs[] = {
|
|||||||
MIST_FUNC_DEF(fd, is_file, 1),
|
MIST_FUNC_DEF(fd, is_file, 1),
|
||||||
MIST_FUNC_DEF(fd, is_dir, 1),
|
MIST_FUNC_DEF(fd, is_dir, 1),
|
||||||
MIST_FUNC_DEF(fd, enumerate, 2),
|
MIST_FUNC_DEF(fd, enumerate, 2),
|
||||||
|
MIST_FUNC_DEF(fd, symlink, 2),
|
||||||
};
|
};
|
||||||
|
|
||||||
JSValue js_fd_use(JSContext *js) {
|
JSValue js_fd_use(JSContext *js) {
|
||||||
|
|||||||
58
scripts/os.c
58
scripts/os.c
@@ -383,6 +383,7 @@ static JSValue js_os_dylib_symbol(JSContext *js, JSValue self, int argc, JSValue
|
|||||||
error_msg = dl_error;
|
error_msg = dl_error;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
return JS_ThrowReferenceError(js, "Failed to load symbol: %s", error_msg);
|
||||||
return JS_NULL;
|
return JS_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -390,6 +391,34 @@ static JSValue js_os_dylib_symbol(JSContext *js, JSValue self, int argc, JSValue
|
|||||||
return symbol(js);
|
return symbol(js);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue js_os_dylib_has_symbol(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||||
|
{
|
||||||
|
if (argc < 2) {
|
||||||
|
return JS_ThrowTypeError(js, "dylib_has_symbol requires dylib object and symbol name");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *handle = JS_GetOpaque(argv[0], js_dylib_class_id);
|
||||||
|
if (!handle) {
|
||||||
|
return JS_ThrowTypeError(js, "First argument must be a dylib object");
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *symbol_name = JS_ToCString(js, argv[1]);
|
||||||
|
if (!symbol_name) {
|
||||||
|
return JS_ThrowTypeError(js, "symbol name must be a string");
|
||||||
|
}
|
||||||
|
|
||||||
|
void *symbol;
|
||||||
|
#ifdef _WIN32
|
||||||
|
symbol = (void*)GetProcAddress((HMODULE)handle, symbol_name);
|
||||||
|
#else
|
||||||
|
symbol = dlsym(handle, symbol_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JS_FreeCString(js, symbol_name);
|
||||||
|
|
||||||
|
return JS_NewBool(js, symbol != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
JSC_CCALL(os_print,
|
JSC_CCALL(os_print,
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *str = JS_ToCStringLen(js, &len, argv[0]);
|
const char *str = JS_ToCStringLen(js, &len, argv[0]);
|
||||||
@@ -427,6 +456,33 @@ static JSValue js_os_load_internal(JSContext *js, JSValue self, int argc, JSValu
|
|||||||
return symbol(js);
|
return symbol(js);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static JSValue js_os_internal_exists(JSContext *js, JSValue self, int argc, JSValue *argv)
|
||||||
|
{
|
||||||
|
void *handle;
|
||||||
|
#ifdef _WIN32
|
||||||
|
handle = GetModuleHandle(NULL);
|
||||||
|
#else
|
||||||
|
handle = dlopen(NULL, RTLD_LAZY);
|
||||||
|
#endif
|
||||||
|
if (argc < 1)
|
||||||
|
return JS_ThrowTypeError(js, "internal_exists requires a symbol name");
|
||||||
|
|
||||||
|
const char *symbol_name = JS_ToCString(js, argv[0]);
|
||||||
|
if (!symbol_name)
|
||||||
|
return JS_ThrowTypeError(js, "symbol name must be a string");
|
||||||
|
|
||||||
|
void *symbol;
|
||||||
|
#if defined(_WIN32)
|
||||||
|
symbol = (void*)GetProcAddress((HMODULE)handle, symbol_name);
|
||||||
|
#else
|
||||||
|
symbol = dlsym(handle, symbol_name);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JS_FreeCString(js, symbol_name);
|
||||||
|
|
||||||
|
return JS_NewBool(js, symbol != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// ------- Windows: use BCryptGenRandom -------
|
// ------- Windows: use BCryptGenRandom -------
|
||||||
int randombytes(void *buf, size_t n) {
|
int randombytes(void *buf, size_t n) {
|
||||||
@@ -494,7 +550,9 @@ static const JSCFunctionListEntry js_os_funcs[] = {
|
|||||||
MIST_FUNC_DEF(os, sleep, 1),
|
MIST_FUNC_DEF(os, sleep, 1),
|
||||||
MIST_FUNC_DEF(os, dylib_open, 1),
|
MIST_FUNC_DEF(os, dylib_open, 1),
|
||||||
MIST_FUNC_DEF(os, dylib_symbol, 2),
|
MIST_FUNC_DEF(os, dylib_symbol, 2),
|
||||||
|
MIST_FUNC_DEF(os, dylib_has_symbol, 2),
|
||||||
MIST_FUNC_DEF(os, load_internal, 1),
|
MIST_FUNC_DEF(os, load_internal, 1),
|
||||||
|
MIST_FUNC_DEF(os, internal_exists, 1),
|
||||||
MIST_FUNC_DEF(os, print, 1),
|
MIST_FUNC_DEF(os, print, 1),
|
||||||
MIST_FUNC_DEF(os, random, 0),
|
MIST_FUNC_DEF(os, random, 0),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,49 +1,29 @@
|
|||||||
// cell replace <alias> <path> - Add or update a replace directive for a dependency
|
// cell replace [package] [path]
|
||||||
|
// replace a package with a local directory
|
||||||
|
|
||||||
var fd = use('fd')
|
|
||||||
var shop = use('shop')
|
var shop = use('shop')
|
||||||
|
|
||||||
if (args.length < 2) {
|
if (args.length < 2) {
|
||||||
log.console("Usage: cell replace <alias> <path>")
|
log.console("Usage: cell replace <package> <path>")
|
||||||
log.console("Examples:")
|
log.console(" cell replace <package> --remove")
|
||||||
log.console(" cell replace prosperon ../prosperon")
|
$_.stop()
|
||||||
log.console(" cell replace extramath ../my-fork-of-extramath")
|
|
||||||
$_.stop()
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var alias = args[0]
|
var pkg = args[0]
|
||||||
var path = args[1]
|
var path = args[1]
|
||||||
|
|
||||||
// Initialize shop if needed
|
if (path == '--remove') {
|
||||||
if (!fd.stat('.cell/cell.toml').isFile) {
|
if (shop.remove_replacement(pkg)) {
|
||||||
log.console("No cell.toml found. Initializing...")
|
log.console("Replacement removed.")
|
||||||
shop.init()
|
} else {
|
||||||
|
log.console("Failed to remove replacement.")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (shop.add_replacement(pkg, path)) {
|
||||||
|
log.console("Replacement added.")
|
||||||
|
} else {
|
||||||
|
log.console("Failed to add replacement.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load current config
|
$_.stop()
|
||||||
var config = shop.load_config()
|
|
||||||
if (!config) {
|
|
||||||
log.error("Failed to load cell.toml")
|
|
||||||
$_.stop()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the alias exists in dependencies
|
|
||||||
if (!config.dependencies || !config.dependencies[alias]) {
|
|
||||||
log.console("Warning: '" + alias + "' is not in dependencies. Adding replace anyway.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure replace section exists
|
|
||||||
if (!config.replace) {
|
|
||||||
config.replace = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add or update the replace directive
|
|
||||||
config.replace[alias] = path
|
|
||||||
shop.save_config(config)
|
|
||||||
|
|
||||||
log.console("Added replace directive: " + alias + " = " + path)
|
|
||||||
log.console("Run 'cell build' to apply changes")
|
|
||||||
|
|
||||||
$_.stop()
|
|
||||||
253
scripts/shop.cm
253
scripts/shop.cm
@@ -348,11 +348,6 @@ Shop.get_module_dir = function(alias) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if replaced
|
|
||||||
if (config.replace && config.replace[alias]) {
|
|
||||||
return config.replace[alias]
|
|
||||||
}
|
|
||||||
|
|
||||||
var pkg = config.dependencies[alias]
|
var pkg = config.dependencies[alias]
|
||||||
var parsed = Shop.parse_package(pkg)
|
var parsed = Shop.parse_package(pkg)
|
||||||
if (!parsed) return null
|
if (!parsed) return null
|
||||||
@@ -568,19 +563,19 @@ function resolve_locator(path, ext, ctx)
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resolve_c_symbol(path, package_ctx)
|
function resolve_c_symbol(path, package_context)
|
||||||
{
|
{
|
||||||
var local_path = package_ctx ? package_ctx : 'local'
|
var local_path = package_context ? package_context : 'local'
|
||||||
var local_sym_base = path.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_')
|
var local_sym_base = path.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_')
|
||||||
var local
|
var local
|
||||||
|
|
||||||
if (!package_ctx) {
|
if (!package_context) {
|
||||||
local = `js_local_${local_sym_base}_use`
|
local = `js_local_${local_sym_base}_use`
|
||||||
} else {
|
} else {
|
||||||
local = `js_${local_path.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_')}_${local_sym_base}_use`
|
local = `js_${local_path.replace(/\//g, '_').replace(/-/g, '_').replace(/\./g, '_')}_${local_sym_base}_use`
|
||||||
}
|
}
|
||||||
|
|
||||||
var build_dir = get_build_dir(package_ctx)
|
var build_dir = get_build_dir(package_context)
|
||||||
var local_dl_name = build_dir + '/cellmod' + dylib_ext
|
var local_dl_name = build_dir + '/cellmod' + dylib_ext
|
||||||
|
|
||||||
if (fd.is_file(local_dl_name)) {
|
if (fd.is_file(local_dl_name)) {
|
||||||
@@ -588,19 +583,25 @@ function resolve_c_symbol(path, package_ctx)
|
|||||||
open_dls[local_dl_name] = os.dylib_open(local_dl_name);
|
open_dls[local_dl_name] = os.dylib_open(local_dl_name);
|
||||||
|
|
||||||
if (open_dls[local_dl_name]) {
|
if (open_dls[local_dl_name]) {
|
||||||
var local_addr = os.dylib_symbol(open_dls[local_dl_name], local);
|
if (os.dylib_has_symbol(open_dls[local_dl_name], local))
|
||||||
if (local_addr) return {symbol: local_addr, scope: SCOPE_LOCAL};
|
return {
|
||||||
|
symbol: function() { return os.dylib_symbol(open_dls[local_dl_name], local); },
|
||||||
|
scope: SCOPE_LOCAL
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try static linking fallback
|
// Try static linking fallback
|
||||||
var static_local_addr = os.load_internal(local);
|
if (os.internal_exists(local))
|
||||||
if (static_local_addr) return {symbol: static_local_addr, scope: SCOPE_LOCAL};
|
return {
|
||||||
|
symbol: function() { return os.load_internal(local); },
|
||||||
|
scope: SCOPE_LOCAL
|
||||||
|
};
|
||||||
|
|
||||||
// If 'path' has a package alias (e.g. 'prosperon/sprite'), try to resolve it
|
// If 'path' has a package alias (e.g. 'prosperon/sprite'), try to resolve it
|
||||||
var pkg_alias = get_import_package(path)
|
var pkg_alias = get_import_package(path)
|
||||||
if (pkg_alias) {
|
if (pkg_alias) {
|
||||||
var canon_pkg = get_normalized_package(path, package_ctx)
|
var canon_pkg = get_normalized_package(path, package_context)
|
||||||
if (canon_pkg) {
|
if (canon_pkg) {
|
||||||
var build_dir = get_build_dir(canon_pkg)
|
var build_dir = get_build_dir(canon_pkg)
|
||||||
var dl_path = build_dir + '/cellmod' + dylib_ext
|
var dl_path = build_dir + '/cellmod' + dylib_ext
|
||||||
@@ -613,20 +614,30 @@ function resolve_c_symbol(path, package_ctx)
|
|||||||
if (fd.is_file(dl_path)) {
|
if (fd.is_file(dl_path)) {
|
||||||
if (!open_dls[dl_path]) open_dls[dl_path] = os.dylib_open(dl_path)
|
if (!open_dls[dl_path]) open_dls[dl_path] = os.dylib_open(dl_path)
|
||||||
if (open_dls[dl_path]) {
|
if (open_dls[dl_path]) {
|
||||||
var addr = os.dylib_symbol(open_dls[dl_path], sym_name)
|
if (os.dylib_has_symbol(open_dls[dl_path], sym_name))
|
||||||
if (addr) return {symbol: addr, scope: SCOPE_PACKAGE, package: canon_pkg}
|
return {
|
||||||
|
symbol: function() { return os.dylib_symbol(open_dls[dl_path], sym_name) },
|
||||||
|
scope: SCOPE_PACKAGE,
|
||||||
|
package: canon_pkg
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var static_package_addr = os.load_internal(sym_name);
|
if (os.internal_exists(sym_name))
|
||||||
if (static_package_addr)
|
return {
|
||||||
return {symbol:static_package_addr, scope: SCOPE_PACKAGE, package: canon_pkg};
|
symbol: function() { return os.load_internal(sym_name) },
|
||||||
|
scope: SCOPE_PACKAGE,
|
||||||
|
package: canon_pkg
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var core_addr = os.load_internal(`js_${path.replace(/\//g, '_')}_use`);
|
var core_sym = `js_${path.replace(/\//g, '_')}_use`;
|
||||||
if (core_addr)
|
if (os.internal_exists(core_sym))
|
||||||
return {symbol:core_addr, scope: SCOPE_CORE};
|
return {
|
||||||
|
symbol: function() { return os.load_internal(core_sym); },
|
||||||
|
scope: SCOPE_CORE
|
||||||
|
};
|
||||||
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
@@ -650,11 +661,11 @@ Shop.use = function(path, package_context) {
|
|||||||
return use_cache[cache_key]
|
return use_cache[cache_key]
|
||||||
|
|
||||||
if (c_resolve.scope < mod_resolve.scope)
|
if (c_resolve.scope < mod_resolve.scope)
|
||||||
use_cache[cache_key] = c_resolve.symbol
|
use_cache[cache_key] = c_resolve.symbol()
|
||||||
else if (mod_resolve.scope < c_resolve.scope)
|
else if (mod_resolve.scope < c_resolve.scope)
|
||||||
use_cache[cache_key] = mod_resolve.symbol.call()
|
use_cache[cache_key] = mod_resolve.symbol.call()
|
||||||
else
|
else
|
||||||
use_cache[cache_key] = mod_resolve.symbol.call(c_resolve.symbol)
|
use_cache[cache_key] = mod_resolve.symbol.call(c_resolve.symbol())
|
||||||
|
|
||||||
return use_cache[cache_key]
|
return use_cache[cache_key]
|
||||||
}
|
}
|
||||||
@@ -671,23 +682,11 @@ function get_cache_path(pkg, commit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function rm_recursive(path) {
|
function rm_recursive(path) {
|
||||||
var st = fd.stat(path)
|
try {
|
||||||
if (!st) return
|
fd.rm(path)
|
||||||
|
} catch (e) {
|
||||||
if (!st.isDirectory) {
|
log.error("Failed to remove " + path + ": " + e)
|
||||||
fd.unlink(path)
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var list = fd.readdir(path)
|
|
||||||
if (list) {
|
|
||||||
for (var i = 0; i < list.length; i++) {
|
|
||||||
var item = list[i]
|
|
||||||
if (item == '.' || item == '..') continue
|
|
||||||
rm_recursive(path + "/" + item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fd.rmdir(path)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_all_files(dir, prefix, results) {
|
function get_all_files(dir, prefix, results) {
|
||||||
@@ -745,9 +744,8 @@ function verify_zip_contents(zip, target_dir) {
|
|||||||
|
|
||||||
// Check for extra files
|
// Check for extra files
|
||||||
var existing_files = get_all_files(target_dir)
|
var existing_files = get_all_files(target_dir)
|
||||||
for (var i = 0; i < existing_files.length; i++) {
|
for (var i = 0; i < existing_files.length; i++)
|
||||||
if (!expected_files[existing_files[i]]) return false
|
if (!expected_files[existing_files[i]]) return false
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -944,100 +942,76 @@ Shop.get = function(pkg, alias) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
// High-level: Update a specific package or all packages
|
Shop.fetch = function(package)
|
||||||
// Like `bun update` or `bun update <pkg>`
|
{
|
||||||
Shop.update_all = function(alias) {
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// High-level: Update a specific package
|
||||||
|
// Like `bun update <pkg>`
|
||||||
|
Shop.update = function(pkg) {
|
||||||
var config = Shop.load_config()
|
var config = Shop.load_config()
|
||||||
if (!config || !config.dependencies) {
|
|
||||||
log.console("No dependencies to update.")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var lock = Shop.load_lock()
|
var lock = Shop.load_lock()
|
||||||
var queue = []
|
|
||||||
var processed = {}
|
|
||||||
|
|
||||||
// Initialize queue
|
// Check if replaced
|
||||||
if (alias) {
|
if (config.replace && config.replace[pkg]) {
|
||||||
if (config.dependencies[alias]) {
|
log.console("Skipping update for replaced package " + pkg)
|
||||||
queue.push(config.dependencies[alias])
|
Shop.update(config.replace[pkg])
|
||||||
} else {
|
return false
|
||||||
log.error("Dependency not found: " + alias)
|
}
|
||||||
return
|
|
||||||
|
// Find existing lock info
|
||||||
|
var lock_info = lock[pkg]
|
||||||
|
var local_hash = lock_info ? lock_info.commit : null
|
||||||
|
|
||||||
|
var api_url = Shop.get_api_url(pkg)
|
||||||
|
var remote_hash = null
|
||||||
|
|
||||||
|
// Check for updates if possible
|
||||||
|
if (api_url) {
|
||||||
|
try {
|
||||||
|
var resp = http.fetch(api_url)
|
||||||
|
remote_hash = Shop.extract_commit_hash(pkg, text(resp))
|
||||||
|
} catch (e) {
|
||||||
|
log.console("Warning: Could not check for updates for " + pkg)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var target_hash = remote_hash
|
||||||
|
if (!target_hash) {
|
||||||
|
log.error("Could not resolve remote commit for " + pkg)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_hash && remote_hash == local_hash) {
|
||||||
|
log.console(alias + " is already up to date.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (local_hash) {
|
||||||
|
log.console("Updating " + alias + " " + local_hash.substring(0,8) + " -> " + remote_hash.substring(0,8))
|
||||||
} else {
|
} else {
|
||||||
for (var k in config.dependencies) {
|
log.console("Installing " + alias + "...")
|
||||||
queue.push(config.dependencies[k])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (queue.length > 0) {
|
// Install with fresh download (no zip hash to force redownload)
|
||||||
var pkg = queue.shift()
|
var result = install_from_package(pkg, target_hash, null)
|
||||||
if (processed[pkg]) continue
|
|
||||||
processed[pkg] = true
|
if (result) {
|
||||||
|
// Update lock
|
||||||
// Find existing lock info
|
lock[pkg] = {
|
||||||
var lock_info = lock[pkg]
|
package: pkg,
|
||||||
var local_hash = lock_info ? lock_info.commit : null
|
commit: result.commit,
|
||||||
var local_zip_hash = lock_info ? lock_info.zip_hash : null
|
zip_hash: result.zip_hash,
|
||||||
|
updated: time.number()
|
||||||
var api_url = Shop.get_api_url(pkg)
|
|
||||||
var remote_hash = null
|
|
||||||
|
|
||||||
// Check for updates if possible
|
|
||||||
if (api_url) {
|
|
||||||
try {
|
|
||||||
var resp = http.fetch(api_url)
|
|
||||||
remote_hash = Shop.extract_commit_hash(pkg, text(resp))
|
|
||||||
} catch (e) {
|
|
||||||
log.console("Warning: Could not check for updates for " + pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var target_hash = remote_hash || local_hash
|
|
||||||
if (!target_hash) {
|
|
||||||
log.error("Could not resolve commit for " + pkg)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
var is_update = remote_hash && local_hash && (remote_hash != local_hash)
|
|
||||||
if (is_update) {
|
|
||||||
log.console("Updating " + pkg + " " + local_hash.substring(0,8) + " -> " + remote_hash.substring(0,8))
|
|
||||||
} else {
|
|
||||||
log.console("Checking " + pkg + "...")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install/Verify
|
|
||||||
// If updating, we pass null as local_zip_hash to force fresh download/check
|
|
||||||
// If verifying, we pass local_zip_hash
|
|
||||||
var result = install_from_package(pkg, target_hash, is_update ? null : local_zip_hash)
|
|
||||||
|
|
||||||
if (result) {
|
|
||||||
// Update lock
|
|
||||||
lock[pkg] = {
|
|
||||||
package: pkg,
|
|
||||||
commit: result.commit,
|
|
||||||
zip_hash: result.zip_hash,
|
|
||||||
updated: time.number()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read package config to find dependencies
|
|
||||||
var parsed = Shop.parse_package(pkg)
|
|
||||||
var pkg_config = Shop.load_config(parsed.path)
|
|
||||||
|
|
||||||
if (pkg_config && pkg_config.dependencies) {
|
|
||||||
for (var k in pkg_config.dependencies) {
|
|
||||||
var dep_pkg = pkg_config.dependencies[k]
|
|
||||||
if (!processed[dep_pkg]) {
|
|
||||||
queue.push(dep_pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Shop.save_lock(lock)
|
||||||
|
log.console("Updated " + alias + ".")
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
Shop.save_lock(lock)
|
log.error("Failed to update " + alias)
|
||||||
log.console("Update complete.")
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// High-level: Remove a package and clean up
|
// High-level: Remove a package and clean up
|
||||||
@@ -1077,6 +1051,33 @@ Shop.remove = function(alias) {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Shop.add_replacement = function(alias, replacement) {
|
||||||
|
var config = Shop.load_config()
|
||||||
|
if (!config) config = {}
|
||||||
|
if (!config.replace) config.replace = {}
|
||||||
|
|
||||||
|
config.replace[alias] = replacement
|
||||||
|
Shop.save_config(config)
|
||||||
|
|
||||||
|
log.console("Added replacement: " + alias + " = " + replacement)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
Shop.remove_replacement = function(alias) {
|
||||||
|
var config = Shop.load_config()
|
||||||
|
if (!config || !config.replace || !config.replace[alias]) {
|
||||||
|
log.error("No replacement found for " + alias)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
delete config.replace[alias]
|
||||||
|
Shop.save_config(config)
|
||||||
|
|
||||||
|
log.console("Removed replacement for " + alias)
|
||||||
|
log.console("Run 'cell update " + alias + "' to restore the package.")
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Install all dependencies from config (like `bun install`)
|
// Install all dependencies from config (like `bun install`)
|
||||||
Shop.install_all = function() {
|
Shop.install_all = function() {
|
||||||
Shop.init()
|
Shop.init()
|
||||||
|
|||||||
@@ -4,14 +4,14 @@ var shop = use('shop')
|
|||||||
|
|
||||||
var alias = args.length > 0 ? args[0] : null
|
var alias = args.length > 0 ? args[0] : null
|
||||||
|
|
||||||
log.console("Checking for updates...")
|
|
||||||
shop.update_all(alias)
|
|
||||||
|
|
||||||
var packages = shop.list_packages()
|
var packages = shop.list_packages()
|
||||||
|
|
||||||
log.console(packages)
|
log.console("Checking for updates...")
|
||||||
|
|
||||||
for (var pack of packages)
|
for (var pack of packages) {
|
||||||
|
log.console("Updating " + pack)
|
||||||
|
shop.update(pack)
|
||||||
shop.build_package(pack)
|
shop.build_package(pack)
|
||||||
|
}
|
||||||
|
|
||||||
$_.stop()
|
$_.stop()
|
||||||
@@ -221,7 +221,6 @@ static int blob_copy_bits(blob *dest, const void *src, size_t from, size_t to) {
|
|||||||
blob *blob_new(size_t capacity) {
|
blob *blob_new(size_t capacity) {
|
||||||
if (capacity < 0) capacity = 0;
|
if (capacity < 0) capacity = 0;
|
||||||
blob *b = calloc(1, sizeof(blob));
|
blob *b = calloc(1, sizeof(blob));
|
||||||
printf("allocating blob %p size %zu\n", b, capacity);
|
|
||||||
if (!b) return NULL;
|
if (!b) return NULL;
|
||||||
if (blob_ensure_capacity(b, capacity) < 0) {
|
if (blob_ensure_capacity(b, capacity) < 0) {
|
||||||
free(b);
|
free(b);
|
||||||
@@ -264,7 +263,6 @@ blob *blob_new_with_fill(size_t length_bits, int logical_value) {
|
|||||||
|
|
||||||
void blob_destroy(blob *b) {
|
void blob_destroy(blob *b) {
|
||||||
if (!b) return;
|
if (!b) return;
|
||||||
printf("destroying blob %p, data %p, length %zu, capacity %zu\n", b, b->data, b->length, b->capacity);
|
|
||||||
if (b->data) {
|
if (b->data) {
|
||||||
free(b->data);
|
free(b->data);
|
||||||
b->data = NULL;
|
b->data = NULL;
|
||||||
|
|||||||
@@ -102,7 +102,8 @@ JSValue js_##ID##_get_##ENTRY (JSContext *js, JSValue self) { \
|
|||||||
#define QJSCLASS(TYPE, ...)\
|
#define QJSCLASS(TYPE, ...)\
|
||||||
JSClassID js_##TYPE##_id;\
|
JSClassID js_##TYPE##_id;\
|
||||||
static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\
|
static void js_##TYPE##_finalizer(JSRuntime *rt, JSValue val){\
|
||||||
TYPE *n = JS_GetOpaque(val, js_##TYPE##_id);\
|
JSContext *js = JS_GetContext(rt);\
|
||||||
|
TYPE *n = JS_GetOpaque2(js, val, js_##TYPE##_id); \
|
||||||
TYPE##_free(rt,n);}\
|
TYPE##_free(rt,n);}\
|
||||||
static JSClassDef js_##TYPE##_class = {\
|
static JSClassDef js_##TYPE##_class = {\
|
||||||
.class_name = #TYPE,\
|
.class_name = #TYPE,\
|
||||||
|
|||||||
@@ -10,10 +10,7 @@
|
|||||||
// Free function for blob
|
// Free function for blob
|
||||||
void blob_free(JSRuntime *rt, blob *b)
|
void blob_free(JSRuntime *rt, blob *b)
|
||||||
{
|
{
|
||||||
if (b) {
|
// blob_destroy(b);
|
||||||
printf("destroying blob %p blob data %p, length %zu\n", b, b->data, b->length);
|
|
||||||
blob_destroy(b);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use QJSCLASS macro to generate class boilerplate
|
// Use QJSCLASS macro to generate class boilerplate
|
||||||
@@ -122,15 +119,7 @@ static JSValue js_blob_constructor(JSContext *ctx, JSValueConst new_target,
|
|||||||
return JS_ThrowOutOfMemory(ctx);
|
return JS_ThrowOutOfMemory(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
JSValue ret = blob2js(ctx, bd);
|
return blob2js(ctx, bd);
|
||||||
printf("created blob %p blob data %p, length %zu\n", bd, bd->data, bd->length);
|
|
||||||
// Ensure the returned object's prototype is set correctly for instanceof
|
|
||||||
JSValue ctor_proto = JS_GetPropertyStr(ctx, new_target, "prototype");
|
|
||||||
if (!JS_IsException(ctor_proto)) {
|
|
||||||
JS_SetPrototype(ctx, ret, ctor_proto);
|
|
||||||
}
|
|
||||||
JS_FreeValue(ctx, ctor_proto);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// blob.write_bit(logical)
|
// blob.write_bit(logical)
|
||||||
@@ -323,8 +312,6 @@ static JSValue js_blob_read_blob(JSContext *ctx, JSValueConst this_val,
|
|||||||
return JS_ThrowOutOfMemory(ctx);
|
return JS_ThrowOutOfMemory(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("stoned copy blob %p blob data %p, length %" PRId64 "\n", new_bd, new_bd->data, new_bd->length);
|
|
||||||
|
|
||||||
return blob2js(ctx, new_bd);
|
return blob2js(ctx, new_bd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,7 +505,6 @@ JSValue js_blob_use(JSContext *js) {
|
|||||||
// Explicitly set the prototype property to ensure instanceof works
|
// Explicitly set the prototype property to ensure instanceof works
|
||||||
JS_SetPropertyStr(js, ctor, "__prototype__", JS_DupValue(js, proto));
|
JS_SetPropertyStr(js, ctor, "__prototype__", JS_DupValue(js, proto));
|
||||||
JS_FreeValue(js, proto);
|
JS_FreeValue(js, proto);
|
||||||
|
|
||||||
return ctor;
|
return ctor;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -529,8 +515,6 @@ JSValue js_new_blob_stoned_copy(JSContext *js, void *data, size_t bytes)
|
|||||||
b->length = bytes * 8; // Set the actual length in bits
|
b->length = bytes * 8; // Set the actual length in bits
|
||||||
blob_make_stone(b);
|
blob_make_stone(b);
|
||||||
|
|
||||||
printf("stoned copy blob %p blob data %p, length %" PRId64 "\n", b, b->data, b->length);
|
|
||||||
|
|
||||||
return blob2js(js, b);
|
return blob2js(js, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -546,8 +530,14 @@ void *js_get_blob_data(JSContext *js, size_t *size, JSValue v)
|
|||||||
JS_ThrowReferenceError(js, "attempted to read data from a non-stone blob");
|
JS_ThrowReferenceError(js, "attempted to read data from a non-stone blob");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (b->length % 8 != 0) {
|
||||||
|
JS_ThrowReferenceError(js, "attempted to read data from a non-byte aligned blob");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
*size = (b->length + 7) / 8; // Return actual byte size based on bit length
|
*size = (b->length + 7) / 8; // Return actual byte size based on bit length
|
||||||
|
|
||||||
return b->data;
|
return b->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -556,13 +546,28 @@ void *js_get_blob_data_bits(JSContext *js, size_t *bits, JSValue v)
|
|||||||
blob *b = js2blob(js, v);
|
blob *b = js2blob(js, v);
|
||||||
if (!b) {
|
if (!b) {
|
||||||
JS_ThrowReferenceError(js, "get_blob_data_bits: not called on a blob");
|
JS_ThrowReferenceError(js, "get_blob_data_bits: not called on a blob");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!b->is_stone) {
|
if (!b->is_stone) {
|
||||||
JS_ThrowReferenceError(js, "attempted to read data from a non-stone blob");
|
JS_ThrowReferenceError(js, "attempted to read data from a non-stone blob");
|
||||||
return NULL;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!b->data) {
|
||||||
|
JS_ThrowReferenceError(js, "attempted to read data from an empty blob");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b->length % 8 != 0) {
|
||||||
|
JS_ThrowReferenceError(js, "attempted to read data from a non-byte aligned blob");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b->length == 0) {
|
||||||
|
JS_ThrowReferenceError(js, "attempted to read data from an empty blob");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
*bits = b->length;
|
*bits = b->length;
|
||||||
return b->data;
|
return b->data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ struct JSRuntime {
|
|||||||
int shape_hash_count; /* number of hashed shapes */
|
int shape_hash_count; /* number of hashed shapes */
|
||||||
JSShape **shape_hash;
|
JSShape **shape_hash;
|
||||||
void *user_opaque;
|
void *user_opaque;
|
||||||
|
JSContext *js;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct JSClass {
|
struct JSClass {
|
||||||
@@ -1576,6 +1577,7 @@ void JS_FreeRuntime(JSRuntime *rt)
|
|||||||
|
|
||||||
JSContext *JS_NewContextRaw(JSRuntime *rt)
|
JSContext *JS_NewContextRaw(JSRuntime *rt)
|
||||||
{
|
{
|
||||||
|
assert(!rt->js);
|
||||||
JSContext *ctx;
|
JSContext *ctx;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
@@ -1599,6 +1601,7 @@ JSContext *JS_NewContextRaw(JSRuntime *rt)
|
|||||||
ctx->regexp_ctor = JS_NULL;
|
ctx->regexp_ctor = JS_NULL;
|
||||||
|
|
||||||
JS_AddIntrinsicBasicObjects(ctx);
|
JS_AddIntrinsicBasicObjects(ctx);
|
||||||
|
rt->js = ctx;
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37481,3 +37484,11 @@ JSValue js_debugger_closure_variables(JSContext *ctx, JSValue fn) {
|
|||||||
done:
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *js_debugger_val_address(JSContext *ctx, JSValue val) {
|
||||||
|
return JS_VALUE_GET_PTR(val);
|
||||||
|
}
|
||||||
|
|
||||||
|
JSContext *JS_GetContext(JSRuntime *rt) {
|
||||||
|
return rt->js;
|
||||||
|
}
|
||||||
@@ -362,6 +362,7 @@ JS_BOOL JS_IsLiveObject(JSRuntime *rt, JSValueConst obj);
|
|||||||
JSContext *JS_NewContext(JSRuntime *rt);
|
JSContext *JS_NewContext(JSRuntime *rt);
|
||||||
void JS_FreeContext(JSContext *s);
|
void JS_FreeContext(JSContext *s);
|
||||||
JSContext *JS_DupContext(JSContext *ctx);
|
JSContext *JS_DupContext(JSContext *ctx);
|
||||||
|
JSContext *JS_GetContext(JSRuntime *rt);
|
||||||
void *JS_GetContextOpaque(JSContext *ctx);
|
void *JS_GetContextOpaque(JSContext *ctx);
|
||||||
void JS_SetContextOpaque(JSContext *ctx, void *opaque);
|
void JS_SetContextOpaque(JSContext *ctx, void *opaque);
|
||||||
JSRuntime *JS_GetRuntime(JSContext *ctx);
|
JSRuntime *JS_GetRuntime(JSContext *ctx);
|
||||||
@@ -990,6 +991,7 @@ JSValue js_debugger_local_variables(JSContext *ctx, int stack_index);
|
|||||||
JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc);
|
JSValue js_debugger_build_backtrace(JSContext *ctx, const uint8_t *cur_pc);
|
||||||
JSValue js_debugger_fn_info(JSContext *ctx, JSValue fn);
|
JSValue js_debugger_fn_info(JSContext *ctx, JSValue fn);
|
||||||
JSValue js_debugger_fn_bytecode(JSContext *js, JSValue fn);
|
JSValue js_debugger_fn_bytecode(JSContext *js, JSValue fn);
|
||||||
|
void *js_debugger_val_address(JSContext *js, JSValue val);
|
||||||
|
|
||||||
#undef js_unlikely
|
#undef js_unlikely
|
||||||
#undef js_force_inline
|
#undef js_force_inline
|
||||||
|
|||||||
Reference in New Issue
Block a user