Cordova CLI 소스 분석 (5) – 플랫폼 추가

11611 단어 Cordovanode
플랫폼 지원을 추가하는 것은 각 플랫폼 SDK 환경을 이용하여 원본 프로젝트 파일을 만드는 것이 본질이다.그래서 모든 함수도 이 주제를 둘러싸고 전개된다.
입구는 당연히 플랫폼 함수입니다.
module.exports = function platform(command, targets, callback) {
.....
};
먼저 구체적인 원본 코드를 보지 않고 다른 몇 개의 함수를 보다
(1)module.exports.supports = function(project_root, name, callback) {
이 함수는 주로 다음 단계를 수행합니다.
//전송 매개변수 확인
//플랫폼 지원 여부 판단
//최상위 디렉터리에서platforms를 얻습니다.js에서parser 매개 변수가 지정한 플랫폼 분석 파일
//플랫폼에 의존하는 SDK가 있는지 확인
/**
 * Check Platform Support.
 *
 * Options:
 *
 *   - {String} `name` of the platform to test.
 *   - {Function} `callback` is triggered with the answer.
 *     - {Error} `e` null when a platform is supported otherwise describes error.
 */

module.exports.supports = function(project_root, name, callback) {
    // required parameters
    if (!name) throw new Error('requires a platform name parameter');
    if (!callback) throw new Error('requires a callback parameter');

    // check if platform exists
    var platform = platforms[name];
    if (!platform) {
        callback(new Error(util.format('"%s" platform does not exist', name)));
        return;
    }

    // look up platform meta-data parser
    var platformParser = platforms[name].parser;
    if (!platformParser) {
        callback(new Error(util.format('"%s" platform parser does not exist', name)));
        return;
    }

    // check for platform support
    platformParser.check_requirements(project_root, function(e) {
        // typecast String to Error
        e = (typeof e == 'string') ? new Error(e) : e;
        // typecast false Boolean to null
        e = (e) ? e : null;

        callback(e);
    });
};

(2)function call_into_create(target, projectRoot, cfg, id, version, callback, end) {
이 함수는 각 모바일 개발 플랫폼 SDK 환경에서 제공하는 원본 프로젝트 파일을 만드는 방법을 호출하여 프로젝트를 만듭니다.
function call_into_create(target, projectRoot, cfg, id, version, callback, end) {
    var output = path.join(projectRoot, 'platforms', target);

    // Check if output directory already exists.
    if (fs.existsSync(output)) {
        var err = new Error('Platform "' + target + '" already exists at "' + output + '"');
        if (callback) callback(err);
        else throw err;
    } else {
        // Make sure we have minimum requirements to work with specified platform
        events.emit('log', 'Checking if platform "' + target + '" passes minimum requirements...');
        module.exports.supports(projectRoot, target, function(err) {
            if (err) {
                if (callback) callback(err);
                else throw err;
            } else {
                // Create a platform app using the ./bin/create scripts that exist in each repo.
                // Run platform's create script
                var bin = path.join(cordova_util.libDirectory, target, id, version, 'bin', 'create');
                // 
                if(target == 'wp7') bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp7', 'bin', 'create');
                if(target == 'wp8') bin = path.join(cordova_util.libDirectory, 'wp', id, version, 'wp8', 'bin', 'create');
                var args = (target=='ios') ? '--arc' : '';
                var pkg = cfg.packageName().replace(/[^\w.]/g,'_');
                var name = cfg.name();
                var command = util.format('"%s" %s "%s" "%s" "%s"', bin, args, output, pkg, name);
                events.emit('log', 'Running bin/create for platform "' + target + '" with command: "' + command + '" (output to follow)');

                shell.exec(command, {silent:true,async:true}, function(code, create_output) {
                    events.emit('log', create_output);
                    if (code > 0) {
                        var err = new Error('An error occured during creation of ' + target + ' sub-project. ' + create_output);
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        require('../cordova').prepare(target, function(err) {
                            if (err) {
                                if (callback) callback(err);
                                else throw err;
                            } else {
                                createOverrides(projectRoot, target);
                                end(); //platform add is done by now.
                                // Install all currently installed plugins into this new platform.
                                var plugins_dir = path.join(projectRoot, 'plugins');
                                var plugins = cordova_util.findPlugins(plugins_dir);
                                var parser = new platforms[target].parser(output);
                                plugins && plugins.forEach(function(plugin) {
                                    events.emit('log', 'Installing plugin "' + plugin + '" following successful platform add of ' + target);
                                    plugman.install(target, output, path.basename(plugin), plugins_dir, { www_dir: parser.staging_dir() });
                                });
                            }
                        });
                    }
                });
            }
        });
    }
}

(3) 플랫폼으로 돌아가는 함수
module.exports = function platform(command, targets, callback) {
    var projectRoot = cordova_util.isCordova(process.cwd());
    // .cordova , cordova , ; false

    if (!projectRoot) {
        var err = new Error('Current working directory is not a Cordova-based project.');
        if (callback) callback(err);
        else throw err;
        return;
    }

    var hooks = new hooker(projectRoot);

    if (arguments.length === 0) command = 'ls';// , ls
    if (targets) {
        if (!(targets instanceof Array)) targets = [targets];// targets 
        targets.forEach(function(t) {
            if (!(t in platforms)) {
                var err = new Error('Platform "' + t + '" not recognized as core cordova platform.');
                if (callback) return callback(err);
                else throw err;
            }
        });
    } else {
        if (command == 'add' || command == 'rm') {
            var err = new Error('You need to qualify `add` or `remove` with one or more platforms!');
            if (callback) return callback(err);
            else throw err;
        }
    }

    var xml = cordova_util.projectConfig(projectRoot);// /www/config.xml
    var cfg = new cordova_util.config_parser(xml);// xml 
    var opts = {
        platforms:targets
    };

    switch(command) {
        case 'add':
            var end = n(targets.length, function() {
                hooks.fire('after_platform_add', opts, function(err) {
                    if (err) {
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        if (callback) callback();
                    }
                });
            });
            hooks.fire('before_platform_add', opts, function(err) {
                if (err) {
                    if (callback) callback(err);
                    else throw err;
                } else {
                    var config_json = config.read(projectRoot);
                    targets.forEach(function(t) {
                        lazy_load.based_on_config(projectRoot, t, function(err) {
                            if (err) {
                                if (callback) callback(err);
                                else throw err;
                            } else {
                                if (config_json.lib && config_json.lib[t]) {
                                    call_into_create(t, projectRoot, cfg, config_json.lib[t].id, config_json.lib[t].version, callback, end);
                                } else {
                                    call_into_create(t, projectRoot, cfg, 'cordova', platforms[t].version, callback, end);
                                }
                            }
                        });
                    });
                }
            });
            break;
        case 'rm':
        case 'remove':
            var end = n(targets.length, function() {
                hooks.fire('after_platform_rm', opts, function(err) {
                    if (err) {
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        if (callback) callback();
                    }
                });
            });
            hooks.fire('before_platform_rm', opts, function(err) {
                if (err) {
                    if (callback) callback(err);
                    else throw err;
                } else {
                    targets.forEach(function(target) {
                        shell.rm('-rf', path.join(projectRoot, 'platforms', target));
                        shell.rm('-rf', path.join(cordova_util.appDir(projectRoot), 'merges', target));
                        var plugins_json = path.join(projectRoot, 'plugins', target + '.json');
                        if (fs.existsSync(plugins_json)) shell.rm(plugins_json);
                        end();
                    });
                }
            });
            break;
        case 'ls':
        case 'list':
        default:
            var platforms_on_fs = cordova_util.listPlatforms(projectRoot);
            hooks.fire('before_platform_ls', function(err) {
                if (err) {
                    if (callback) callback(err);
                    else throw err;
                } else {
                    events.emit('results', (platforms_on_fs.length ? platforms_on_fs : 'No platforms added. Use `cordova platform add <platform>`.'));
                    hooks.fire('after_platform_ls', function(err) {
                        if (err) {
                            if (callback) callback(err);
                            else throw err;
                        }
                    });
                }
            });
            break;
    }
};

구조가 비교적 간단하고 매개 변수 검사를 한 다음에 서로 다른 매개 변수에 따라 서로 다른 동작을 수행한다. 유일한 설명은 switch 함수에 나타난
 var end = n(targets.length, function() {
                hooks.fire('after_platform_add', opts, function(err) {
                    if (err) {
                        if (callback) callback(err);
                        else throw err;
                    } else {
                        if (callback) callback();
                    }
                });
            });

이 함수는 node의 nCallbacks 플러그인을 사용합니다.https://npmjs.org/package/ncallbacks
공식 문서 설명은functionthatexecutesntimes입니다. 위의 코드에서 end 함수는 targets만 실행된다는 뜻입니다.length회, targets를 초과합니다.length 회 재호출end, 그 내부 함수도 다시 실행되지 않습니다. 사실은 횟수를 제한하여 플랫폼 목록이 비어 있는 후에도 잘못 실행하지 않도록 합니다.

좋은 웹페이지 즐겨찾기