// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. 'use strict'; var fs = require('fs'); var fse = require('fs-extra'); var https = require('https'); var path = require('path'); var child_process = require('child_process'); var yaml = require('js-yaml'); var optimist = require('optimist'); var util = require('./util'); // constants var DEFAULT_REPO_PATH = 'README.md'; var DEFAULT_VERSION_NAME = 'dev'; var DEFAULT_LANGUAGE_NAME = 'en'; var THIS_FILE = path.basename(__filename); var WARNING_COMMENT = '\n\n'; // helpers function isPluginName (packageName) { return packageName.match(/cordova-plugin-.*/); } function getRepoFileURI (repoName, commit, filePath) { return 'https://raw.githubusercontent.com/' + repoName + '/' + commit + '/' + filePath; } function getRepoEditURI (repoName, commit, filePath) { return 'https://github.com/' + repoName + '/blob/' + commit + '/' + filePath; } function getLatestRelease (packageName) { var latestRelease = child_process.execSync('npm info ' + packageName + ' dist-tags.latest'); return latestRelease.toString().trim(); } function packageNameFromRepoName (repoName) { return repoName.split('/')[1]; } function getFetchedFileConfig (entry) { // get entry components var srcConfig = entry.src; var destConfig = entry.dest; // validate entry if (!srcConfig) { console.error("entry '" + entry.toString() + "' missing 'src'"); return; } if (!srcConfig.repoName) { console.error("entry '" + entry.toString() + "' missing 'repoName' in 'src'"); return; } if (!srcConfig.repoName) { console.error("entry '" + entry.toString() + "' missing 'repoName' in 'src'"); return; } if (!destConfig) { console.error("entry '" + entry.toString() + "' missing 'dest'"); return; } if (!destConfig.path) { console.error("entry '" + entry.toString() + "' missing 'path' in 'dest'"); return; } // complete src config if (!srcConfig.packageName) { srcConfig.packageName = packageNameFromRepoName(srcConfig.repoName); } if (!srcConfig.path) { srcConfig.path = DEFAULT_REPO_PATH; } if (!srcConfig.commit) { srcConfig.commit = getLatestRelease(srcConfig.packageName); } // make front matter var frontMatter = { edit_link: getRepoEditURI(srcConfig.repoName, srcConfig.commit, srcConfig.path), title: srcConfig.packageName }; // set special front matter values for plugins if (isPluginName(srcConfig.packageName)) { frontMatter.plugin_name = srcConfig.packageName; frontMatter.plugin_version = srcConfig.commit; } // set returned values var fetchedFileConfig = { frontMatter: frontMatter, downloadURI: getRepoFileURI(srcConfig.repoName, srcConfig.commit, srcConfig.path), savePath: destConfig.path }; return fetchedFileConfig; } function getFrontMatter (text) { var frontMatterString = util.getFrontMatterString(text); if (frontMatterString !== null) { return yaml.load(frontMatterString); } return {}; } function setFrontMatter (text, frontMatter, options) { var frontMatterString = yaml.dump(frontMatter, options); return util.setFrontMatterString(text, frontMatterString); } function dumpEntries (downloadPrefix, entries) { entries.forEach(function (entry) { // validate entry's dest config if (!entry.dest) { console.error("entry '" + entry.toString() + "' missing 'dest'"); return; } if (!entry.dest.path) { console.error("entry '" + entry.toString() + "' missing 'path' in 'dest'"); return; } // print the save path for the entry if (entry.dest && entry.dest.path) { var filePath = path.join(downloadPrefix, entry.dest.path); console.log(filePath); // error out on invalid entries } else { console.error('Invalid dest: ' + entry); process.exit(1); } }); } function downloadEntries (downloadPrefix, entries) { entries.forEach(function (entry) { // verify and process entry var fetchedFileConfig = getFetchedFileConfig(entry); if (!fetchedFileConfig) { process.exit(1); } // get info for fetching var fetchURI = fetchedFileConfig.downloadURI; var outFilePath = path.join(downloadPrefix, fetchedFileConfig.savePath); var outFileDir = path.dirname(outFilePath); // create directory for the file if it doesn't exist if (!fs.existsSync(outFileDir)) { fse.mkdirsSync(outFileDir); } console.log(fetchURI + ' -> ' + outFilePath); // open the file for writing var outFile = fs.createWriteStream(outFilePath); // open an HTTP request for the file https.get(fetchURI, function (response) { if (response.statusCode !== 200) { console.error('Failed to download ' + fetchURI + ': got ' + response.statusCode); process.exit(1); } // read in the response var fileContents = ''; response.setEncoding('utf8'); response.on('data', function (data) { fileContents += data; }); // process the response when it finishes response.on('end', function () { // merge new front matter and file's own front matter (if it had any) // // NOTE: // fileFrontMatter's properties should override those of newFrontMatter var newFrontMatter = fetchedFileConfig.frontMatter; var fileFrontMatter = getFrontMatter(fileContents); var mergedFrontMatter = util.mergeObjects(newFrontMatter, fileFrontMatter); // add a warning and set the merged file matter in the file var contentsOnly = util.stripFrontMatter(fileContents); contentsOnly = WARNING_COMMENT + contentsOnly; var augmentedContents = setFrontMatter(contentsOnly, mergedFrontMatter); // write out the file outFile.end(augmentedContents); }).on('error', function (e) { console.error(e); }); }); // http request }); // entries } // main function main () { // get args var argv = optimist .usage('Usage: $0 [options]') .demand('config') .demand('docsRoot') .string('version') .string('language') .boolean('dump') .describe('config', '.yml file listing fetched files') .describe('docsRoot', 'docs root directory') .describe('version', 'version in which to save the downloaded files').default('version', DEFAULT_VERSION_NAME) .describe('language', 'language in which to save the downloaded files').default('language', DEFAULT_LANGUAGE_NAME) .describe('dump', 'only print the downloaded files') .argv; var configFile = argv.config; var docsRoot = argv.docsRoot; var targetVersion = argv.version; var targetLanguage = argv.language; var printOnly = argv.dump; var downloadPrefix = path.join(docsRoot, targetLanguage, targetVersion); // validate args if (!fs.existsSync(configFile)) { console.error("Config file doesn't exist."); process.exit(); } if (!fs.existsSync(docsRoot)) { console.error("Docs root doesn't exist."); process.exit(); } // get config var fetchConfig = fs.readFileSync(configFile); var configEntries = yaml.load(fetchConfig); // just dump entries if --dump was passed if (printOnly === true) { dumpEntries(downloadPrefix, configEntries); // otherwise, fetch them } else { downloadEntries(downloadPrefix, configEntries); } } main();