// cell install - Install a package to the shop // // Usage: // cell install Install a package and its dependencies // cell install . Install current directory package // // Options: // --target 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 [options]") log.console("") log.console("Options:") log.console(" --target 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 for (i = 0; i < length(args); i++) { if (args[i] == '--target' || args[i] == '-t') { if (i + 1 < length(args)) { target_triple = args[++i] } else { 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') { recursive = true } else if (args[i] == '--help' || args[i] == '-h') { log.console("Usage: cell install [options]") log.console("") log.console("Install a package and its dependencies to the shop.") log.console("") log.console("Options:") log.console(" --target 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() } else if (!starts_with(args[i], '-')) { locator = args[i] } } if (!locator && !recursive) { log.console("Usage: cell install ") $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 } } var cwd = fd.realpath('.') // If -r flag, find all packages recursively and install each if (recursive) { if (!locator) { locator = '.' } resolved = fd.realpath(locator) if (!resolved || !fd.is_dir(resolved)) { log.error(`${locator} is not a directory`) $stop() } locators = filter(pkg.find_packages(resolved), function(p) { return p != cwd }) if (length(locators) == 0) { log.console("No packages found in " + resolved) $stop() } log.console(`Found ${text(length(locators))} package(s) in ${resolved}`) } // 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)" : "")) }) $stop() } 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) } disruption { push(skipped_packages, loc) 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) $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) $stop()