-
Notifications
You must be signed in to change notification settings - Fork 26
/
index.js
154 lines (144 loc) · 4.67 KB
/
index.js
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
/**
* Things we will need
*/
var async = require('async')
var distros = require('./os.json')
var fs = require('fs')
var os = require('os')
/**
* Begin definition of globals.
*/
var cachedDistro = null // Store result of getLinuxDistro() after first call
/**
* Module definition.
*/
module.exports = function getOs (cb) {
// Node builtin as first line of defense.
var osName = os.platform()
// Linux is a special case.
if (osName === 'linux') return getLinuxDistro(cb)
// Else, node's builtin is acceptable.
return cb(null, { os: osName })
}
/**
* Identify the actual distribution name on a linux box.
*/
function getLinuxDistro (cb) {
/**
* First, we check to see if this function has been called before.
* Since an OS doesn't change during runtime, its safe to cache
* the result and return it for future calls.
*/
if (cachedDistro) return cb(null, cachedDistro)
/**
* We are going to take our list of release files from os.json and
* check to see which one exists. It is safe to assume that no more
* than 1 file in the list from os.json will exist on a distribution.
*/
getReleaseFile(Object.keys(distros), function (e, file) {
if (e) return cb(e)
/**
* Multiple distributions may share the same release file.
* We get our array of candidates and match the format of the release
* files and match them to a potential distribution
*/
var candidates = distros[file]
var os = { os: 'linux', dist: candidates[0] }
fs.readFile(file, 'utf-8', function (e, file) {
if (e) return cb(e)
/**
* If we only know of one distribution that has this file, its
* somewhat safe to assume that it is the distribution we are
* running on.
*/
if (candidates.length === 1) {
return customLogic(os, getName(os.dist), file, function (e, os) {
if (e) return cb(e)
cachedDistro = os
return cb(null, os)
})
}
/**
* First, set everything to lower case to keep inconsistent
* specifications from mucking up our logic.
*/
file = file.toLowerCase()
/**
* Now we need to check all of our potential candidates one by one.
* If their name is in the release file, it is guarenteed to be the
* distribution we are running on. If distributions share the same
* release file, it is reasonably safe to assume they will have the
* distribution name stored in their release file.
*/
async.each(candidates, function (candidate, done) {
var name = getName(candidate)
if (file.indexOf(name) >= 0) {
os.dist = candidate
return customLogic(os, name, file, function (e, augmentedOs) {
if (e) return done(e)
os = augmentedOs
return done()
})
} else {
return done()
}
}, function (e) {
if (e) return cb(e)
cachedDistro = os
return cb(null, os)
})
})
})() // sneaky sneaky.
}
function getName (candidate) {
/**
* We only care about the first word. I.E. for Arch Linux it is safe
* to simply search for "arch". Also note, we force lower case to
* match file.toLowerCase() above.
*/
var index = 0
var name = 'linux'
/**
* Don't include 'linux' when searching since it is too aggressive when
* matching (see #54)
*/
while (name === 'linux') {
name = candidate.split(' ')[index++].toLowerCase()
}
return name
}
/**
* Loads a custom logic module to populate additional distribution information
*/
function customLogic (os, name, file, cb) {
try { require(`./logic/${name}.js`)(os, file, cb) } catch (e) { cb(null, os) }
}
/**
* getReleaseFile() checks an array of filenames and returns the first one it
* finds on the filesystem.
*/
function getReleaseFile (names, cb) {
var index = 0 // Lets keep track of which file we are on.
/**
* checkExists() is a first class function that we are using for recursion.
*/
return function checkExists () {
/**
* Lets get the file metadata off the current file.
*/
fs.stat(names[index], function (e, stat) {
/**
* Now we check if either the file didn't exist, or it is something
* other than a file for some very very bizzar reason.
*/
if (e || !stat.isFile()) {
index++ // If it is not a file, we will check the next one!
if (names.length <= index) { // Unless we are out of files.
return cb(new Error('No unique release file found!')) // Then error.
}
return checkExists() // Re-call this function to check the next file.
}
cb(null, names[index]) // If we found a file, return it!
})
}
}