2
0

git.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. "use strict";
  2. var Git = require("git-wrapper2-promise"),
  3. Promise = require('bluebird'),
  4. path = require('path'),
  5. os = require('os'),
  6. fs = Promise.promisifyAll(require("fs")),
  7. moment = require('moment'),
  8. _ = require('lodash'),
  9. URL = require('url');
  10. /**
  11. * Git Model
  12. */
  13. module.exports = {
  14. _git: null,
  15. _url: '',
  16. _repo: {
  17. path: '',
  18. branch: 'master',
  19. exists: false,
  20. sync: true
  21. },
  22. _signature: {
  23. name: 'Wiki',
  24. email: 'user@example.com'
  25. },
  26. _opts: {
  27. clone: {},
  28. push: {}
  29. },
  30. /**
  31. * Initialize Git model
  32. *
  33. * @param {Object} appconfig The application config
  34. * @return {Object} Git model instance
  35. */
  36. init(appconfig) {
  37. let self = this;
  38. //-> Build repository path
  39. if(_.isEmpty(appconfig.datadir.repo)) {
  40. self._repo.path = path.join(ROOTPATH, 'repo');
  41. } else {
  42. self._repo.path = appconfig.datadir.repo;
  43. }
  44. //-> Initialize repository
  45. self._initRepo(appconfig).then((repo) => {
  46. if(self._repo.sync) {
  47. self.resync();
  48. }
  49. });
  50. // Define signature
  51. self._signature.name = appconfig.git.signature.name || 'Wiki';
  52. self._signature.email = appconfig.git.signature.email || 'user@example.com';
  53. return self;
  54. },
  55. /**
  56. * Initialize Git repository
  57. *
  58. * @param {Object} appconfig The application config
  59. * @return {Object} Promise
  60. */
  61. _initRepo(appconfig) {
  62. let self = this;
  63. winston.info('[GIT] Checking Git repository...');
  64. //-> Check if path is accessible
  65. return fs.mkdirAsync(self._repo.path).catch((err) => {
  66. if(err.code !== 'EEXIST') {
  67. winston.error('Invalid Git repository path or missing permissions.');
  68. }
  69. }).then(() => {
  70. self._git = new Git({ 'git-dir': self._repo.path });
  71. //-> Check if path already contains a git working folder
  72. return self._git.isRepo().then((isRepo) => {
  73. self._repo.exists = isRepo;
  74. return (!isRepo) ? self._git.exec('init') : true;
  75. }).catch((err) => {
  76. self._repo.exists = false;
  77. });
  78. }).then(() => {
  79. // Initialize remote
  80. let urlObj = URL.parse(appconfig.git.url);
  81. urlObj.auth = appconfig.git.auth.username + ((appconfig.git.auth.type !== 'ssh') ? ':' + appconfig.git.auth.password : '');
  82. self._url = URL.format(urlObj);
  83. return self._git.exec('remote', 'show').then((cProc) => {
  84. let out = cProc.stdout.toString();
  85. if(_.includes(out, 'origin')) {
  86. return true;
  87. } else {
  88. return Promise.join(
  89. self._git.exec('config', ['--local', 'user.name', self._signature.name]),
  90. self._git.exec('config', ['--local', 'user.email', self._signature.email])
  91. ).then(() => {
  92. return self._git.exec('remote', ['add', 'origin', self._url]);
  93. })
  94. }
  95. });
  96. }).catch((err) => {
  97. winston.error('Git remote error!');
  98. throw err;
  99. }).then(() => {
  100. winston.info('[GIT] Git repository is now ready.');
  101. return true;
  102. });
  103. },
  104. /**
  105. * Sync with the remote repository
  106. *
  107. * @return {Promise} Resolve on sync success
  108. */
  109. resync() {
  110. let self = this;
  111. // Fetch
  112. winston.info('[GIT] Performing pull from remote repository...');
  113. return self._git.pull('origin', self._repo.branch).then((cProc) => {
  114. winston.info('[GIT] Pull completed.');
  115. })
  116. .catch((err) => {
  117. winston.error('Unable to fetch from git origin!');
  118. throw err;
  119. })
  120. .then(() => {
  121. // Check for changes
  122. return self._git.exec('log', 'origin/' + self._repo.branch + '..HEAD').then((cProc) => {
  123. let out = cProc.stdout.toString();
  124. if(_.includes(out, 'commit')) {
  125. winston.info('[GIT] Performing push to remote repository...');
  126. return self._git.push('origin', self._repo.branch).then(() => {
  127. return winston.info('[GIT] Push completed.');
  128. });
  129. } else {
  130. winston.info('[GIT] Repository is already in sync.');
  131. }
  132. return true;
  133. });
  134. })
  135. .catch((err) => {
  136. winston.error('Unable to push changes to remote!');
  137. throw err;
  138. });
  139. },
  140. /**
  141. * Commits a document.
  142. *
  143. * @param {String} entryPath The entry path
  144. * @return {Promise} Resolve on commit success
  145. */
  146. commitDocument(entryPath) {
  147. let self = this;
  148. let gitFilePath = entryPath + '.md';
  149. let commitMsg = '';
  150. return self._git.exec('ls-files', gitFilePath).then((cProc) => {
  151. let out = cProc.stdout.toString();
  152. return _.includes(out, gitFilePath);
  153. }).then((isTracked) => {
  154. commitMsg = (isTracked) ? 'Updated ' + gitFilePath : 'Added ' + gitFilePath;
  155. return self._git.add(gitFilePath);
  156. }).then(() => {
  157. return self._git.commit(commitMsg);
  158. });
  159. }
  160. };