user-utilities.js 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * decaffeinate suggestions:
  3. * DS101: Remove unnecessary use of Array.from
  4. * DS102: Remove unnecessary code created because of implicit returns
  5. * DS207: Consider shorter variations of null checks
  6. * Full docs: https://github.com/decaffeinate/decaffeinate/blob/main/docs/suggestions.md
  7. */
  8. const os = require('os');
  9. const fs = require('fs');
  10. const path = require('path');
  11. const semver = require('semver');
  12. const {BufferedProcess} = require('atom');
  13. /*
  14. A collection of methods for retrieving information about the user's system for
  15. bug report purposes.
  16. */
  17. const DEV_PACKAGE_PATH = path.join('dev', 'packages');
  18. module.exports = {
  19. /*
  20. Section: System Information
  21. */
  22. getPlatform() {
  23. return os.platform();
  24. },
  25. // OS version strings lifted from https://github.com/lee-dohm/bug-report
  26. getOSVersion() {
  27. return new Promise((resolve, reject) => {
  28. switch (this.getPlatform()) {
  29. case 'darwin': return resolve(this.macVersionText());
  30. case 'win32': return resolve(this.winVersionText());
  31. case 'linux': return resolve(this.linuxVersionText());
  32. default: return resolve(`${os.platform()} ${os.release()}`);
  33. }
  34. });
  35. },
  36. macVersionText() {
  37. return this.macVersionInfo().then(function(info) {
  38. if (!info.ProductName || !info.ProductVersion) { return 'Unknown macOS version'; }
  39. return `${info.ProductName} ${info.ProductVersion}`;
  40. });
  41. },
  42. macVersionInfo() {
  43. return new Promise(function(resolve, reject) {
  44. let stdout = '';
  45. const plistBuddy = new BufferedProcess({
  46. command: '/usr/libexec/PlistBuddy',
  47. args: [
  48. '-c',
  49. 'Print ProductVersion',
  50. '-c',
  51. 'Print ProductName',
  52. '/System/Library/CoreServices/SystemVersion.plist'
  53. ],
  54. stdout(output) { return stdout += output; },
  55. exit() {
  56. const [ProductVersion, ProductName] = Array.from(stdout.trim().split('\n'));
  57. return resolve({ProductVersion, ProductName});
  58. }
  59. });
  60. return plistBuddy.onWillThrowError(function({handle}) {
  61. handle();
  62. return resolve({});
  63. });
  64. });
  65. },
  66. linuxVersionText() {
  67. return this.linuxVersionInfo().then(function(info) {
  68. if (info.DistroName && info.DistroVersion) {
  69. return `${info.DistroName} ${info.DistroVersion}`;
  70. } else {
  71. return `${os.platform()} ${os.release()}`;
  72. }
  73. });
  74. },
  75. linuxVersionInfo() {
  76. return new Promise(function(resolve, reject) {
  77. let stdout = '';
  78. const lsbRelease = new BufferedProcess({
  79. command: 'lsb_release',
  80. args: ['-ds'],
  81. stdout(output) { return stdout += output; },
  82. exit(exitCode) {
  83. const [DistroName, DistroVersion] = Array.from(stdout.trim().split(' '));
  84. return resolve({DistroName, DistroVersion});
  85. }
  86. });
  87. return lsbRelease.onWillThrowError(function({handle}) {
  88. handle();
  89. return resolve({});
  90. });
  91. });
  92. },
  93. winVersionText() {
  94. return new Promise(function(resolve, reject) {
  95. const data = [];
  96. const systemInfo = new BufferedProcess({
  97. command: 'systeminfo',
  98. stdout(oneLine) { return data.push(oneLine); },
  99. exit() {
  100. let res;
  101. let info = data.join('\n');
  102. info = (res = /OS.Name.\s+(.*)$/im.exec(info)) ? res[1] : 'Unknown Windows version';
  103. return resolve(info);
  104. }
  105. });
  106. return systemInfo.onWillThrowError(function({handle}) {
  107. handle();
  108. return resolve('Unknown Windows version');
  109. });
  110. });
  111. },
  112. /*
  113. Section: Installed Packages
  114. */
  115. getNonCorePackages() {
  116. return new Promise(function(resolve, reject) {
  117. const nonCorePackages = atom.packages.getAvailablePackageMetadata().filter(p => !atom.packages.isBundledPackage(p.name));
  118. const devPackageNames = atom.packages.getAvailablePackagePaths().filter(p => p.includes(DEV_PACKAGE_PATH)).map(p => path.basename(p));
  119. return resolve(Array.from(nonCorePackages).map((pack) => `${pack.name} ${pack.version} ${Array.from(devPackageNames).includes(pack.name) ? '(dev)' : ''}`));
  120. });
  121. },
  122. checkPulsarUpToDate() {
  123. const installedVersion = atom.getVersion().replace(/-.*$/, '');
  124. return {
  125. upToDate: true,
  126. latestVersion: installedVersion,
  127. installedVersion
  128. }
  129. },
  130. getPackageVersion(packageName) {
  131. const pack = atom.packages.getLoadedPackage(packageName);
  132. return (pack != null ? pack.metadata.version : undefined);
  133. },
  134. getPackageVersionShippedWithPulsar(packageName) {
  135. return require(path.join(atom.getLoadSettings().resourcePath, 'package.json')).packageDependencies[packageName];
  136. },
  137. getLatestPackageData(packageName) {
  138. const githubHeaders = new Headers({
  139. accept: 'application/json',
  140. contentType: "application/json"
  141. });
  142. const apiURL = process.env.ATOM_API_URL || 'https://api.pulsar-edit.dev/api';
  143. return fetch(`${apiURL}/${packageName}`, {headers: githubHeaders})
  144. .then(r => {
  145. if (r.ok) {
  146. return r.json();
  147. } else {
  148. return Promise.reject(new Error(`Fetching updates resulted in status ${r.status}`));
  149. }
  150. });
  151. },
  152. checkPackageUpToDate(packageName) {
  153. return this.getLatestPackageData(packageName).then(latestPackageData => {
  154. let isCore;
  155. const installedVersion = this.getPackageVersion(packageName);
  156. let upToDate = (installedVersion != null) && semver.gte(installedVersion, latestPackageData?.releases?.latest);
  157. const latestVersion = latestPackageData?.releases?.latest;
  158. const versionShippedWithPulsar = this.getPackageVersionShippedWithPulsar(packageName);
  159. if (isCore = (versionShippedWithPulsar != null)) {
  160. // A core package is out of date if the version which is being used
  161. // is lower than the version which normally ships with the version
  162. // of Pulsar which is running. This will happen when there's a locally
  163. // installed version of the package with a lower version than Pulsar's.
  164. upToDate = (installedVersion != null) && semver.gte(installedVersion, versionShippedWithPulsar);
  165. }
  166. return {isCore, upToDate, latestVersion, installedVersion, versionShippedWithPulsar};
  167. });
  168. }
  169. };