Last active
January 3, 2016 18:08
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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