#!/bin/sh ':' //; exec "$(command -v nodejs || command -v node)" "$0" "$@" "use strict"; /* * Copies over the files from an installed yum package into a specified folder * along with the files of all its dependency packages * * Requirements: * nodejs (0.10.x and above) (sudo yum install nodejs) * repoquery (sudo yum install yum-utils) * npm (sudo yum install npm) * Nodejs dependencies: * fs-extra (npm install --save fs-extra) * async (npm install --save fs-extra * * Warning: THIS WILL COPY ALL DEPENDENCIES, including packages like bash, vim etc. * which is most often NOT something you would want. To prevent this from happening, specify * an optional argument (see excluded_package_list below) containing a line separated list * of packages you need ignored. * * Usage: copy_yum_repo [excluded_package_list] * where: * package_name -- (required) name of package you want to copy over * destination_folder -- (required) path to destination folder where the files need to be copied over * excluded_package_list -- (optional but highly recommended) path to a file containing a line separated * list of packages to ignore during copy (possibly like bash, glibc etc.) */ var fs = require('fs-extra'); var child_process = require('child_process'); var async = require('async'); var path = require('path'); async.waterfall([ function (callback) { // Argument parsing and initialization var errrorMsg; // Fetch commandline arguments if (process.argv.length < 4){ errrorMsg = "Usage: copy_yum_repo [excluded_package_list]"; callback(errrorMsg, null); } // If we got here then commandline args are fine // Proceed by passing that to the next step callback(null, process.argv); }, function (commandlineArgs, callback) { // We next open the file containing list of packages already // found in RHEL minimal and extract the package names var excludedPackages = {}; var errorMsg; if (commandlineArgs.length == 5) { console.log("Parsing excluded packages listed in: " + commandlineArgs[4]); try { fs.readFile(commandlineArgs[4], function (err, data) { data.toString().split('\n').forEach( function (line) { var packageDetails, packageName; packageDetails = line.split(/\s+/); packageName = packageDetails[0]; if (packageName.length != 0) { excludedPackages[packageName] = true; } }); }); // Move on to the next phase callback(null, commandlineArgs, excludedPackages); } catch (e) { errorMsg = "Unable to open excluded package list: \n" + e; callback(errorMsg, null); } } }, function (commandlineArgs, excludedPackages, callback) { // We find the dependencies of the given package by running 'repoquery --requires --recursive --resolve ' console.log("Querying dependencies of: " + process.argv[2]); var dependencyQueryHandler = { output: '', dependencies: {}, onOutput: function (output) { this.output += output; }, onError: function (errorInfo) { }, onComplete: function () { // We can now process the dependencies var self = this; var outputLines = this.output.split('\n').forEach(function (line) { var re = /^(.*)-.*:.*.x86_64/; var regexResults = line.match(re); var dependencyName; if(regexResults){ dependencyName = regexResults[1]; // Check if this is one of the excluded packages if (!(dependencyName in excludedPackages)) { self.dependencies[dependencyName] = true; } } }); // Note that the main library whose dependencies we have listed // also needs to have its files copied over self.dependencies[process.argv[2]] = true; callback(null, commandlineArgs, self.dependencies); } }; try { // repoquery --requires --recursive --resolve var deplistOut = child_process.spawn('repoquery', ['--requires', '--recursive', '--resolve', process.argv[2]]); deplistOut.stdout.on('data', function (data) { dependencyQueryHandler.onOutput(data); }); deplistOut.on('close', function (errCode) { dependencyQueryHandler.onComplete(); }); deplistOut.stderr.on('data', function (error) { dependencyQueryHandler.onError(error); }); } catch (e) { callback("Unable to do repoquery: " + e, null); } }, function (commandlineArgs, dependencies, callback){ // Here we process the files in each package and copy them over // to the specified folder console.log("Listing files from dependency packages"); var numDeps = dependencies.length; var filesToCopy = {}; var repoQuery; var errorMsg; // We make a consolidated set containing all the files // that need to be copied async.forEachOf(dependencies, function (value, dep, forEachCallback) { if ( dependencies.hasOwnProperty(dep) ) { try { repoQuery = child_process.spawn('repoquery', ['-l', dep]); repoQuery.stdout.on('data', function (data) { data.toString().split('\n').forEach( function(line) { //if(line.trim().length > 0){ filesToCopy[line] = true; //} }); }); repoQuery.on('close', function (errCode) { forEachCallback(); }); repoQuery.stderr.on('data', function (error) { }); } catch (e) { forEachCallback("Unable to call repoquery: " + e); } } }, function (err) { if (err) { callback(err, null); } else { callback(null, commandlineArgs, filesToCopy); } }); }, function (commandlineArgs, filesToCopy, callback) { // Here we actually make the copies of all files console.log('Copying dependency files into destination folder'); var re = /\/usr\/(.*)/; var symbolicLinksNeeded = []; var destDir = commandlineArgs[3]; async.forEachOf(filesToCopy, function (value, file, forEachCallback) { var pathMatches; pathMatches = file.match(re); if(!pathMatches){ if(file.trim().length !== 0){ console.error('Error: Dont know how to copy: ' + file + '. Skipping.'); } forEachCallback(null); } else { var destPath = path.join(destDir, pathMatches[1]); console.log("Attempting file: " + file); fs.lstat(file, function (err, stat) { if (err) { console.error("Error: No such file: " + file + ". Skipping..."); forEachCallback(null); } else if(stat.isDirectory()) { forEachCallback(null); } else if(stat.isFile() /*|| stat.isSymbolicLink()*/) { console.log('Copying: ' + file + ' to ' + destPath); fs.copy(file, destPath, function (err) { if(err){ console.error('Error: Unable to copy file: ' + file); } forEachCallback(null); }); } else { console.error('Error: Unhandled file type: ' + file); forEachCallback(null); } }); } }, function (err) { if (err) { callback(err, null); } else { callback(null, "Done"); } }); } ], function (err, result) { if(err){ console.error(err); process.exit(1); }else if(result){ console.log(result); process.exit(0); } });