better commands
This commit is contained in:
17
add.ce
17
add.ce
@@ -1,17 +1,26 @@
|
|||||||
// cell get <locator> [alias] - Add and install a package with its dependencies
|
// cell add <locator> [alias] - Add and install a package with its dependencies
|
||||||
|
|
||||||
var shop = use('internal/shop')
|
var shop = use('internal/shop')
|
||||||
|
var fd = use('fd')
|
||||||
|
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
log.console("Usage: cell get <locator> [alias]")
|
log.console("Usage: cell add <locator> [alias]")
|
||||||
log.console("Examples:")
|
log.console("Examples:")
|
||||||
log.console(" cell get gitea.pockle.world/john/prosperon@main")
|
log.console(" cell add gitea.pockle.world/john/prosperon@main")
|
||||||
log.console(" cell get github.com/user/repo@v1.0.0 myalias")
|
log.console(" cell add github.com/user/repo@v1.0.0 myalias")
|
||||||
$stop()
|
$stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var locator = args[0]
|
var locator = args[0]
|
||||||
|
|
||||||
|
// Resolve relative paths to absolute paths
|
||||||
|
if (locator == '.' || locator.startsWith('./') || locator.startsWith('../') || fd.is_dir(locator)) {
|
||||||
|
var resolved = fd.realpath(locator)
|
||||||
|
if (resolved) {
|
||||||
|
locator = resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
var alias = args.length > 1 ? args[1] : null
|
var alias = args.length > 1 ? args[1] : null
|
||||||
|
|
||||||
shop.get(locator, alias)
|
shop.get(locator, alias)
|
||||||
|
|||||||
122
clone.ce
Normal file
122
clone.ce
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
// cell clone <origin> <path>
|
||||||
|
// Clones a cell package <origin> to the local <path>, and links it.
|
||||||
|
|
||||||
|
var shop = use('internal/shop')
|
||||||
|
var link = use('link')
|
||||||
|
var fd = use('fd')
|
||||||
|
var http = use('http')
|
||||||
|
var miniz = use('miniz')
|
||||||
|
|
||||||
|
if (args.length < 2) {
|
||||||
|
log.console("Usage: cell clone <origin> <path>")
|
||||||
|
log.console("Clones a cell package to a local path and links it.")
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var origin = args[0]
|
||||||
|
var target_path = args[1]
|
||||||
|
|
||||||
|
// Resolve target path to absolute
|
||||||
|
if (target_path == '.' || target_path.startsWith('./') || target_path.startsWith('../')) {
|
||||||
|
var resolved = fd.realpath(target_path)
|
||||||
|
if (resolved) {
|
||||||
|
target_path = resolved
|
||||||
|
} else {
|
||||||
|
// Path doesn't exist yet, resolve relative to cwd
|
||||||
|
var cwd = fd.realpath('.')
|
||||||
|
if (target_path == '.') {
|
||||||
|
target_path = cwd
|
||||||
|
} else if (target_path.startsWith('./')) {
|
||||||
|
target_path = cwd + target_path.substring(1)
|
||||||
|
} else if (target_path.startsWith('../')) {
|
||||||
|
// Go up one directory from cwd
|
||||||
|
var parent = cwd.substring(0, cwd.lastIndexOf('/'))
|
||||||
|
target_path = parent + target_path.substring(2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if target already exists
|
||||||
|
if (fd.is_dir(target_path)) {
|
||||||
|
log.console("Error: " + target_path + " already exists")
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.console("Cloning " + origin + " to " + target_path + "...")
|
||||||
|
|
||||||
|
// Get the latest commit
|
||||||
|
var info = shop.resolve_package_info(origin)
|
||||||
|
if (!info || info == 'local') {
|
||||||
|
log.console("Error: " + origin + " is not a remote package")
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update to get the commit hash
|
||||||
|
var update_result = shop.update(origin)
|
||||||
|
if (!update_result) {
|
||||||
|
log.console("Error: Could not fetch " + origin)
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch and extract to the target path
|
||||||
|
var lock = shop.load_lock()
|
||||||
|
var entry = lock[origin]
|
||||||
|
if (!entry || !entry.commit) {
|
||||||
|
log.console("Error: No commit found for " + origin)
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var download_url = shop.get_download_url(origin, entry.commit)
|
||||||
|
log.console("Downloading from " + download_url)
|
||||||
|
|
||||||
|
try {
|
||||||
|
var zip_blob = http.fetch(download_url)
|
||||||
|
|
||||||
|
// Extract zip to target path
|
||||||
|
var zip = miniz.read(zip_blob)
|
||||||
|
if (!zip) {
|
||||||
|
log.console("Error: Failed to read zip archive")
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create target directory
|
||||||
|
fd.mkdir(target_path)
|
||||||
|
|
||||||
|
var count = zip.count()
|
||||||
|
for (var i = 0; i < count; i++) {
|
||||||
|
if (zip.is_directory(i)) continue
|
||||||
|
var filename = zip.get_filename(i)
|
||||||
|
var parts = filename.split('/')
|
||||||
|
if (parts.length <= 1) continue
|
||||||
|
|
||||||
|
// Skip the first directory (repo-commit prefix)
|
||||||
|
parts.shift()
|
||||||
|
var rel_path = parts.join('/')
|
||||||
|
var full_path = target_path + '/' + rel_path
|
||||||
|
var dir_path = full_path.substring(0, full_path.lastIndexOf('/'))
|
||||||
|
|
||||||
|
// Ensure directory exists
|
||||||
|
if (!fd.is_dir(dir_path)) {
|
||||||
|
fd.mkdir(dir_path)
|
||||||
|
}
|
||||||
|
fd.slurpwrite(full_path, zip.slurp(filename))
|
||||||
|
}
|
||||||
|
|
||||||
|
log.console("Extracted to " + target_path)
|
||||||
|
|
||||||
|
// Link the origin to the cloned path
|
||||||
|
link.add(origin, target_path, shop)
|
||||||
|
log.console("Linked " + origin + " -> " + target_path)
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
log.console("Error: " + e.message)
|
||||||
|
if (e.stack) log.console(e.stack)
|
||||||
|
}
|
||||||
|
|
||||||
|
$stop()
|
||||||
54
install.ce
54
install.ce
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
var shop = use('internal/shop')
|
var shop = use('internal/shop')
|
||||||
var build = use('build')
|
var build = use('build')
|
||||||
|
var fd = use('fd')
|
||||||
|
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
log.console("Usage: cell install <locator>")
|
log.console("Usage: cell install <locator>")
|
||||||
@@ -12,21 +13,50 @@ if (args.length < 1) {
|
|||||||
|
|
||||||
var locator = args[0]
|
var locator = args[0]
|
||||||
|
|
||||||
|
// Resolve relative paths to absolute paths
|
||||||
|
// Local paths like '.' or '../foo' need to be converted to absolute paths
|
||||||
|
if (locator == '.' || locator.startsWith('./') || locator.startsWith('../') || fd.is_dir(locator)) {
|
||||||
|
var resolved = fd.realpath(locator)
|
||||||
|
if (resolved) {
|
||||||
|
locator = resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
log.console("Installing " + locator + "...")
|
log.console("Installing " + locator + "...")
|
||||||
if (!shop.update(locator)) {
|
|
||||||
log.console("Failed to install " + locator)
|
var pkg = use('package')
|
||||||
$stop()
|
|
||||||
return
|
// Recursive install function that handles dependencies
|
||||||
|
function install_package(pkg_locator, visited) {
|
||||||
|
if (visited[pkg_locator]) return
|
||||||
|
visited[pkg_locator] = true
|
||||||
|
|
||||||
|
// First, add to lock.toml
|
||||||
|
shop.update(pkg_locator)
|
||||||
|
|
||||||
|
// Extract/symlink the package so we can read its cell.toml
|
||||||
|
shop.extract(pkg_locator)
|
||||||
|
|
||||||
|
// Now get direct dependencies and install them first
|
||||||
|
try {
|
||||||
|
var deps = pkg.dependencies(pkg_locator)
|
||||||
|
if (deps) {
|
||||||
|
for (var alias in deps) {
|
||||||
|
var dep_locator = deps[alias]
|
||||||
|
log.console("Installing dependency " + dep_locator)
|
||||||
|
install_package(dep_locator, visited)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Package might not have dependencies or cell.toml issue
|
||||||
|
log.console("Warning: Could not read dependencies for " + pkg_locator + ": " + e.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build the package after all dependencies are installed
|
||||||
|
build.build_package(pkg_locator)
|
||||||
}
|
}
|
||||||
|
|
||||||
var deps = shop.list_packages(locator)
|
install_package(locator, {})
|
||||||
for (var dep of deps) {
|
|
||||||
log.console("Installing dependency " + dep)
|
|
||||||
shop.update(dep)
|
|
||||||
build.build_package(dep)
|
|
||||||
}
|
|
||||||
|
|
||||||
build.build_package(locator)
|
|
||||||
log.console("Installed " + locator)
|
log.console("Installed " + locator)
|
||||||
|
|
||||||
$stop()
|
$stop()
|
||||||
|
|||||||
@@ -224,6 +224,10 @@ function get_canonical_package(alias, package_context) {
|
|||||||
// guaranteed to be validated
|
// guaranteed to be validated
|
||||||
function safe_package_path(pkg)
|
function safe_package_path(pkg)
|
||||||
{
|
{
|
||||||
|
// For absolute paths, replace / with _ to create a valid directory name
|
||||||
|
// Also replace @ with _
|
||||||
|
if (pkg && pkg.startsWith('/'))
|
||||||
|
return pkg.replaceAll('/', '_').replaceAll('@', '_')
|
||||||
return pkg.replaceAll('@', '_')
|
return pkg.replaceAll('@', '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -459,7 +463,15 @@ function resolve_locator(path, ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check in ctx package
|
// check in ctx package
|
||||||
var ctx_path = get_packages_dir() + '/' + safe_package_path(ctx) + '/' + path
|
// If ctx is an absolute path (starts with /), use it directly
|
||||||
|
// Otherwise, look it up in the packages directory
|
||||||
|
var ctx_dir
|
||||||
|
if (ctx.startsWith('/')) {
|
||||||
|
ctx_dir = ctx
|
||||||
|
} else {
|
||||||
|
ctx_dir = get_packages_dir() + '/' + safe_package_path(ctx)
|
||||||
|
}
|
||||||
|
var ctx_path = ctx_dir + '/' + path
|
||||||
|
|
||||||
if (fd.is_file(ctx_path)) {
|
if (fd.is_file(ctx_path)) {
|
||||||
var fn = resolve_mod_fn(ctx_path, ctx)
|
var fn = resolve_mod_fn(ctx_path, ctx)
|
||||||
@@ -818,7 +830,7 @@ function get_cache_path(pkg, commit) {
|
|||||||
|
|
||||||
function get_package_abs_dir(package)
|
function get_package_abs_dir(package)
|
||||||
{
|
{
|
||||||
return get_packages_dir() + '/' + package
|
return get_packages_dir() + '/' + safe_package_path(package)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch the latest commit hash from remote for a package
|
// Fetch the latest commit hash from remote for a package
|
||||||
@@ -1195,4 +1207,29 @@ Shop.audit_packages = function() {
|
|||||||
return bad
|
return bad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse a package locator and return info about it
|
||||||
|
// Returns { path: canonical_path, name: package_name, type: 'local'|'gitea'|null }
|
||||||
|
Shop.parse_package = function(locator) {
|
||||||
|
if (!locator) return null
|
||||||
|
|
||||||
|
// Strip version suffix if present
|
||||||
|
var clean = locator
|
||||||
|
if (locator.includes('@')) {
|
||||||
|
clean = locator.split('@')[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
var info = Shop.resolve_package_info(clean)
|
||||||
|
if (!info) return null
|
||||||
|
|
||||||
|
// Extract package name (last component of path)
|
||||||
|
var parts = clean.split('/')
|
||||||
|
var name = parts[parts.length - 1]
|
||||||
|
|
||||||
|
return {
|
||||||
|
path: clean,
|
||||||
|
name: name,
|
||||||
|
type: info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Shop
|
return Shop
|
||||||
5
link.cm
5
link.cm
@@ -20,11 +20,14 @@ function get_packages_dir() {
|
|||||||
|
|
||||||
// return the safe path for the package
|
// return the safe path for the package
|
||||||
function safe_package_path(pkg) {
|
function safe_package_path(pkg) {
|
||||||
|
// For absolute paths, replace / with _ to create a valid directory name
|
||||||
|
if (pkg && pkg.startsWith('/'))
|
||||||
|
return pkg.replaceAll('/', '_').replaceAll('@', '_')
|
||||||
return pkg.replaceAll('@', '_')
|
return pkg.replaceAll('@', '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
function get_package_abs_dir(package) {
|
function get_package_abs_dir(package) {
|
||||||
return get_packages_dir() + '/' + package
|
return get_packages_dir() + '/' + safe_package_path(package)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ensure_dir(path) {
|
function ensure_dir(path) {
|
||||||
|
|||||||
19
package.cm
19
package.cm
@@ -4,9 +4,26 @@ var fd = use('fd')
|
|||||||
var toml = use('toml')
|
var toml = use('toml')
|
||||||
var os = use('os')
|
var os = use('os')
|
||||||
|
|
||||||
|
// Convert package name to a safe directory name
|
||||||
|
// For absolute paths (local packages), replace / with _
|
||||||
|
// For remote packages, keep slashes as they use nested directories
|
||||||
|
function safe_package_path(pkg) {
|
||||||
|
if (!pkg) return pkg
|
||||||
|
if (pkg.startsWith('/'))
|
||||||
|
return pkg.replaceAll('/', '_').replaceAll('@', '_')
|
||||||
|
return pkg.replaceAll('@', '_')
|
||||||
|
}
|
||||||
|
|
||||||
function get_path(name)
|
function get_path(name)
|
||||||
{
|
{
|
||||||
return os.global_shop_path + '/packages/' + name
|
// If name is null, return the current project directory
|
||||||
|
if (!name)
|
||||||
|
return fd.realpath('.')
|
||||||
|
// If name is already an absolute path, use it directly
|
||||||
|
if (name.startsWith('/'))
|
||||||
|
return name
|
||||||
|
// Remote packages use nested directories, so don't transform slashes
|
||||||
|
return os.global_shop_path + '/packages/' + name.replaceAll('@', '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
package.load_config = function(name)
|
package.load_config = function(name)
|
||||||
|
|||||||
13
remove.ce
13
remove.ce
@@ -1,6 +1,7 @@
|
|||||||
// cell remove <alias|path> - Remove a package from dependencies or shop
|
// cell remove <alias|path> - Remove a package from dependencies or shop
|
||||||
|
|
||||||
var shop = use('internal/shop')
|
var shop = use('internal/shop')
|
||||||
|
var fd = use('fd')
|
||||||
|
|
||||||
if (args.length < 1) {
|
if (args.length < 1) {
|
||||||
log.console("Usage: cell remove <alias|path>")
|
log.console("Usage: cell remove <alias|path>")
|
||||||
@@ -8,6 +9,16 @@ if (args.length < 1) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
shop.remove(args[0])
|
var pkg = args[0]
|
||||||
|
|
||||||
|
// Resolve relative paths to absolute paths
|
||||||
|
if (pkg == '.' || pkg.startsWith('./') || pkg.startsWith('../') || fd.is_dir(pkg)) {
|
||||||
|
var resolved = fd.realpath(pkg)
|
||||||
|
if (resolved) {
|
||||||
|
pkg = resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
shop.remove(pkg)
|
||||||
|
|
||||||
$stop()
|
$stop()
|
||||||
|
|||||||
81
search.ce
Normal file
81
search.ce
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
// cell search <query>
|
||||||
|
// Searches for packages matching <query>, or actors or modules within them.
|
||||||
|
|
||||||
|
var shop = use('internal/shop')
|
||||||
|
var pkg = use('package')
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
log.console("Usage: cell search <query>")
|
||||||
|
log.console("Searches for packages, actors, or modules matching the query.")
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = args[0].toLowerCase()
|
||||||
|
var found_packages = []
|
||||||
|
var found_modules = []
|
||||||
|
var found_actors = []
|
||||||
|
|
||||||
|
// Search through all installed packages
|
||||||
|
var packages = shop.list_packages()
|
||||||
|
|
||||||
|
for (var package_name of packages) {
|
||||||
|
// Check if package name matches
|
||||||
|
if (package_name.toLowerCase().includes(query)) {
|
||||||
|
found_packages.push(package_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search modules and actors within the package
|
||||||
|
try {
|
||||||
|
var modules = pkg.list_modules(package_name)
|
||||||
|
for (var mod of modules) {
|
||||||
|
if (mod.toLowerCase().includes(query)) {
|
||||||
|
found_modules.push(package_name + ':' + mod)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var actors = pkg.list_programs(package_name)
|
||||||
|
for (var actor of actors) {
|
||||||
|
if (actor.toLowerCase().includes(query)) {
|
||||||
|
found_actors.push(package_name + ':' + actor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Skip packages that can't be read
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print results
|
||||||
|
var total = found_packages.length + found_modules.length + found_actors.length
|
||||||
|
|
||||||
|
if (total == 0) {
|
||||||
|
log.console("No results found for '" + query + "'")
|
||||||
|
} else {
|
||||||
|
log.console("Found " + text(total) + " result(s) for '" + query + "':")
|
||||||
|
log.console("")
|
||||||
|
|
||||||
|
if (found_packages.length > 0) {
|
||||||
|
log.console("Packages:")
|
||||||
|
for (var p of found_packages) {
|
||||||
|
log.console(" " + p)
|
||||||
|
}
|
||||||
|
log.console("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_modules.length > 0) {
|
||||||
|
log.console("Modules:")
|
||||||
|
for (var m of found_modules) {
|
||||||
|
log.console(" " + m)
|
||||||
|
}
|
||||||
|
log.console("")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found_actors.length > 0) {
|
||||||
|
log.console("Actors:")
|
||||||
|
for (var a of found_actors) {
|
||||||
|
log.console(" " + a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$stop()
|
||||||
33
unlink.ce
Normal file
33
unlink.ce
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// cell unlink <origin>
|
||||||
|
// Unlinks <origin> from its <target> from a previous link.
|
||||||
|
|
||||||
|
var link = use('link')
|
||||||
|
var shop = use('internal/shop')
|
||||||
|
|
||||||
|
if (args.length < 1) {
|
||||||
|
log.console("Usage: cell unlink <origin>")
|
||||||
|
log.console("Removes a link and restores the original package.")
|
||||||
|
$stop()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var origin = args[0]
|
||||||
|
|
||||||
|
if (link.remove(origin)) {
|
||||||
|
log.console("Removed link for " + origin)
|
||||||
|
|
||||||
|
// Try to restore the original package
|
||||||
|
log.console("Restoring " + origin + "...")
|
||||||
|
try {
|
||||||
|
shop.fetch(origin)
|
||||||
|
shop.extract(origin)
|
||||||
|
log.console("Restored " + origin)
|
||||||
|
} catch (e) {
|
||||||
|
log.console("Could not restore: " + e.message)
|
||||||
|
log.console("Run 'cell update " + origin + "' to restore")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log.console("No link found for " + origin)
|
||||||
|
}
|
||||||
|
|
||||||
|
$stop()
|
||||||
21
update.ce
21
update.ce
@@ -9,6 +9,7 @@
|
|||||||
// cell update <package> - Update a specific package
|
// cell update <package> - Update a specific package
|
||||||
|
|
||||||
var shop = use('internal/shop')
|
var shop = use('internal/shop')
|
||||||
|
var fd = use('fd')
|
||||||
|
|
||||||
var target_pkg = null
|
var target_pkg = null
|
||||||
|
|
||||||
@@ -26,6 +27,13 @@ for (var i = 0; i < args.length; i++) {
|
|||||||
$stop()
|
$stop()
|
||||||
} else if (!args[i].startsWith('-')) {
|
} else if (!args[i].startsWith('-')) {
|
||||||
target_pkg = args[i]
|
target_pkg = args[i]
|
||||||
|
// Resolve relative paths to absolute paths
|
||||||
|
if (target_pkg == '.' || target_pkg.startsWith('./') || target_pkg.startsWith('../') || fd.is_dir(target_pkg)) {
|
||||||
|
var resolved = fd.realpath(target_pkg)
|
||||||
|
if (resolved) {
|
||||||
|
target_pkg = resolved
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,9 +45,16 @@ function update_and_fetch(pkg)
|
|||||||
|
|
||||||
var new_entry = shop.update(pkg)
|
var new_entry = shop.update(pkg)
|
||||||
|
|
||||||
if (new_entry && new_entry.commit) {
|
if (new_entry) {
|
||||||
log.console(" " + pkg + " " + old_commit.substring(0, 8) + " -> " + new_entry.commit.substring(0, 8))
|
if (new_entry.commit) {
|
||||||
shop.fetch(pkg)
|
var old_str = old_commit ? old_commit.substring(0, 8) : "(new)"
|
||||||
|
log.console(" " + pkg + " " + old_str + " -> " + new_entry.commit.substring(0, 8))
|
||||||
|
shop.fetch(pkg)
|
||||||
|
} else {
|
||||||
|
// Local package - just ensure symlink is correct
|
||||||
|
log.console(" " + pkg + " (local)")
|
||||||
|
}
|
||||||
|
shop.extract(pkg)
|
||||||
shop.build_package_scripts(pkg)
|
shop.build_package_scripts(pkg)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user