cocos_lib/cmake/scripts/plugins_parser.js

271 lines
9.8 KiB

const fs = require('fs');
const path = require('path');
const version_parser = require('./plugin_support/plugin_cfg');
const MAX_SEARCH_LEVEL = 7;
const CC_PLUGIN_JSON_STR = 'cc_plugin.json';
const node_path = process.argv.shift();
const script_path = process.argv.shift();
const search_path_input_file = process.argv.shift();
const plugin_cmake_output_file = process.argv.shift();
const PLATFORM_NAME_FROM_CMAKE = process.argv.shift();
const PROJ_SEARCH_PATHS = fs.readFileSync(search_path_input_file, 'utf8').
split('\n').
map(x => x.trim()).
filter(x => x.length > 0 && !x.startsWith("#"));
const cc_config_json_list = [];
function search_cc_config_json_levels(dir, depth) {
// console.log(`[searching plugins] search dir ${dir}`);
if (depth > MAX_SEARCH_LEVEL) return;
const st = fs.statSync(dir);
if (!st.isDirectory()) return;
let subfiles = fs.readdirSync(dir);
let subdirs = [];
for (let item of subfiles) {
if (item === "." || item === "..") continue;
let fp = path.join(dir, item);
const subst = fs.statSync(fp);
if (subst.isFile() && item === CC_PLUGIN_JSON_STR) {
cc_config_json_list.push(dir);
return;
}
if (subst.isDirectory()) {
subdirs.push(fp);
}
}
for (let sd of subdirs) {
search_cc_config_json_levels(sd, depth + 1);
}
}
for (let searchPath of PROJ_SEARCH_PATHS) {
if (!fs.existsSync(searchPath)) {
console.log(`[searching plugins] directory ${searchPath} does not exist`);
continue;
}
search_cc_config_json_levels(searchPath, 1);
}
if (cc_config_json_list.length === 0) {
console.log("[searching plugins] no plugins found!");
process.exit(0)
}
for (let dir of cc_config_json_list) {
console.log(`[searching plugins] plugin dir found: ${dir}`)
}
function read_engine_version() {
const pkg = path.join(__dirname, '../../../package.json');
return require(pkg).version;
}
function parse_package_dependency(info) {
let pkgs = [];
for (let m of info.modules) {
if (m.platforms && m.platforms.indexOf(PLATFORM_NAME_FROM_CMAKE) < 0) {
continue;
}
pkgs.push({ target: m.target, depends: typeof m.depends === 'string' ? [m.depends] : (m.depends || []) });
}
return pkgs;
}
function get_property_variants(obj, ...names) {
for (let n of names) {
if (obj.hasOwnProperty(n)) {
return obj[n];
}
if (n.indexOf('_') >= 0) {
const k = n.replace(/_/g, '-');
if (obj.hasOwnProperty(k)) {
return obj[k];
}
}
if (n.indexOf('-') >= 0) {
const k = n.replace(/-/g, '_');
if (obj.hasOwnProperty(k)) {
return obj[k];
}
}
}
return undefined;
}
function test_enable_by_configurations(config) {
const support_platforms = get_property_variants(config, "platforms") || [];
const enabled_default = get_property_variants(config, "enable", "enabled");
const enable_all = enabled_default === undefined ? true : enabled_default;
const disable_all = (get_property_variants(config, "disable", "disabled") || false) || !enable_all;
const disabled_platforms = get_property_variants(config, "disable-by-platforms", "disabled-by-platforms") || [];
const engine_version_value = get_property_variants(config, "engine-version");
if (disable_all) {
// all disabled
console.log(` plugin is disabled.`);
return false;
}
if (support_platforms.length > 0 && support_platforms.indexOf(PLATFORM_NAME_FROM_CMAKE) < 0) {
// unsupported platform
console.log(` plugin is not supported by current platform ${PLATFORM_NAME_FROM_CMAKE}.`);
return false;
}
if (disabled_platforms.indexOf(PLATFORM_NAME_FROM_CMAKE) > -1) {
// disable by user settings
console.log(` plugin is disabled by setting.`);
return false;
}
const ENGINE_VERSION = read_engine_version().replace(/^(v|V)/, '');
try {
const version_filter = version_parser.parse(engine_version_value);
const version_valid = version_filter.match(ENGINE_VERSION);
if (!version_valid) {
console.warn(` Engine version '${ENGINE_VERSION}' mismatch '${engine_version_value}'`);
}
} catch (e) {
console.error(` Failed to parse 'engine-version', value: '${engine_version_value}'`);
console.error(e);
return false;
}
return true;
}
function validate_cc_plugin_json_format(tag, content) {
const field_required = (obj, field_name) => {
if (Object.hasOwnProperty(obj, field_name)) {
console.warn(`${tag} field '${field_name}' is not set`);
return false;
}
return true;
}
const required_fields = ["name", "version", "engine-version", "author", "description", "modules", "platforms"];
for (const f of required_fields) {
if (!field_required(content, f)) {
return false;
}
}
const modules = content["modules"];
if (modules.length == 0) {
console.warn(`${tag} modules field is empty`);
return false;
}
for (let m of modules) {
const mod_fields = ["target"];
for (const f of mod_fields) {
if (!field_required(m, f)) {
console.warn(`${tag} module field ${f} is not set`);
return false;
}
}
}
return true;
}
function add_search_path_suffix(dir, platform) {
if (platform.match(/^android/i)) {
return [`${dir}/android/\${ANDROID_ABI}`, `${dir}/android`];
} else if (platform.match(/^win/i)) {
return [`${dir}/windows/x86_64`, `${dir}/windows`];
} else if (platform.match(/^iphonesimulator/i)) {
return [`${dir}/iphonesimulator`, `${dir}/ios`];
} else if (platform.match(/^ios/i)) {
return [`${dir}/ios`];
} else if (platform.match(/^mac/i) || platform.match(/^darwin/i)) {
return [`${dir}/mac/\${CMAKE_SYSTEM_PROCESSOR}`, `${dir}/mac`];
} else {
console.warn(`Don't knowm suffix for '${platform}`)
return [];
}
}
console.log(`Engine version: ${read_engine_version()}`);
/// Generate Pre-AutoLoadPlugins.cmake
let output_lines = ["# plugins found & enabled in search path",
"# To disable automatic update of this file, set SKIP_SCAN_PLUGINS to ON.",
""];
for (let plugin_dir of cc_config_json_list) {
let load_plugins = [];
try {
let maybe_plugin_name = path.basename(plugin_dir);
console.log(`Parsing plugin directory ${maybe_plugin_name}`);
let cc_plugin_file = path.join(plugin_dir, CC_PLUGIN_JSON_STR);
let cc_plugin_content = fs.readFileSync(cc_plugin_file, { encoding: 'utf8' });
let cc_plugin_json = JSON.parse(cc_plugin_content);
if (!validate_cc_plugin_json_format(`Parsing module ${maybe_plugin_name}:`, cc_plugin_json)) {
continue;
}
if (!test_enable_by_configurations(cc_plugin_json)) {
console.log(` ${maybe_plugin_name} disabled by configuration`);
continue;
}
const plugin_name = cc_plugin_json.name;
const module_type = get_property_variants(cc_plugin_json, "module_type")
if (module_type !== undefined && module_type !== 'release') {
console.log(` plugin ${plugin_name} is not a release, should be include or add_subdirectory in dev env.`);
continue;
}
const packages = parse_package_dependency(cc_plugin_json);
const cc_project_dir = path.dirname(plugin_cmake_output_file);
let project_to_plugin_dir = path.relative(cc_project_dir, plugin_dir).replace(/\\/g, '/');
project_to_plugin_dir = `\${CC_PROJECT_DIR}/${project_to_plugin_dir}`;
const plugin_root_path_for_platform = add_search_path_suffix(project_to_plugin_dir, PLATFORM_NAME_FROM_CMAKE);
for (let pkg of packages) {
const [target_name, target_version] = pkg.target.split('@');
output_lines.push(`set(${target_name}_ROOT\n${plugin_root_path_for_platform.map(x => ` "${x}"`).join("\n")}\n)`, "");
output_lines.push(`list(APPEND CMAKE_FIND_ROOT_PATH \${${target_name}_ROOT})`)
load_plugins = load_plugins.concat([...pkg.depends, target_name + (target_version !== undefined ? '@' + target_version : '')]);
output_lines.push(`list(APPEND CC_REGISTERED_PLUGINS`);
output_lines = output_lines.concat(` ${target_name}`);
output_lines.push(`)`);
}
let plugin_names = load_plugins.map(x => x.split(/@/));
for (let plg of plugin_names) {
output_lines.push("");
if (plg[1] && plg.length > 0) {
output_lines.push(`find_package(${plg[0]} ${plg[1]}`);
} else {
output_lines.push(`find_package(${plg[0]}`);
}
output_lines.push(` REQUIRED`);
output_lines.push(` NAMES "${plg[0]}"`);
output_lines.push(`# NO_DEFAULT_PATH`);
output_lines.push(`)`);
}
if (packages.length > 0) {
console.log(` record plugin ${plugin_name}`);
} else {
console.log(` no sub module found`);
}
} catch (e) {
console.error(`Parsing plugin directory: ${plugin_dir}`)
console.error(e);
}
}
if (cc_config_json_list.length == 0) {
console.log(`Try unlink file ${out_file}`)
if (fs.existsSync(out_file)) {
fs.unlinkSync(out_file);
}
} else {
let old_content = null;
let new_content = output_lines.join("\n") + "\n";
if (fs.existsSync(plugin_cmake_output_file)) {
old_content = fs.readFileSync(plugin_cmake_output_file);
}
if (old_content !== new_content) {
fs.writeFileSync(plugin_cmake_output_file, output_lines.join("\n") + "\n", { encoding: 'utf8' });
}
}
process.exit(0);