Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

git_helper.js 4.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. const util = require("util");
  2. const exec = util.promisify(require("child_process").exec);
  3. const fs = require("fs");
  4. const path = require("path");
  5. const Log = require("logger");
  6. class gitHelper {
  7. constructor() {
  8. this.gitRepos = [];
  9. this.baseDir = path.normalize(__dirname + "/../../../");
  10. }
  11. getRefRegex(branch) {
  12. return new RegExp("s*([a-z,0-9]+[.][.][a-z,0-9]+) " + branch, "g");
  13. }
  14. async execShell(command) {
  15. let res = { stdout: "", stderr: "" };
  16. const { stdout, stderr } = await exec(command);
  17. res.stdout = stdout;
  18. res.stderr = stderr;
  19. return res;
  20. }
  21. async isGitRepo(moduleFolder) {
  22. let res = await this.execShell("cd " + moduleFolder + " && git remote -v");
  23. if (res.stderr) {
  24. Log.error("Failed to fetch git data for " + moduleFolder + ": " + res.stderr);
  25. return false;
  26. } else {
  27. return true;
  28. }
  29. }
  30. add(moduleName) {
  31. let moduleFolder = this.baseDir;
  32. if (moduleName !== "default") {
  33. moduleFolder = moduleFolder + "modules/" + moduleName;
  34. }
  35. try {
  36. Log.info("Checking git for module: " + moduleName);
  37. // Throws error if file doesn't exist
  38. fs.statSync(path.join(moduleFolder, ".git"));
  39. // Fetch the git or throw error if no remotes
  40. if (this.isGitRepo(moduleFolder)) {
  41. // Folder has .git and has at least one git remote, watch this folder
  42. this.gitRepos.unshift({ module: moduleName, folder: moduleFolder });
  43. }
  44. } catch (err) {
  45. // Error when directory .git doesn't exist or doesn't have any remotes
  46. // This module is not managed with git, skip
  47. }
  48. }
  49. async getStatusInfo(repo) {
  50. let gitInfo = {
  51. module: repo.module,
  52. // commits behind:
  53. behind: 0,
  54. // branch name:
  55. current: "",
  56. // current hash:
  57. hash: "",
  58. // remote branch:
  59. tracking: "",
  60. isBehindInStatus: false
  61. };
  62. let res;
  63. if (repo.module === "default") {
  64. // the hash is only needed for the mm repo
  65. res = await this.execShell("cd " + repo.folder + " && git rev-parse HEAD");
  66. if (res.stderr) {
  67. Log.error("Failed to get current commit hash for " + repo.module + ": " + res.stderr);
  68. }
  69. gitInfo.hash = res.stdout;
  70. }
  71. if (repo.res) {
  72. // mocking
  73. res = repo.res;
  74. } else {
  75. res = await this.execShell("cd " + repo.folder + " && git status -sb");
  76. }
  77. if (res.stderr) {
  78. Log.error("Failed to get git status for " + repo.module + ": " + res.stderr);
  79. // exit without git status info
  80. return;
  81. }
  82. // only the first line of stdout is evaluated
  83. let status = res.stdout.split("\n")[0];
  84. // examples for status:
  85. // ## develop...origin/develop
  86. // ## master...origin/master [behind 8]
  87. status = status.match(/(?![.#])([^.]*)/g);
  88. // examples for status:
  89. // [ ' develop', 'origin/develop', '' ]
  90. // [ ' master', 'origin/master [behind 8]', '' ]
  91. gitInfo.current = status[0].trim();
  92. status = status[1].split(" ");
  93. // examples for status:
  94. // [ 'origin/develop' ]
  95. // [ 'origin/master', '[behind', '8]' ]
  96. gitInfo.tracking = status[0].trim();
  97. if (status[2]) {
  98. // git fetch was already called before so `git status -sb` delivers already the behind number
  99. gitInfo.behind = parseInt(status[2].substring(0, status[2].length - 1));
  100. gitInfo.isBehindInStatus = true;
  101. }
  102. return gitInfo;
  103. }
  104. async getRepoInfo(repo) {
  105. let gitInfo;
  106. if (repo.gitInfo) {
  107. // mocking
  108. gitInfo = repo.gitInfo;
  109. } else {
  110. gitInfo = await this.getStatusInfo(repo);
  111. }
  112. if (!gitInfo) {
  113. return;
  114. }
  115. if (gitInfo.isBehindInStatus) {
  116. return gitInfo;
  117. }
  118. let res;
  119. if (repo.res) {
  120. // mocking
  121. res = repo.res;
  122. } else {
  123. res = await this.execShell("cd " + repo.folder + " && git fetch --dry-run");
  124. }
  125. // example output:
  126. // From https://github.com/MichMich/MagicMirror
  127. // e40ddd4..06389e3 develop -> origin/develop
  128. // here the result is in stderr (this is a git default, don't ask why ...)
  129. const matches = res.stderr.match(this.getRefRegex(gitInfo.current));
  130. if (!matches || !matches[0]) {
  131. // no refs found, nothing to do
  132. return;
  133. }
  134. // get behind with refs
  135. try {
  136. res = await this.execShell("cd " + repo.folder + " && git rev-list --ancestry-path --count " + matches[0]);
  137. gitInfo.behind = parseInt(res.stdout);
  138. return gitInfo;
  139. } catch (err) {
  140. Log.error("Failed to get git revisions for " + repo.module + ": " + err);
  141. }
  142. }
  143. async getStatus() {
  144. const gitResultList = [];
  145. for (let repo of this.gitRepos) {
  146. const gitInfo = await this.getStatusInfo(repo);
  147. if (gitInfo) {
  148. gitResultList.unshift(gitInfo);
  149. }
  150. }
  151. return gitResultList;
  152. }
  153. async getRepos() {
  154. const gitResultList = [];
  155. for (let repo of this.gitRepos) {
  156. const gitInfo = await this.getRepoInfo(repo);
  157. if (gitInfo) {
  158. gitResultList.unshift(gitInfo);
  159. }
  160. }
  161. return gitResultList;
  162. }
  163. }
  164. module.exports.gitHelper = gitHelper;