packages-svn.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. var fs = require('graceful-fs');
  2. var path = require('path');
  3. var Q = require('q');
  4. var semver = require('semver');
  5. var mout = require('mout');
  6. var rimraf = require('rimraf');
  7. var mkdirp = require('mkdirp');
  8. var chalk = require('chalk');
  9. var cmd = require('../lib/util/cmd');
  10. var packages = require('./packages-svn.json');
  11. var nopt = require('nopt');
  12. var options = nopt({
  13. 'force': Boolean
  14. }, {
  15. 'f': '--force'
  16. });
  17. var env = {};
  18. // Preserve the original environment
  19. mout.object.mixIn(env, process.env);
  20. function ensurePackage(admin, dir) {
  21. var promise;
  22. // If force is specified, delete folder
  23. if (options.force) {
  24. promise = Q.nfcall(rimraf, dir)
  25. .then(function () {
  26. throw new Error();
  27. });
  28. // Otherwise check if .svn is already created
  29. } else {
  30. promise = Q.nfcall(fs.stat, path.join(dir, '.svn'));
  31. }
  32. // Only create if stat failed
  33. return promise.fail(function () {
  34. // Create dir
  35. return Q.nfcall(mkdirp, dir)
  36. // Init svn repo
  37. .then(cmd.bind(null, 'svnadmin', ['create', admin]))
  38. // checkout the repo
  39. .then(cmd.bind(null, 'svn', ['checkout', 'file://' + admin, dir]))
  40. // create directory structure
  41. .then(cmd.bind(null, 'svn', ['mkdir', 'trunk'], { cwd: dir }))
  42. .then(cmd.bind(null, 'svn', ['mkdir', 'tags'], { cwd: dir }))
  43. .then(cmd.bind(null, 'svn', ['mkdir', 'branches'], { cwd: dir }))
  44. // Commit
  45. .then(function () {
  46. return cmd('svn', ['commit', '-m"Initial commit."'], {
  47. cwd: dir,
  48. env: env
  49. });
  50. })
  51. .then(function () {
  52. return dir;
  53. });
  54. });
  55. }
  56. function checkRelease(dir, release) {
  57. if (semver.valid(release)) {
  58. return cmd('svn', ['list', 'tags'], { cwd: dir })
  59. .spread(function (stdout) {
  60. return stdout.split(/\/\s*\r*\n\s*/).some(function (tag) {
  61. return semver.clean(tag) === release;
  62. });
  63. });
  64. }
  65. return cmd('svn', ['list', 'branches'], { cwd: dir })
  66. .spread(function (stdout) {
  67. return stdout.split(/\/\s*\r*\n\s*/).some(function (branch) {
  68. branch = branch.trim().replace(/^\*?\s*/, '');
  69. return branch === release;
  70. });
  71. });
  72. }
  73. function createRelease(admin, dir, release, files) {
  74. // checkout the repo
  75. return cmd('svn', ['checkout', 'file://' + admin, dir])
  76. // Attempt to delete branch, ignoring the error
  77. .then(function () {
  78. return cmd('svn', ['delete', dir + '/branches/' + release], { cwd: dir })
  79. .fail(function () {});
  80. })
  81. // Attempt to delete tag, ignoring the error
  82. .then(function () {
  83. cmd('svn', ['delete', dir + '/tags/' + release], { cwd: dir })
  84. .fail(function (err) {});
  85. })
  86. // Create files
  87. .then(function () {
  88. var promise;
  89. var promises = [];
  90. mout.object.forOwn(files, function (contents, name) {
  91. name = path.join(dir + '/trunk', name);
  92. // Convert contents to JSON if they are not a string
  93. if (typeof contents !== 'string') {
  94. contents = JSON.stringify(contents, null, ' ');
  95. }
  96. promise = Q.nfcall(mkdirp, path.dirname(name))
  97. .then(function () {
  98. return Q.nfcall(fs.writeFile, name, contents);
  99. });
  100. promises.push(promise);
  101. });
  102. return Q.all(promises);
  103. })
  104. // Stage files
  105. .then(cmd.bind(null, 'svn', ['add', '--force', '.'], { cwd: dir }))
  106. // create tag
  107. .then(function () {
  108. if (!semver.valid(release)) {
  109. return;
  110. }
  111. return cmd('svn', ['copy', dir + '/trunk', dir + '/tags/' + release], { cwd: dir });
  112. })
  113. // create branch
  114. .then(function () {
  115. if (!semver.valid(release)) {
  116. return;
  117. }
  118. return cmd('svn', ['copy', dir + '/trunk', dir + '/branches/' + release], { cwd: dir });
  119. })
  120. // commit all
  121. .then(function () {
  122. return cmd('svn', ['commit', '-m"SVN Setup'], {
  123. cwd: dir,
  124. env: env
  125. });
  126. });
  127. }
  128. var promises = [];
  129. // Process packages.json
  130. mout.object.forOwn(packages, function (pkg, name) {
  131. var promise;
  132. var admin = path.join(__dirname, 'assets', name, 'admin');
  133. var dir = path.join(__dirname, 'assets', name, 'repo');
  134. // Ensure package is created
  135. promise = ensurePackage(admin, dir);
  136. promise = promise.fail(function (err) {
  137. console.log('Failed to create ' + name);
  138. console.log(err.message);
  139. });
  140. mout.object.forOwn(pkg, function (files, release) {
  141. // Check if the release already exists
  142. promise = promise.then(checkRelease.bind(null, dir, release))
  143. .then(function (exists) {
  144. // Skip it if already created
  145. if (exists) {
  146. return console.log(chalk.cyan('> ') + 'Package ' + name + '#' + release + ' already created');
  147. }
  148. // Create it based on the metadata
  149. return createRelease(admin, dir, release, files)
  150. .then(function () {
  151. console.log(chalk.green('> ') + 'Package ' + name + '#' + release + ' successfully created');
  152. });
  153. })
  154. .fail(function (err) {
  155. console.log(chalk.red('> ') + 'Failed to create ' + name + '#' + release);
  156. console.log(err.message.trim());
  157. if (err.details) {
  158. console.log(err.details.trim());
  159. }
  160. console.log(err.stack);
  161. });
  162. });
  163. promises.push(promise);
  164. });
  165. Q.allSettled(promises, function (results) {
  166. results.forEach(function (result) {
  167. if (result.state !== 'fulfilled') {
  168. process.exit(1);
  169. }
  170. });
  171. });