286 lines
7.4 KiB
Plaintext
286 lines
7.4 KiB
Plaintext
// Module shop system for managing dependencies and mods
|
|
|
|
var io = use('io')
|
|
var toml = use('toml')
|
|
var json = use('json')
|
|
|
|
var Shop = {}
|
|
|
|
// Load shop.toml configuration
|
|
Shop.load_config = function() {
|
|
var shop_path = '.cell/shop.toml'
|
|
if (!io.exists(shop_path)) {
|
|
return null
|
|
}
|
|
|
|
var content = io.slurp(shop_path)
|
|
return toml.parse(content)
|
|
}
|
|
|
|
// Save shop.toml configuration
|
|
Shop.save_config = function(config) {
|
|
// Simple TOML writer for our needs
|
|
var lines = []
|
|
|
|
// Top-level strings
|
|
if (config.module) lines.push('module = "' + config.module + '"')
|
|
if (config.engine) lines.push('engine = "' + config.engine + '"')
|
|
if (config.entrypoint) lines.push('entrypoint = "' + config.entrypoint + '"')
|
|
|
|
// Dependencies section
|
|
if (config.dependencies && Object.keys(config.dependencies).length > 0) {
|
|
lines.push('')
|
|
lines.push('[dependencies]')
|
|
for (var key in config.dependencies) {
|
|
lines.push(key + ' = "' + config.dependencies[key] + '"')
|
|
}
|
|
}
|
|
|
|
// Aliases section
|
|
if (config.aliases && Object.keys(config.aliases).length > 0) {
|
|
lines.push('')
|
|
lines.push('[aliases]')
|
|
for (var key in config.aliases) {
|
|
lines.push(key + ' = "' + config.aliases[key] + '"')
|
|
}
|
|
}
|
|
|
|
// Replace section
|
|
if (config.replace && Object.keys(config.replace).length > 0) {
|
|
lines.push('')
|
|
lines.push('[replace]')
|
|
for (var key in config.replace) {
|
|
lines.push('"' + key + '" = "' + config.replace[key] + '"')
|
|
}
|
|
}
|
|
|
|
// Patches section
|
|
if (config.patches && Object.keys(config.patches).length > 0) {
|
|
lines.push('')
|
|
lines.push('[patches]')
|
|
for (var key in config.patches) {
|
|
lines.push(key + ' = "' + config.patches[key] + '"')
|
|
}
|
|
}
|
|
|
|
// Mods section
|
|
if (config.mods && config.mods.enabled && config.mods.enabled.length > 0) {
|
|
lines.push('')
|
|
lines.push('[mods]')
|
|
lines.push('enabled = [')
|
|
for (var i = 0; i < config.mods.enabled.length; i++) {
|
|
lines.push(' "' + config.mods.enabled[i] + '",')
|
|
}
|
|
lines.push(']')
|
|
}
|
|
|
|
io.slurpwrite('.cell/shop.toml', lines.join('\n'))
|
|
}
|
|
|
|
// Initialize .cell directory structure
|
|
Shop.init = function() {
|
|
if (!io.exists('.cell')) {
|
|
io.mkdir('.cell')
|
|
}
|
|
|
|
if (!io.exists('.cell/modules')) {
|
|
io.mkdir('.cell/modules')
|
|
}
|
|
|
|
if (!io.exists('.cell/build')) {
|
|
io.mkdir('.cell/build')
|
|
}
|
|
|
|
if (!io.exists('.cell/patches')) {
|
|
io.mkdir('.cell/patches')
|
|
}
|
|
|
|
if (!io.exists('.cell/shop.toml')) {
|
|
var default_config = {
|
|
module: "my-game",
|
|
engine: "mist/prosperon@v0.9.3",
|
|
entrypoint: "main.js",
|
|
dependencies: {},
|
|
aliases: {},
|
|
replace: {},
|
|
patches: {},
|
|
mods: {
|
|
enabled: []
|
|
}
|
|
}
|
|
Shop.save_config(default_config)
|
|
}
|
|
|
|
if (!io.exists('.cell/lock.toml')) {
|
|
io.slurpwrite('.cell/lock.toml', '# Lock file for module integrity\n')
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
// Mount modules according to the specification
|
|
Shop.mount = function() {
|
|
var config = Shop.load_config()
|
|
if (!config) {
|
|
log.error("No shop.toml found")
|
|
return false
|
|
}
|
|
|
|
// 1. Mount mods first (highest priority, prepend=1)
|
|
if (config.mods && config.mods.enabled) {
|
|
for (var i = 0; i < config.mods.enabled.length; i++) {
|
|
var mod_path = config.mods.enabled[i]
|
|
if (io.exists(mod_path)) {
|
|
io.mount(mod_path, "/", true) // prepend=true
|
|
log.console("Mounted mod: " + mod_path)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2. Self is already mounted (project root)
|
|
// This happens in prosperon.c
|
|
|
|
// 3. Mount aliases (dependencies)
|
|
if (config.dependencies) {
|
|
for (var alias in config.dependencies) {
|
|
var version = config.dependencies[alias]
|
|
var parsed = Shop.parse_locator(version)
|
|
var module_name = alias
|
|
if (parsed && parsed.version) {
|
|
module_name = alias + '@' + parsed.version
|
|
}
|
|
|
|
// Check if replaced with local path
|
|
var mount_path = '.cell/modules/' + module_name
|
|
if (config.replace && config.replace[version]) {
|
|
mount_path = config.replace[version]
|
|
}
|
|
|
|
// Try compiled version first
|
|
var compiled_path = '.cell/build/' + module_name
|
|
if (io.exists(compiled_path)) {
|
|
io.mount(compiled_path, alias, false) // Mount at alias name
|
|
log.console("Mounted compiled: " + alias + " at /" + alias + " from " + compiled_path)
|
|
} else if (io.exists(mount_path)) {
|
|
io.mount(mount_path, alias, false) // Mount at alias name
|
|
log.console("Mounted source: " + alias + " at /" + alias + " from " + mount_path)
|
|
}
|
|
|
|
// Also handle short aliases
|
|
if (config.aliases) {
|
|
for (var short_alias in config.aliases) {
|
|
if (config.aliases[short_alias] === alias) {
|
|
if (io.exists(compiled_path)) {
|
|
io.mount(compiled_path, short_alias, false)
|
|
log.console("Mounted alias: " + short_alias + " -> " + alias)
|
|
} else if (io.exists(mount_path)) {
|
|
io.mount(mount_path, short_alias, false)
|
|
log.console("Mounted alias: " + short_alias + " -> " + alias)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 4. Mount compiled modules directory
|
|
if (io.exists('.cell/build')) {
|
|
io.mount('.cell/build', "modules", false)
|
|
log.console("Mounted compiled modules at /modules")
|
|
}
|
|
|
|
// 5. Mount source modules directory
|
|
if (io.exists('.cell/modules')) {
|
|
io.mount('.cell/modules', "modules-src", false)
|
|
log.console("Mounted source modules at /modules-src")
|
|
}
|
|
|
|
// 6. Mount core if available
|
|
if (io.exists('.cell/modules/core')) {
|
|
io.mount('.cell/modules/core', "core", false)
|
|
log.console("Mounted core at /core")
|
|
}
|
|
|
|
// 6. Core is already mounted in prosperon.c
|
|
|
|
return true
|
|
}
|
|
|
|
// Parse module locator (e.g., "git.world/jj/mod@v0.6.3")
|
|
Shop.parse_locator = function(locator) {
|
|
var parts = locator.split('@')
|
|
if (parts.length !== 2) {
|
|
return null
|
|
}
|
|
|
|
return {
|
|
path: parts[0],
|
|
version: parts[1],
|
|
name: parts[0].split('/').pop()
|
|
}
|
|
}
|
|
|
|
// Add a dependency
|
|
Shop.add_dependency = function(alias, locator) {
|
|
var config = Shop.load_config()
|
|
if (!config) {
|
|
log.error("No shop.toml found")
|
|
return false
|
|
}
|
|
|
|
if (!config.dependencies) {
|
|
config.dependencies = {}
|
|
}
|
|
|
|
config.dependencies[alias] = locator
|
|
Shop.save_config(config)
|
|
return true
|
|
}
|
|
|
|
// Get the module directory for a given alias
|
|
Shop.get_module_dir = function(alias) {
|
|
var config = Shop.load_config()
|
|
if (!config || !config.dependencies || !config.dependencies[alias]) {
|
|
return null
|
|
}
|
|
|
|
var version = config.dependencies[alias]
|
|
var module_name = alias + '@' + version.split('@')[1]
|
|
|
|
// Check if replaced
|
|
if (config.replace && config.replace[version]) {
|
|
return config.replace[version]
|
|
}
|
|
|
|
return '.cell/modules/' + module_name
|
|
}
|
|
|
|
// Compile a module
|
|
Shop.compile_module = function(alias) {
|
|
var module_dir = Shop.get_module_dir(alias)
|
|
if (!module_dir) {
|
|
log.error("Module not found: " + alias)
|
|
return false
|
|
}
|
|
|
|
// TODO: Implement actual compilation
|
|
// For now, just copy .js files to .cell/build with .o extension
|
|
log.console("Would compile module: " + alias + " from " + module_dir)
|
|
return true
|
|
}
|
|
|
|
// Build all modules
|
|
Shop.build = function() {
|
|
var config = Shop.load_config()
|
|
if (!config || !config.dependencies) {
|
|
return true
|
|
}
|
|
|
|
for (var alias in config.dependencies) {
|
|
Shop.compile_module(alias)
|
|
}
|
|
|
|
return true
|
|
}
|
|
|
|
return Shop |