-
-
Notifications
You must be signed in to change notification settings - Fork 184
/
index.ts
157 lines (126 loc) · 4.25 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import { platform } from 'os';
import debug from 'debug';
import { isNullOrUndefined, tryReleaseFile } from '../utils';
const log = debug('MongoMS:getos');
/** Collection of Regexes for "lsb_release -a" parsing */
const LSBRegex = {
// regex format is "lsb_release" (command output) and then "lsb-release" (file output)
name: /^(?:distributor id:|DISTRIB_ID=)\s*(.*)$/im,
codename: /^(?:codename:|DISTRIB_CODENAME=)\s*(.*)$/im,
release: /^(?:release:|DISTRIB_RELEASE=)\s*(.*)$/im,
};
/** Collection of Regexes for "/etc/os-release" parsing */
const OSRegex = {
name: /^id\s*=\s*"?(\w*)"?$/im,
codename: /^version_codename\s*=\s*(.*)$/im,
release: /^version_id\s*=\s*"?(\d*(?:\.\d*)?)"?$/im,
id_like: /^id_like\s*=\s*"?([\w\s]*)"?$/im,
};
/** Helper Static so that a consistent UNKNOWN value is used */
export const UNKNOWN = 'unknown';
export interface OtherOS {
os: 'aix' | 'android' | 'darwin' | 'freebsd' | 'openbsd' | 'sunos' | 'win32' | 'cygwin' | string;
}
export interface LinuxOS extends OtherOS {
os: 'linux';
dist: string;
release: string;
codename?: string;
id_like?: string[];
}
export type AnyOS = OtherOS | LinuxOS;
/**
* Check if the OS is a LinuxOS Typeguard
* @param os The OS object to check for
*/
export function isLinuxOS(os: AnyOS): os is LinuxOS {
return os.os === 'linux';
}
/**
* Cache the "getOS" call, so that not much has to be re-executed over and over
*/
let cachedOs: AnyOS | undefined;
/** Get an OS object */
export async function getOS(): Promise<AnyOS> {
if (!cachedOs) {
/** Node builtin function for first determinations */
const osName = platform();
// Linux is a special case.
if (osName === 'linux') {
cachedOs = await getLinuxInformation();
} else {
cachedOs = { os: osName };
}
}
return cachedOs;
}
/** Function to outsource Linux Information Parsing */
async function getLinuxInformation(): Promise<LinuxOS> {
// Structure of this function:
// 1. get upstream release, if possible
// 2. get os release (etc) because it has an "id_like"
// 3. get os release (usr) because it has an "id_like"
// 4. get lsb-release (etc) as fallback
const upstreamLSB = await tryReleaseFile('/etc/upstream-release/lsb-release', parseLSB);
if (isValidOs(upstreamLSB)) {
log('getLinuxInformation: Using UpstreamLSB');
return upstreamLSB;
}
const etcOsRelease = await tryReleaseFile('/etc/os-release', parseOS);
if (isValidOs(etcOsRelease)) {
log('getLinuxInformation: Using etcOsRelease');
return etcOsRelease;
}
const usrOsRelease = await tryReleaseFile('/usr/lib/os-release', parseOS);
if (isValidOs(usrOsRelease)) {
log('getLinuxInformation: Using usrOsRelease');
return usrOsRelease;
}
const etcLSBRelease = await tryReleaseFile('/etc/lsb-release', parseLSB);
if (isValidOs(etcLSBRelease)) {
log('getLinuxInformation: Using etcLSBRelease');
return etcLSBRelease;
}
console.warn('Could not find any valid Release File, using fallback information');
// if none has worked, return unknown
return {
os: 'linux',
dist: UNKNOWN,
release: '',
};
}
/**
* Helper function to check if the input os is valid
* @param os The OS information to check
* @returns `true` if not undefined AND not UNKNOWN
*/
export function isValidOs(os: LinuxOS | undefined): os is LinuxOS {
// helper for debugging
if (os && os.dist === UNKNOWN) {
log('isValidOS: found defined os, but was unknown:', os);
}
return !isNullOrUndefined(os) && os.dist !== UNKNOWN;
}
/**
* Parse LSB-like output (either command or file)
*/
export function parseLSB(input: string): LinuxOS {
return {
os: 'linux',
dist: input.match(LSBRegex.name)?.[1].toLocaleLowerCase() ?? UNKNOWN,
codename: input.match(LSBRegex.codename)?.[1].toLocaleLowerCase(),
release: input.match(LSBRegex.release)?.[1].toLocaleLowerCase() ?? '',
};
}
/**
* Parse OSRelease-like output
*/
export function parseOS(input: string): LinuxOS {
return {
os: 'linux',
dist: input.match(OSRegex.name)?.[1].toLocaleLowerCase() ?? UNKNOWN,
codename: input.match(OSRegex.codename)?.[1].toLocaleLowerCase(),
release: input.match(OSRegex.release)?.[1].toLocaleLowerCase() ?? '',
id_like: input.match(OSRegex.id_like)?.[1].toLocaleLowerCase().split(' '),
};
}