Skip to content

Instantly share code, notes, and snippets.

@balajeerc
Last active January 3, 2016 18:08
Show Gist options
  • Save balajeerc/29d731a5c0686eb53bf6 to your computer and use it in GitHub Desktop.
Save balajeerc/29d731a5c0686eb53bf6 to your computer and use it in GitHub Desktop.
Nodejs script that copies files of a specified yum package along with those of its dependencies (queried recursively) into a folder
#!/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 <package_name> <path_to_folder> [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 <package_name> <path_to_folder> [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 <libname>'
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);
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment