reduce dups

This commit is contained in:
2026-02-20 14:44:48 -06:00
parent 601a78b3c7
commit 4ac92c8a87
16 changed files with 232 additions and 635 deletions

92
add.ce
View File

@@ -9,20 +9,18 @@
var shop = use('internal/shop')
var pkg = use('package')
var build = use('build')
var fd = use('fd')
var locator = null
var alias = null
var resolved = null
var parts = null
var cwd = null
var build_target = null
var recursive = false
var cwd = fd.realpath('.')
var parts = null
var locators = null
var added = 0
var failed = 0
var summary = null
var _add_dep = null
var _install = null
array(args, function(arg) {
if (arg == '--help' || arg == '-h') {
@@ -52,89 +50,65 @@ if (!locator && !recursive) {
$stop()
}
// Resolve relative paths to absolute paths
if (locator && (locator == '.' || starts_with(locator, './') || starts_with(locator, '../') || fd.is_dir(locator))) {
resolved = fd.realpath(locator)
if (resolved) {
locator = resolved
}
}
if (locator)
locator = shop.resolve_locator(locator)
// Generate default alias from locator
if (!alias && locator) {
// Use the last component of the locator as alias
parts = array(locator, '/')
alias = parts[length(parts) - 1]
// Remove any version suffix
if (search(alias, '@') != null) {
if (search(alias, '@') != null)
alias = array(alias, '@')[0]
}
}
// Check we're in a package directory
cwd = fd.realpath('.')
if (!fd.is_file(cwd + '/cell.toml')) {
log.error("Not in a package directory (no cell.toml found)")
$stop()
}
// If -r flag, find all packages recursively and add each
// Recursive mode
if (recursive) {
if (!locator) {
locator = '.'
}
resolved = fd.realpath(locator)
if (!resolved || !fd.is_dir(resolved)) {
if (!locator) locator = '.'
locator = shop.resolve_locator(locator)
if (!fd.is_dir(locator)) {
log.error(`${locator} is not a directory`)
$stop()
}
locators = filter(pkg.find_packages(resolved), function(p) {
locators = filter(pkg.find_packages(locator), function(p) {
return p != cwd
})
if (length(locators) == 0) {
log.console("No packages found in " + resolved)
log.console("No packages found in " + locator)
$stop()
}
log.console(`Found ${text(length(locators))} package(s) in ${resolved}`)
log.console(`Found ${text(length(locators))} package(s) in ${locator}`)
added = 0
failed = 0
arrfor(locators, function(loc) {
// Generate alias from directory name
var loc_parts = array(loc, '/')
var loc_alias = loc_parts[length(loc_parts) - 1]
log.console(" Adding " + loc + " as '" + loc_alias + "'...")
var _add = function() {
pkg.add_dependency(null, loc, loc_alias)
shop.get(loc)
shop.extract(loc)
shop.build_package_scripts(loc)
var _build_c = function() {
build_target = build.detect_host_target()
build.build_dynamic(loc, build_target, 'release')
} disruption {
// Not all packages have C code
}
_build_c()
added++
shop.sync(loc)
added = added + 1
} disruption {
log.console(` Warning: Failed to add ${loc}`)
failed++
failed = failed + 1
}
_add()
})
summary = "Added " + text(added) + " package(s)."
if (failed > 0) {
summary += " Failed: " + text(failed) + "."
}
log.console(summary)
log.console("Added " + text(added) + " package(s)." + (failed > 0 ? " Failed: " + text(failed) + "." : ""))
$stop()
}
// Single package add
log.console("Adding " + locator + " as '" + alias + "'...")
// Add to local project's cell.toml
var _add_dep = function() {
_add_dep = function() {
pkg.add_dependency(null, locator, alias)
log.console(" Added to cell.toml")
} disruption {
@@ -143,26 +117,8 @@ var _add_dep = function() {
}
_add_dep()
// Install to shop
var _install = function() {
shop.get(locator)
shop.extract(locator)
// Build scripts
var script_result = shop.build_package_scripts(locator)
if (length(script_result.errors) > 0) {
log.console(" Warning: " + text(length(script_result.errors)) + " script(s) failed to compile")
}
// Build C code if any
var _build_c = function() {
build_target = build.detect_host_target()
build.build_dynamic(locator, build_target, 'release')
} disruption {
// Not all packages have C code
}
_build_c()
_install = function() {
shop.sync_with_deps(locator)
log.console(" Installed to shop")
} disruption {
log.error("Failed to install")

View File

@@ -10,11 +10,9 @@
var shop = use('internal/shop')
var pkg = use('package')
var fd = use('fd')
var target_package = null
var i = 0
var resolved = null
for (i = 0; i < length(args); i++) {
if (args[i] == '--help' || args[i] == '-h') {
@@ -30,12 +28,7 @@ for (i = 0; i < length(args); i++) {
// Resolve local paths
if (target_package) {
if (target_package == '.' || starts_with(target_package, './') || starts_with(target_package, '../') || fd.is_dir(target_package)) {
resolved = fd.realpath(target_package)
if (resolved) {
target_package = resolved
}
}
target_package = shop.resolve_locator(target_package)
}
var packages = null

View File

@@ -22,7 +22,6 @@ var dry_run = false
var i = 0
var targets = null
var t = 0
var resolved = null
var lib = null
var results = null
var success = 0
@@ -74,15 +73,8 @@ for (i = 0; i < length(args); i++) {
}
}
// Resolve local paths to absolute paths
if (target_package) {
if (target_package == '.' || starts_with(target_package, './') || starts_with(target_package, '../') || fd.is_dir(target_package)) {
resolved = fd.realpath(target_package)
if (resolved) {
target_package = resolved
}
}
}
if (target_package)
target_package = shop.resolve_locator(target_package)
// Detect target if not specified
if (!target) {
@@ -97,10 +89,9 @@ if (target && !build.has_target(target)) {
}
var packages = shop.list_packages()
log.console('Preparing packages...')
arrfor(packages, function(package) {
if (package == 'core') return
shop.extract(package)
shop.sync(package, {no_build: true})
})
var _build = null

View File

@@ -24,7 +24,6 @@ var clean_fetch = false
var deep = false
var dry_run = false
var i = 0
var resolved = null
var deps = null
for (i = 0; i < length(args); i++) {
@@ -76,12 +75,7 @@ var is_shop_scope = (scope == 'shop')
var is_world_scope = (scope == 'world')
if (!is_shop_scope && !is_world_scope) {
if (scope == '.' || starts_with(scope, './') || starts_with(scope, '../') || fd.is_dir(scope)) {
resolved = fd.realpath(scope)
if (resolved) {
scope = resolved
}
}
scope = shop.resolve_locator(scope)
}
var files_to_delete = []

View File

@@ -7,10 +7,6 @@ var fd = use('fd')
var http = use('http')
var miniz = use('miniz')
var resolved = null
var cwd = null
var parent = null
if (length(args) < 2) {
log.console("Usage: cell clone <origin> <path>")
log.console("Clones a cell package to a local path and links it.")
@@ -21,24 +17,7 @@ var origin = args[0]
var target_path = args[1]
// Resolve target path to absolute
if (target_path == '.' || starts_with(target_path, './') || starts_with(target_path, '../')) {
resolved = fd.realpath(target_path)
if (resolved) {
target_path = resolved
} else {
// Path doesn't exist yet, resolve relative to cwd
cwd = fd.realpath('.')
if (target_path == '.') {
target_path = cwd
} else if (starts_with(target_path, './')) {
target_path = cwd + text(target_path, 1)
} else if (starts_with(target_path, '../')) {
// Go up one directory from cwd
parent = fd.dirname(cwd)
target_path = parent + text(target_path, 2)
}
}
}
target_path = shop.resolve_locator(target_path)
// Check if target already exists
if (fd.is_dir(target_path)) {

100
fetch.ce
View File

@@ -1,104 +1,46 @@
// cell fetch - Fetch package zips from remote sources
// cell fetch - Sync packages from remote sources
//
// This command ensures that the zip files on disk match what's in the lock file.
// For local packages, this is a no-op.
// For remote packages, downloads the zip if not present or hash mismatch.
// Ensures all packages are fetched, extracted, compiled, and ready to use.
// For local packages, this is a no-op (symlinks only).
//
// Usage:
// cell fetch - Fetch all packages
// cell fetch <package> - Fetch a specific package
// cell fetch - Sync all packages
// cell fetch <package> - Sync a specific package
var shop = use('internal/shop')
// Parse arguments
var target_pkg = null
var i = 0
var packages = null
var count = 0
for (i = 0; i < length(args); i++) {
if (args[i] == '--help' || args[i] == '-h') {
log.console("Usage: cell fetch [package]")
log.console("Fetch package zips from remote sources.")
log.console("Sync packages from remote sources.")
log.console("")
log.console("Arguments:")
log.console(" package Optional package name to fetch. If omitted, fetches all.")
log.console("")
log.console("This command ensures that the zip files on disk match what's in")
log.console("the lock file. For local packages, this is a no-op.")
log.console(" package Optional package to sync. If omitted, syncs all.")
$stop()
} else if (!starts_with(args[i], '-')) {
target_pkg = args[i]
}
}
var all_packages = shop.list_packages()
var lock = shop.load_lock()
var packages_to_fetch = []
var _update = null
if (target_pkg) {
// Fetch specific package - auto-update if not in lock
if (find(all_packages, target_pkg) == null) {
log.console("Package not in lock, updating: " + target_pkg)
_update = function() {
shop.update(target_pkg)
} disruption {
log.error("Could not update package: " + target_pkg)
$stop()
}
_update()
// Reload after update
all_packages = shop.list_packages()
lock = shop.load_lock()
if (find(all_packages, target_pkg) == null) {
log.error("Package not found: " + target_pkg)
$stop()
}
}
push(packages_to_fetch, target_pkg)
target_pkg = shop.resolve_locator(target_pkg)
log.console("Syncing " + target_pkg + "...")
shop.sync(target_pkg)
log.console("Done.")
} else {
// Fetch all packages
packages_to_fetch = all_packages
packages = shop.list_packages()
count = 0
arrfor(packages, function(pkg) {
if (pkg == 'core') return
shop.sync(pkg)
count = count + 1
})
log.console("Synced " + text(count) + " package(s).")
}
var remote_count = 0
arrfor(packages_to_fetch, function(pkg) {
var entry = lock[pkg]
if (pkg != 'core' && (!entry || entry.type != 'local'))
remote_count++
}, null, null)
if (remote_count > 0)
log.console(`Fetching ${text(remote_count)} remote package(s)...`)
var downloaded_count = 0
var cached_count = 0
var fail_count = 0
arrfor(packages_to_fetch, function(pkg) {
// Skip core (handled separately)
if (pkg == 'core') return
var result = shop.fetch(pkg)
if (result.status == 'local') {
// Local packages are just symlinks, nothing to fetch
return
} else if (result.status == 'cached') {
cached_count++
} else if (result.status == 'downloaded') {
log.console(" Downloaded: " + pkg)
downloaded_count++
} else if (result.status == 'error') {
log.error(" Failed: " + pkg + (result.message ? " - " + result.message : ""))
fail_count++
}
}, null, null)
log.console("")
var parts = []
if (downloaded_count > 0) push(parts, `${text(downloaded_count)} downloaded`)
if (cached_count > 0) push(parts, `${text(cached_count)} cached`)
if (fail_count > 0) push(parts, `${text(fail_count)} failed`)
if (length(parts) == 0) push(parts, "nothing to fetch")
log.console("Fetch complete: " + text(parts, ", "))
$stop()

View File

@@ -15,7 +15,6 @@
var shop = use('internal/shop')
var pkg = use('package')
var link = use('link')
var fd = use('fd')
var json = use('json')
var target_locator = null
@@ -23,7 +22,6 @@ var format = 'tree'
var show_locked = false
var show_world = false
var i = 0
var resolved = null
for (i = 0; i < length(args); i++) {
if (args[i] == '--format' || args[i] == '-f') {
@@ -127,13 +125,7 @@ if (show_world) {
target_locator = '.'
}
// Resolve local paths
if (target_locator == '.' || starts_with(target_locator, './') || starts_with(target_locator, '../') || fd.is_dir(target_locator)) {
resolved = fd.realpath(target_locator)
if (resolved) {
target_locator = resolved
}
}
target_locator = shop.resolve_locator(target_locator)
push(roots, target_locator)
}

View File

@@ -1,4 +1,4 @@
// cell install <locator> - Install a package to the shop
// cell install <locator> - Install a package and its dependencies
//
// Usage:
// cell install <locator> Install a package and its dependencies
@@ -6,34 +6,23 @@
//
// Options:
// --target <triple> Build for target platform
// --refresh Refresh floating refs before locking
// --dry-run Show what would be installed
// -r Recursively find and install all packages in directory
var shop = use('internal/shop')
var build = use('build')
var pkg = use('package')
var fd = use('fd')
if (length(args) < 1) {
log.console("Usage: cell install <locator> [options]")
log.console("")
log.console("Options:")
log.console(" --target <triple> Build for target platform")
log.console(" --refresh Refresh floating refs before locking")
log.console(" --dry-run Show what would be installed")
log.console(" -r Recursively find and install all packages in directory")
$stop()
}
var locator = null
var target_triple = null
var refresh = false
var dry_run = false
var recursive = false
var i = 0
var resolved = null
var locators = null
var cwd = fd.realpath('.')
var lock = null
var installed = 0
var failed = 0
for (i = 0; i < length(args); i++) {
if (args[i] == '--target' || args[i] == '-t') {
@@ -43,8 +32,6 @@ for (i = 0; i < length(args); i++) {
log.error('--target requires a triple')
$stop()
}
} else if (args[i] == '--refresh') {
refresh = true
} else if (args[i] == '--dry-run') {
dry_run = true
} else if (args[i] == '-r') {
@@ -52,11 +39,10 @@ for (i = 0; i < length(args); i++) {
} else if (args[i] == '--help' || args[i] == '-h') {
log.console("Usage: cell install <locator> [options]")
log.console("")
log.console("Install a package and its dependencies to the shop.")
log.console("Install a package and its dependencies.")
log.console("")
log.console("Options:")
log.console(" --target <triple> Build for target platform")
log.console(" --refresh Refresh floating refs before locking")
log.console(" --dry-run Show what would be installed")
log.console(" -r Recursively find and install all packages in directory")
$stop()
@@ -66,197 +52,65 @@ for (i = 0; i < length(args); i++) {
}
if (!locator && !recursive) {
log.console("Usage: cell install <locator>")
log.console("Usage: cell install <locator> [options]")
$stop()
}
// Resolve relative paths to absolute paths
// Local paths like '.' or '../foo' need to be converted to absolute paths
if (locator && (locator == '.' || starts_with(locator, './') || starts_with(locator, '../') || fd.is_dir(locator))) {
resolved = fd.realpath(locator)
if (resolved) {
locator = resolved
}
}
if (locator)
locator = shop.resolve_locator(locator)
var cwd = fd.realpath('.')
// If -r flag, find all packages recursively and install each
// Recursive mode: find all packages in directory and install each
if (recursive) {
if (!locator) {
locator = '.'
}
resolved = fd.realpath(locator)
if (!resolved || !fd.is_dir(resolved)) {
if (!locator) locator = '.'
locator = shop.resolve_locator(locator)
if (!fd.is_dir(locator)) {
log.error(`${locator} is not a directory`)
$stop()
}
locators = filter(pkg.find_packages(resolved), function(p) {
locators = filter(pkg.find_packages(locator), function(p) {
return p != cwd
})
if (length(locators) == 0) {
log.console("No packages found in " + resolved)
log.console("No packages found in " + locator)
$stop()
}
log.console(`Found ${text(length(locators))} package(s) in ${resolved}`)
}
log.console(`Found ${text(length(locators))} package(s) in ${locator}`)
// Default target
if (!target_triple) {
target_triple = build.detect_host_target()
}
// Gather all packages that will be installed
var packages_to_install = []
var skipped_packages = []
var summary = null
var visited = {}
// Recursive mode: install all found packages and exit
if (recursive) {
if (dry_run) {
log.console("Would install:")
arrfor(locators, function(loc) {
var lock = shop.load_lock()
var exists = lock[loc] != null
log.console(" " + loc + (exists ? " (already installed)" : ""))
lock = shop.load_lock()
log.console(" " + loc + (lock[loc] ? " (already installed)" : ""))
})
$stop()
}
installed = 0
failed = 0
arrfor(locators, function(loc) {
log.console(" Installing " + loc + "...")
var _inst = function() {
shop.update(loc)
shop.extract(loc)
shop.build_package_scripts(loc)
var _build_c = function() {
build.build_dynamic(loc, target_triple, 'release')
} disruption {
// Not all packages have C code
}
_build_c()
push(packages_to_install, loc)
shop.sync(loc, {target: target_triple})
installed = installed + 1
} disruption {
push(skipped_packages, loc)
failed = failed + 1
log.console(` Warning: Failed to install ${loc}`)
}
_inst()
})
summary = "Installed " + text(length(packages_to_install)) + " package(s)."
if (length(skipped_packages) > 0) {
summary += " Failed: " + text(length(skipped_packages)) + "."
}
log.console(summary)
log.console("Installed " + text(installed) + " package(s)." + (failed > 0 ? " Failed: " + text(failed) + "." : ""))
$stop()
}
// Single package install with dependencies
if (dry_run) {
log.console("Would install: " + locator + " (and dependencies)")
$stop()
}
log.console("Installing " + locator + "...")
function gather_packages(pkg_locator) {
var lock = null
var update_result = null
var deps = null
if (visited[pkg_locator]) return
visited[pkg_locator] = true
// Check if this is a local path that doesn't exist
if (starts_with(pkg_locator, '/') && !fd.is_dir(pkg_locator)) {
push(skipped_packages, pkg_locator)
log.console(" Skipping missing local package: " + pkg_locator)
return
}
push(packages_to_install, pkg_locator)
// Try to read dependencies
var _gather = function() {
// For packages not yet extracted, we need to update and extract first to read deps
lock = shop.load_lock()
if (!lock[pkg_locator]) {
if (!dry_run) {
update_result = shop.update(pkg_locator)
if (update_result) {
shop.extract(pkg_locator)
} else {
// Update failed - package might not be fetchable
log.console("Warning: Could not fetch " + pkg_locator)
return
}
}
} else {
// Package is in lock, ensure it's extracted
if (!dry_run) {
shop.extract(pkg_locator)
}
}
deps = pkg.dependencies(pkg_locator)
if (deps) {
arrfor(array(deps), function(alias) {
var dep_locator = deps[alias]
gather_packages(dep_locator)
})
}
} disruption {
// Package might not have dependencies or cell.toml issue
if (!dry_run) {
log.console(`Warning: Could not read dependencies for ${pkg_locator}`)
}
}
_gather()
}
// Gather all packages
gather_packages(locator)
if (dry_run) {
log.console("Would install:")
arrfor(packages_to_install, function(p) {
var lock = shop.load_lock()
var exists = lock[p] != null
log.console(" " + p + (exists ? " (already installed)" : ""))
})
if (length(skipped_packages) > 0) {
log.console("")
log.console("Would skip (missing local paths):")
arrfor(skipped_packages, function(p) {
log.console(" " + p)
})
}
$stop()
}
// Install each package
function install_package(pkg_locator) {
// Update lock entry
shop.update(pkg_locator)
// Extract/symlink the package
shop.extract(pkg_locator)
// Build scripts
shop.build_package_scripts(pkg_locator)
// Build C code
var _build_c = function() {
build.build_dynamic(pkg_locator, target_triple, 'release')
} disruption {
// Not all packages have C code
}
_build_c()
}
arrfor(packages_to_install, function(p) {
log.console(" Installing " + p + "...")
install_package(p)
})
summary = "Installed " + text(length(packages_to_install)) + " package(s)."
if (length(skipped_packages) > 0) {
summary += " Skipped " + text(length(skipped_packages)) + " missing local path(s)."
}
log.console(summary)
shop.sync_with_deps(locator, {refresh: true, target: target_triple})
log.console("Done.")
$stop()

View File

@@ -1268,20 +1268,12 @@ $_.clock(_ => {
if (!fd.is_dir(_dep_dir)) {
log.console('installing missing dependency: ' + _deps[_di])
_auto_install = function() {
shop.update(_deps[_di])
shop.fetch(_deps[_di])
shop.extract(_deps[_di])
shop.build_package_scripts(_deps[_di])
shop.sync(_deps[_di])
} disruption {
log.error('failed to install dependency: ' + _deps[_di])
disrupt
}
_auto_install()
_dep_dir = package.get_dir(_deps[_di])
if (!fd.is_dir(_dep_dir)) {
log.error('missing dependency package: ' + _deps[_di])
disrupt
}
}
_di = _di + 1
}

View File

@@ -270,6 +270,17 @@ function safe_package_path(pkg)
return replace(pkg, '@', '_')
}
// Resolve a locator string to its canonical form
// Handles '.', './', '../', and existing directory paths
Shop.resolve_locator = function(locator) {
var resolved = null
if (locator == '.' || starts_with(locator, './') || starts_with(locator, '../') || fd.is_dir(locator)) {
resolved = fd.realpath(locator)
if (resolved) return resolved
}
return locator
}
function package_cache_path(pkg)
{
return global_shop_path + '/cache/' + replace(replace(pkg, '/', '_'), '@', '_')
@@ -297,7 +308,8 @@ Shop.load_lock = function() {
// Save lock.toml configuration (to global shop)
Shop.save_lock = function(lock) {
var path = global_shop_path + '/lock.toml'
fd.slurpwrite(path, stone(blob(toml.encode(lock))));
fd.slurpwrite(path, stone(blob(toml.encode(lock))))
_lock = lock
}
@@ -1317,8 +1329,6 @@ Shop.use = function use(path, package_context) {
return use_cache[info.cache_key]
}
Shop.resolve_locator = resolve_locator
// Resolve a use() module path to a filesystem path without compiling.
// Returns the absolute path string, or null if not found.
Shop.resolve_use_path = function(path, ctx) {
@@ -1335,14 +1345,13 @@ Shop.resolve_program = function(prog, package_context) {
var info = resolve_path(prog + '.ce', package_context)
if (info) return info
// Auto-install: if the path matches a recognized remote locator, try fetching
// Find best matching package from lock or infer from path
var lock = Shop.load_lock()
var best_pkg = null
var best_remainder = null
var pkg_info = null
var parts = array(prog, '/')
var i = 0
var candidate = null
var pkg_info = null
var _auto = null
arrfor(array(lock), function(pkg_name) {
if (starts_with(prog, pkg_name + '/')) {
@@ -1353,8 +1362,7 @@ Shop.resolve_program = function(prog, package_context) {
}
})
// If not in lock, check if this looks like a fetchable package
// For gitea-style URLs, the package root is host/owner/repo (3 components)
// If not in lock, try gitea-style 3-component package (host/owner/repo)
if (!best_pkg && length(parts) > 3) {
candidate = text(array(parts, 0, 3), '/')
pkg_info = Shop.resolve_package_info(candidate)
@@ -1364,78 +1372,19 @@ Shop.resolve_program = function(prog, package_context) {
}
}
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
}
_auto()
// Retry resolution
info = resolve_path(prog + '.ce', package_context)
if (info) return info
}
if (!best_pkg || !best_remainder) return null
return null
// Auto-install the package and all its dependencies
log.console('fetching ' + best_pkg + '...')
_auto = function() {
Shop.sync_with_deps(best_pkg)
} disruption {
return null
}
_auto()
info = resolve_path(prog + '.ce', package_context)
return info
}
// Resolve a use() module path to {resolved_path, package, type} without compiling.
@@ -1713,6 +1662,82 @@ Shop.update = function(pkg) {
return new_entry
}
// Sync a package: ensure it's in lock, fetched, extracted, and compiled
// opts.refresh - check remote for updates even if lock entry exists
// opts.no_build - skip C module build step
// opts.target - explicit build target (auto-detected if not provided)
// opts.buildtype - 'release'|'debug'|'minsize' (default 'release')
Shop.sync = function(pkg, opts) {
var lock = Shop.load_lock()
var info = Shop.resolve_package_info(pkg)
var build_mod = null
var target = null
var _build_c = null
// Step 1: Ensure lock entry (update if refresh or not in lock)
if ((opts && opts.refresh) || !lock[pkg])
Shop.update(pkg)
// Step 2: Fetch zip (no-op for local packages)
if (info && info != 'local')
Shop.fetch(pkg)
// Step 3: Extract to packages dir
Shop.extract(pkg)
// Step 4: Compile scripts
Shop.build_package_scripts(pkg)
// Step 5: Build C modules
if (!opts || !opts.no_build) {
build_mod = use_cache['core/build']
if (build_mod) {
target = (opts && opts.target) ? opts.target : build_mod.detect_host_target()
_build_c = function() {
build_mod.build_dynamic(pkg, target, (opts && opts.buildtype) ? opts.buildtype : 'release')
} disruption {
// Not all packages have C code
}
_build_c()
}
}
}
// Sync a package and all its dependencies (BFS)
Shop.sync_with_deps = function(pkg, opts) {
var visited = {}
var queue = [pkg]
var qi = 0
var current = null
var deps = null
var dep_locator = null
var _read_deps = null
while (qi < length(queue)) {
current = queue[qi]
qi = qi + 1
if (visited[current]) continue
visited[current] = true
Shop.sync(current, opts)
_read_deps = function() {
deps = pkg_tools.dependencies(current)
} disruption {
deps = null
}
_read_deps()
if (deps) {
arrfor(array(deps), function(alias) {
dep_locator = deps[alias]
if (!visited[dep_locator])
push(queue, dep_locator)
})
}
}
}
function install_zip(zip_blob, target_dir) {
var zip = miniz.read(zip_blob)
if (!zip) { print("Failed to read zip archive"); disrupt }
@@ -1779,34 +1804,6 @@ Shop.remove = function(pkg) {
return true
}
Shop.get = function(pkg) {
var lock = Shop.load_lock()
var info = null
var commit = null
if (!lock[pkg]) {
info = Shop.resolve_package_info(pkg)
if (!info) {
print("Invalid package: " + pkg); disrupt
}
commit = null
if (info != 'local') {
commit = fetch_remote_hash(pkg)
if (!commit) {
print("Could not resolve commit for " + pkg); disrupt
}
}
lock[pkg] = {
type: info,
commit: commit,
updated: time.number()
}
Shop.save_lock(lock)
}
}
// Compile a module
// List all files in a package
@@ -1883,6 +1880,7 @@ Shop.build_package_scripts = function(package)
ok = ok + 1
} disruption {
push(errors, script)
log.console(" compile error: " + package + '/' + script)
}
_try()
})

21
link.ce
View File

@@ -28,7 +28,6 @@ var target = null
var start_idx = 0
var arg1 = null
var arg2 = null
var cwd = null
var toml_path = null
var content = null
var _restore = null
@@ -123,30 +122,14 @@ if (cmd == 'list') {
target = arg2
// Resolve target if it's a local path
if (target == '.' || fd.is_dir(target)) {
target = fd.realpath(target)
} else if (starts_with(target, './') || starts_with(target, '../')) {
// Relative path that doesn't exist yet - try to resolve anyway
cwd = fd.realpath('.')
if (starts_with(target, './')) {
target = cwd + text(target, 1)
} else {
// For ../ paths, let fd.realpath handle it if possible
target = fd.realpath(target) || target
}
}
// Otherwise target is a package name (e.g., github.com/prosperon)
target = shop.resolve_locator(target)
} else {
// One argument: assume it's a local path, infer package name from cell.toml
target = arg1
// Resolve path
if (target == '.' || fd.is_dir(target)) {
target = fd.realpath(target)
} else if (starts_with(target, './') || starts_with(target, '../')) {
target = fd.realpath(target) || target
}
target = shop.resolve_locator(target)
// Must be a local path with cell.toml
toml_path = target + '/cell.toml'

10
list.ce
View File

@@ -8,11 +8,9 @@
var shop = use('internal/shop')
var pkg = use('package')
var link = use('link')
var fd = use('fd')
var mode = 'local'
var target_pkg = null
var resolved = null
var i = 0
var deps = null
var packages = null
@@ -37,13 +35,7 @@ if (args && length(args) > 0) {
mode = 'package'
target_pkg = args[0]
// Resolve local paths
if (target_pkg == '.' || starts_with(target_pkg, './') || starts_with(target_pkg, '../') || fd.is_dir(target_pkg)) {
resolved = fd.realpath(target_pkg)
if (resolved) {
target_pkg = resolved
}
}
target_pkg = shop.resolve_locator(target_pkg)
}
}

View File

@@ -17,7 +17,6 @@ var target_pkg = null
var prune = false
var dry_run = false
var i = 0
var resolved = null
for (i = 0; i < length(args); i++) {
if (args[i] == '--prune') {
@@ -43,13 +42,7 @@ if (!target_pkg) {
$stop()
}
// Resolve relative paths to absolute paths
if (target_pkg == '.' || starts_with(target_pkg, './') || starts_with(target_pkg, '../') || fd.is_dir(target_pkg)) {
resolved = fd.realpath(target_pkg)
if (resolved) {
target_pkg = resolved
}
}
target_pkg = shop.resolve_locator(target_pkg)
var packages_to_remove = [target_pkg]

View File

@@ -21,7 +21,6 @@ var target_triple = null
var show_locked = false
var refresh_first = false
var i = 0
var resolved = null
for (i = 0; i < length(args); i++) {
if (args[i] == '--target' || args[i] == '-t') {
@@ -56,12 +55,7 @@ if (!target_locator) {
}
// Resolve local paths
if (target_locator == '.' || starts_with(target_locator, './') || starts_with(target_locator, '../') || fd.is_dir(target_locator)) {
resolved = fd.realpath(target_locator)
if (resolved) {
target_locator = resolved
}
}
target_locator = shop.resolve_locator(target_locator)
// Check if it's a valid package
var pkg_dir = null

121
update.ce
View File

@@ -1,30 +1,28 @@
// cell update [<locator>] - Update packages from remote sources
//
// Usage:
// cell update Update all packages in shop
// cell update Update all packages
// cell update . Update current directory package
// cell update <locator> Update a specific package
//
// Options:
// --build Run build after updating
// --target <triple> Target platform for build (requires --build)
// --target <triple> Target platform for build
// --follow-links Update link targets instead of origins
// --git Run git pull on local packages before updating
var shop = use('internal/shop')
var build = use('build')
var fd = use('fd')
var os = use('os')
var link = use('link')
var target_pkg = null
var run_build = false
var target_triple = null
var follow_links = false
var git_pull = false
var i = 0
var resolved = null
var updated = 0
var packages = null
// Parse arguments
for (i = 0; i < length(args); i++) {
if (args[i] == '--help' || args[i] == '-h') {
log.console("Usage: cell update [<locator>] [options]")
@@ -32,13 +30,10 @@ for (i = 0; i < length(args); i++) {
log.console("Update packages from remote sources.")
log.console("")
log.console("Options:")
log.console(" --build Run build after updating")
log.console(" --target <triple> Target platform for build (requires --build)")
log.console(" --target <triple> Target platform for build")
log.console(" --follow-links Update link targets instead of origins")
log.console(" --git Run git pull on local packages")
$stop()
} else if (args[i] == '--build') {
run_build = true
} else if (args[i] == '--target' || args[i] == '-t') {
if (i + 1 < length(args)) {
target_triple = args[++i]
@@ -52,33 +47,22 @@ for (i = 0; i < length(args); i++) {
git_pull = true
} else if (!starts_with(args[i], '-')) {
target_pkg = args[i]
// Resolve relative paths to absolute paths
if (target_pkg == '.' || starts_with(target_pkg, './') || starts_with(target_pkg, '../') || fd.is_dir(target_pkg)) {
resolved = fd.realpath(target_pkg)
if (resolved) {
target_pkg = resolved
}
}
}
}
// Default target if building
if (run_build && !target_triple) {
target_triple = build.detect_host_target()
}
if (target_pkg)
target_pkg = shop.resolve_locator(target_pkg)
var link = use('link')
function update_and_fetch(pkg) {
function update_one(pkg) {
var effective_pkg = pkg
var link_target = null
var lock = shop.load_lock()
var old_entry = lock[pkg]
var old_commit = old_entry ? old_entry.commit : null
var effective_pkg = pkg
var link_target = null
var info = shop.resolve_package_info(pkg)
var new_entry = null
var old_str = null
// Handle follow-links option
if (follow_links) {
link_target = link.get_target(pkg)
if (link_target) {
@@ -87,80 +71,47 @@ function update_and_fetch(pkg) {
}
}
// For local packages with --git, pull first
if (git_pull && info == 'local' && fd.is_dir(effective_pkg + '/.git')) {
log.console(" " + effective_pkg + " (git pull)")
os.system('git -C "' + effective_pkg + '" pull')
}
// Check for update (sets lock entry if changed)
new_entry = shop.update(effective_pkg)
if (new_entry) {
if (new_entry.commit) {
old_str = old_commit ? text(old_commit, 0, 8) : "(new)"
log.console(" " + effective_pkg + " " + old_str + " -> " + text(new_entry.commit, 0, 8))
shop.fetch(effective_pkg)
} else {
// Local package - run git pull if requested
if (git_pull && fd.is_dir(effective_pkg + '/.git')) {
log.console(" " + effective_pkg + " (git pull)")
os.system('git -C "' + effective_pkg + '" pull')
} else {
log.console(" " + effective_pkg + " (local)")
}
}
shop.extract(effective_pkg)
shop.build_package_scripts(effective_pkg)
return effective_pkg
if (new_entry && new_entry.commit) {
old_str = old_commit ? text(old_commit, 0, 8) : "(new)"
log.console(" " + effective_pkg + " " + old_str + " -> " + text(new_entry.commit, 0, 8))
}
return null
// Sync: fetch, extract, build
shop.sync(effective_pkg, {target: target_triple})
return new_entry
}
var updated_packages = []
var updated = null
var packages = null
var pkg_count = 0
var pkg = null
if (target_pkg) {
updated = update_and_fetch(target_pkg)
if (updated) {
push(updated_packages, updated)
if (update_one(target_pkg)) {
log.console("Updated " + target_pkg + ".")
} else {
log.console(target_pkg + " is up to date.")
}
} else {
packages = shop.list_packages()
pkg_count = length(packages)
log.console("Checking for updates (" + text(pkg_count) + " package" + (pkg_count == 1 ? "" : "s") + ")...")
log.console("Checking for updates (" + text(length(packages)) + " packages)...")
for (i = 0; i < length(packages); i++) {
pkg = packages[i]
if (pkg == 'core') continue
arrfor(packages, function(pkg) {
if (pkg == 'core') return
if (update_one(pkg))
updated = updated + 1
})
updated = update_and_fetch(pkg)
if (updated) {
push(updated_packages, updated)
}
}
if (length(updated_packages) > 0) {
log.console("Updated " + text(length(updated_packages)) + " package" + (length(updated_packages) == 1 ? "" : "s") + ".")
if (updated > 0) {
log.console("Updated " + text(updated) + " package(s).")
} else {
log.console("All packages are up to date.")
}
}
// Run build if requested
if (run_build && length(updated_packages) > 0) {
log.console("")
log.console("Building updated packages...")
arrfor(updated_packages, function(pkg) {
var _build = function() {
var lib = build.build_dynamic(pkg, target_triple, 'release')
if (lib)
log.console(" Built: " + lib)
} disruption {
log.error(" Failed to build " + pkg)
}
_build()
})
}
$stop()

View File

@@ -21,7 +21,6 @@ var scope = null
var deep = false
var target_triple = null
var i = 0
var resolved = null
for (i = 0; i < length(args); i++) {
if (args[i] == '--deep') {
@@ -206,13 +205,7 @@ if (scope == 'shop') {
// Single package
locator = scope
// Resolve local paths
if (locator == '.' || starts_with(locator, './') || starts_with(locator, '../') || fd.is_dir(locator)) {
resolved = fd.realpath(locator)
if (resolved) {
locator = resolved
}
}
locator = shop.resolve_locator(locator)
if (deep) {
// Gather all dependencies