package resolution

This commit is contained in:
2026-02-20 14:10:24 -06:00
parent f0c2486a5c
commit 601a78b3c7
2 changed files with 104 additions and 17 deletions

View File

@@ -1224,7 +1224,18 @@ if (prog_info) {
}
$_.clock(_ => {
var file_info = shop.file_info ? shop.file_info(prog_path) : null
var _file_info_ok = false
var file_info = null
var _try_fi = function() {
file_info = shop.file_info ? shop.file_info(prog_path) : null
_file_info_ok = true
} disruption {}
_try_fi()
if (!_file_info_ok || !file_info)
file_info = {path: prog_path, is_module: false, is_actor: true, package: null, name: prog}
// If the unified resolver found the package, use that as the authoritative source
if (prog_info && prog_info.pkg)
file_info.package = prog_info.pkg
var inject = shop.script_inject_for ? shop.script_inject_for(file_info) : []
// Build env with runtime functions + capability injections
@@ -1278,10 +1289,22 @@ $_.clock(_ => {
env.use = function(path) {
var ck = 'core/' + path
var _use_core_result = null
var _use_core_ok = false
if (use_cache[ck]) return use_cache[ck]
var core_mod = use_core(path)
if (core_mod) return core_mod
return shop.use(path, pkg)
var _try_core = function() {
_use_core_result = use_core(path)
_use_core_ok = true
} disruption {}
_try_core()
if (_use_core_ok && _use_core_result) return _use_core_result
var _shop_use = function() {
return shop.use(path, pkg)
} disruption {
log.error(`use('${path}') failed (package: ${pkg})`)
disrupt
}
return _shop_use()
}
env.args = _cell.args.arg
env.log = log

View File

@@ -137,9 +137,6 @@ function split_explicit_package_import(path)
if (package_in_shop(pkg_candidate))
return {package: pkg_candidate, path: mod_path}
if (Shop.resolve_package_info(pkg_candidate))
return {package: pkg_candidate, path: mod_path}
}
return null
@@ -158,6 +155,8 @@ function abs_path_to_package(package_dir)
}
var packages_prefix = get_packages_dir() + '/'
var packages_prefix_abs = fd.realpath(get_packages_dir())
if (packages_prefix_abs) packages_prefix_abs = packages_prefix_abs + '/'
var core_dir = packages_prefix + core_package
// Check if this is the core package directory (or its symlink target)
@@ -176,6 +175,10 @@ function abs_path_to_package(package_dir)
if (starts_with(package_dir, packages_prefix))
return text(package_dir, length(packages_prefix))
// Also try absolute path comparison (package_dir may be absolute, packages_prefix relative)
if (packages_prefix_abs && starts_with(package_dir, packages_prefix_abs))
return text(package_dir, length(packages_prefix_abs))
// Check if this local path is the target of a link
// If so, return the canonical package name (link origin) instead
var link_origin = link.get_origin(package_dir)
@@ -344,9 +347,11 @@ function get_policy() {
// Get information about how to resolve a package
// Local packages always start with /
// Remote packages must be exactly host/owner/repo (3 components)
Shop.resolve_package_info = function(pkg) {
if (starts_with(pkg, '/')) return 'local'
if (search(pkg, 'gitea') != null) return 'gitea'
var parts = array(pkg, '/')
if (length(parts) == 3 && search(parts[0], 'gitea') != null) return 'gitea'
return null
}
@@ -1349,25 +1354,78 @@ Shop.resolve_program = function(prog, package_context) {
})
// If not in lock, check if this looks like a fetchable package
if (!best_pkg) {
for (i = length(parts) - 1; i >= 1; i--) {
candidate = text(array(parts, 0, i), '/')
pkg_info = Shop.resolve_package_info(candidate)
if (pkg_info && pkg_info != 'local') {
best_pkg = candidate
best_remainder = text(array(parts, i), '/')
break
}
// For gitea-style URLs, the package root is host/owner/repo (3 components)
if (!best_pkg && length(parts) > 3) {
candidate = text(array(parts, 0, 3), '/')
pkg_info = Shop.resolve_package_info(candidate)
if (pkg_info && pkg_info != 'local') {
best_pkg = candidate
best_remainder = text(array(parts, 3), '/')
}
}
if (best_pkg && best_remainder) {
log.console('fetching ' + best_pkg + '...')
_auto = function() {
// Install the package itself first
Shop.update(best_pkg)
Shop.fetch(best_pkg)
Shop.extract(best_pkg)
// Install dependencies iteratively (each dep must be extracted before reading its deps)
var all_deps = {}
var queue = [best_pkg]
var qi = 0
var current = null
var direct_deps = null
var dep_locator = null
var dep_dir = null
var build_mod = null
var target = null
var _build_c = null
var _read_deps = null
while (qi < length(queue)) {
current = queue[qi]
qi = qi + 1
_read_deps = function() {
direct_deps = pkg_tools.dependencies(current)
} disruption {
direct_deps = null
}
_read_deps()
if (direct_deps) {
arrfor(array(direct_deps), function(alias) {
dep_locator = direct_deps[alias]
if (!all_deps[dep_locator]) {
all_deps[dep_locator] = true
dep_dir = pkg_tools.get_dir(dep_locator)
if (!fd.is_dir(dep_dir)) {
log.console(' installing dependency: ' + dep_locator)
Shop.update(dep_locator)
Shop.fetch(dep_locator)
Shop.extract(dep_locator)
}
push(queue, dep_locator)
}
})
}
}
// Build scripts for all packages
Shop.build_package_scripts(best_pkg)
arrfor(array(all_deps), function(dep) {
Shop.build_package_scripts(dep)
})
// Build C modules
build_mod = use_cache['core/build']
if (build_mod) {
_build_c = function() {
target = build_mod.detect_host_target()
arrfor(array(all_deps), function(dep) {
build_mod.build_dynamic(dep, target, 'release')
})
build_mod.build_dynamic(best_pkg, target, 'release')
} disruption {}
_build_c()
}
} disruption {
return null
}
@@ -1600,10 +1658,16 @@ function get_package_zip(pkg)
// Update: Check for new version, update lock, fetch and extract
// Returns the new lock entry if updated, null if already up to date or failed
Shop.update = function(pkg) {
Shop.verify_package_name(pkg)
var lock = Shop.load_lock()
var lock_entry = lock[pkg]
var info = Shop.resolve_package_info(pkg)
if (!info) {
log.error("Not a valid package locator: " + pkg)
return null
}
log.shop(`checking ${pkg}`)
var new_entry = null