Advertisement
Guest User

Untitled

a guest
Jun 3rd, 2015
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.78 KB | None | 0 0
  1. /*
  2.  
  3. For each module found in the source folder
  4. replace the duplicate by a symlink to the sources & npm install external sources
  5.  
  6. */
  7.  
  8. var fs = require('fs');
  9. var childProcess = require('child_process');
  10. var path = require('path');
  11.  
  12. function collectModules(filename){
  13. var modules = [];
  14.  
  15. return fs.readdirSync(filename).map(function(name){
  16. return filename + path.sep + name;
  17. }).filter(function(filepath){
  18. return fs.statSync(filepath).isDirectory() && fs.existsSync(filepath + path.sep + 'package.json');
  19. }).map(function(modulePath){
  20. var meta = JSON.parse(fs.readFileSync(modulePath + path.sep + 'package.json'));
  21.  
  22. return {
  23. name: meta.name,
  24. meta: meta,
  25. dependencies: mergeDependencies(meta),
  26. path: modulePath
  27. };
  28. });
  29. }
  30.  
  31. function mergeDependencies(meta){
  32. var names = {};
  33.  
  34. [
  35. 'dependencies',
  36. 'devDependencies',
  37. 'optionalDependencies'
  38. ].forEach(function(dependencyType){
  39. var dependencyNames = meta[dependencyType];
  40.  
  41. if( typeof dependencyNames === 'object' ){
  42. for(var name in dependencyNames){
  43. names[name] = dependencyNames[name];
  44. }
  45. }
  46. });
  47.  
  48. return names;
  49. }
  50.  
  51. function rmdirRecursive(filename){
  52. var stat = fs.lstatSync(filename);
  53.  
  54. if( stat.isDirectory() ){
  55. fs.readdirSync(filename).map(function(name){
  56. return filename + path.sep + name;
  57. }).forEach(rmdirRecursive);
  58.  
  59. fs.rmdirSync(filename);
  60. }
  61. else if( stat.isFile() || stat.isSymbolicLink() ){
  62. fs.unlinkSync(filename);
  63. }
  64. else{
  65. throw new Error('nothing to remove');
  66. }
  67. }
  68.  
  69. var projectPath = process.cwd();
  70. var sourceFolder = path.resolve(projectPath, process.argv[2]);
  71. var sourceModules = collectModules(sourceFolder);
  72.  
  73. function findByName(array, name){
  74. var i = 0, j = array.length;
  75. for(;i<j;i++){
  76. if( array[i].name === name ) return array[i];
  77. }
  78. return null;
  79. }
  80.  
  81. function symlink(projectPath){
  82. var metaPath = projectPath + path.sep + 'package.json';
  83. var nodeModulePath = projectPath + path.sep + 'node_modules';
  84.  
  85. if( !fs.existsSync(metaPath) ){
  86. throw new Error(projectPath + ' has no package.json');
  87. }
  88.  
  89. var meta = JSON.parse(fs.readFileSync(metaPath));
  90. var moduleNames = Object.keys(mergeDependencies(meta));
  91. var usedSourceModules = sourceModules.filter(function(sourceModule){
  92. var index = moduleNames.indexOf(sourceModule.name);
  93. return index !== -1;
  94. });
  95. var toInstall = [];
  96.  
  97. // add indirect dependency (dependency of dependency) recursively
  98. function addIndirectDependency(sourceModule){
  99. Object.keys(sourceModule.dependencies).filter(function(dependency, index, dependencies){
  100. // dependency already present
  101. if( moduleNames.indexOf(dependency) !== -1 ) return;
  102. moduleNames.push(dependency);
  103.  
  104. var indirectSourceModule = findByName(sourceModules, dependency);
  105. if( indirectSourceModule ){
  106. usedSourceModules.push(indirectSourceModule);
  107. addIndirectDependency(indirectSourceModule);
  108. }
  109. else{
  110. // if local sources of subdependency is not found, install them in the top folder
  111. toInstall.push({
  112. name: dependency,
  113. value: sourceModule.dependencies[dependency]
  114. });
  115. }
  116. });
  117. }
  118.  
  119. usedSourceModules.forEach(addIndirectDependency);
  120.  
  121. usedSourceModules.forEach(function(sourceModule){
  122. var sourcePath = sourceModule.path;
  123. var modulePath = path.join(nodeModulePath, sourceModule.name);
  124. var lstat, exists = true;
  125.  
  126. try{
  127. lstat = fs.lstatSync(modulePath);
  128. }
  129. catch(e){
  130. if( e.code == 'ENOENT' ) exists = false;
  131. else throw e;
  132. }
  133.  
  134. if( exists ){
  135. if( lstat.isSymbolicLink() ){
  136. var linkPath = fs.readlinkSync(modulePath);
  137.  
  138. if( linkPath != sourcePath ){
  139. console.log('remove previous link to', linkPath);
  140. fs.unlinkSync(modulePath);
  141. }
  142. else{
  143. console.log(modulePath, 'already linked to ', sourcePath);
  144. return;
  145. }
  146. }
  147. else{
  148. console.log('rmdirRecursive', modulePath);
  149. rmdirRecursive(modulePath);
  150. }
  151. }
  152. // create a directory structure leading to the directory to put a symlink inside
  153. else{
  154. var directories = modulePath.split(path.sep), i = 0, j = directories.length -1, directory;
  155. for(;i<j;i++){
  156. directory = directories.slice(0, i + 1).join(path.sep);
  157. if( !fs.existsSync(directory) ){
  158. console.log('mkdir', directory);
  159. fs.mkdirSync(directory);
  160. }
  161. }
  162. }
  163.  
  164. console.log('linking', sourcePath, '->', modulePath);
  165. fs.symlinkSync(sourcePath, modulePath, 'dir');
  166. });
  167.  
  168. toInstall.forEach(function(installArgs){
  169. var name = installArgs.name;
  170. var value = installArgs.value;
  171. var cmd;
  172.  
  173. if( value === '*' ){
  174. cmd = name;
  175. }
  176. else if( typeof Number(value) === 'number' ){
  177. cmd = name + '@' + value;
  178. }
  179. else if( ['<', '^', '~', '>'].indexOf(value[0]) !== -1 ){
  180. cmd = name + '@' + '"' + value + '"';
  181. }
  182. else{
  183. cmd = value;
  184. }
  185.  
  186. console.log('npm install', cmd);
  187. childProcess.execSync('npm install ' + cmd);
  188. });
  189. }
  190.  
  191. if( process.env.npm_config_production !== 'true' ){
  192. symlink(projectPath);
  193. }
  194.  
  195. process.exit();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement