dLobatog/npm2rpm

View on GitHub
bin/npm2rpm.js

Summary

Maintainability
A
50 mins
Test Coverage
#!/usr/bin/env node
// NodeJS core
const fs = require('fs');
const tmp = require('tmp');
const execSync = require('child_process').execSync;
const path = require('path');
// NPM deps
const request = require('request');
const tar = require('tar');
const npm_remote_ls = require('npm-remote-ls');
const colors = require('colors');
const npm2rpm = require('commander');
const normalizeData = require('normalize-package-data');
// Our own deps
const {npmUrl, rsplit, getCacheFilename, getRpmPackageName} = require('../lib/npm_helpers.js');
const specFileGenerator = require('../lib/spec_file_generator.js');

console.log('---- npm2rpm ----'.green.bold);
console.log('-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-'.rainbow.bgWhite);
npm2rpm
.option('-n, --name <name>', 'NodeJS module name')
.option('-v, --version <version>', 'module version in X.Y.Z format')
.option('-s, --strategy [strategy]', "Strategy to build the npm packages", /^(single|bundle)$/i)
.option('-r, --release [release]', "RPM's release", 1)
.option('-t, --template [template]', "RPM .spec template to use")
.option('-6, --use-nodejs6 [useNodejs6]', "If wanting to generate cache tarball for NodeJS 6")
.option('-o, --output [directory]', "Directory to output files to")
.option('-c, --scl [scl]', "Adds scl prefixes to spec file")
.parse(process.argv);

// If a name is not provided, then npm2rpm.name defaults to calling 'commander' name() function
if (typeof(npm2rpm.name) === 'function' || typeof(npm2rpm.version) === 'function') {
  npm2rpm.help();
}

if (npm2rpm.strategy === undefined) {
  console.log(' - Undefined strategy - defaulting to single'.bold)
  npm2rpm.strategy = 'single';
}

if (npm2rpm.template === undefined) {
  npm2rpm.template = path.join(__dirname, '..', npm2rpm.strategy + '.mustache');
}

if (npm2rpm.output === undefined) {
  console.log(' - Undefined output directory - defaulting to npm2rpm'.bold)
  npm2rpm.output = 'npm2rpm';
}

if (npm2rpm.useNodejs6 === undefined) {
  npm2rpm.useNodejs6 = false;
}

if (npm2rpm.scl === undefined) {
  npm2rpm.scl = false;
}

const url = npmUrl(npm2rpm.name, npm2rpm.version);
console.log(' - Starting npm module download: '.bold + url );
const tmpDir = createTempDir();
console.log(' - Unpacking in '.bold + tmpDir + ' ...'.bold);
const tar_stream = request.get(url).pipe(tar.extract({cwd: tmpDir}))
tar_stream.on('error', (error) => {
  console.log('ERROR'.red, '-', error.message);
  if (error.code === 'Z_DATA_ERROR') {
    console.log('Are you sure that the module name and version can be found on npmjs.org?'.bold);
  }
})
tar_stream.on('finish', () => {
  console.log(' - Finished extracting for '.bold + npm2rpm.name);
  console.log(' - Reading package.json for '.bold + npm2rpm.name);
  const npm_module = readPackageJson(path.join(tmpDir, 'package', 'package.json'),
    msg => console.warn('Warning:', msg));
  console.log(' - Finished reading package.json for '.bold + npm2rpm.name);

  const files = fs.readdirSync(path.join(tmpDir, 'package'));

  if (!fs.existsSync(npm2rpm.output)) {
    fs.mkdirSync(npm2rpm.output);
  }

  if (npm2rpm.strategy === 'bundle') {
    npm_remote_ls.config({
      development: false,
      optional: false
    });

    console.log(' - Fetching flattened list of production dependencies for '.bold + npm_module.name);
    npm_remote_ls.ls(npm_module.name, npm_module.version, true, (deps) => {
      // Dependencies come as name@version but sometimes as @name@version
      const dependencies = deps.map(dependency => rsplit(dependency, '@'));

      specfile = writeSpecFile(npm_module, files, dependencies, npm2rpm.release, npm2rpm.template, npm2rpm.output, npm2rpm.scl);

      if (dependencies.length > 0) {
        console.log(' - Generating npm cache tgz... '.bold)
        createNpmCacheTar(npm_module, npm2rpm.output, npm2rpm.useNodejs6, specfile);
      }
    });
  } else {
    writeSpecFile(npm_module, files, [], npm2rpm.release, npm2rpm.template, npm2rpm.output, npm2rpm.scl);
  }
})

function writeSpecFile(npmModule, files, dependencies, release, template, specDir, scl) {
  const content = specFileGenerator(npmModule, files, dependencies, release, template, scl);
  const filename = path.join(specDir, `${getRpmPackageName(npmModule.name)}.spec`);
  fs.writeFileSync(filename, content);
  return filename;
}

function createNpmCacheTar(npm_module, outputDir, useNodejs6, specfile) {
  const command = path.join(__dirname, 'generate_npm_tarball.sh');
  const pkg = `${npm_module.name}@${npm_module.version}`;
  const filename = path.join(outputDir, getCacheFilename(getRpmPackageName(npm_module.name), npm_module.version));
  execSync([command, pkg, filename, useNodejs6, specfile].join(' '), {stdio: [0,1,2]});
}

function createTempDir() {
  const tmpDir = tmp.dirSync({
    mode: 6644,
    prefix: 'npm2rpm-',
    keep: true
  });
  return tmpDir.name;
}

function readPackageJson(filename, warn) {
  const packageData = JSON.parse(fs.readFileSync(filename));
  normalizeData(packageData, warn);
  return packageData;
}