UNPKG

5.45 kBJavaScriptView Raw
1/*
2 * Copyright 2014-2016 Guy Bedford (http://guybedford.com)
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17var ui = require('../ui');
18var fs = require('graceful-fs');
19var mkdirp = require('mkdirp');
20var path = require('path');
21var lockFile = require('proper-lockfile');
22var dprepend = require('../common').dprepend;
23var readJSONSync = require('../common').readJSONSync;
24var stringify = require('../common').stringify;
25var HOME = require('../common').HOME;
26var dprepend = require('../common').dprepend;
27
28function GlobalConfigFile(homePath) {
29 this.globalConfigFile = homePath + path.sep + '.jspm' + path.sep + 'config';
30 this.config = null;
31 // global config - automatically created and loaded on startup
32 this.registries = [];
33
34 // old windows HOME migration
35 // can deprecate with jspm 0.15.3
36 if (process.env.USERPROFILE && HOME !== process.env.USERPROFILE && !fs.existsSync(path.join(HOME, '.jspm')) && fs.existsSync(path.join(process.env.USERPROFILE, '.jspm'))) {
37 var OLD_HOME = process.env.USERPROFILE;
38 var from = path.join(OLD_HOME, '.jspm');
39 var to = path.join(HOME, '.jspm');
40 ui.log('info', 'Migrating global jspm folder from `' + from + '` to `' + to + '`...');
41 try {
42 ui.log('info', 'Copying configuration...');
43 var oldConfig = fs.readFileSync(path.resolve(from, 'config'));
44 mkdirp.sync(to);
45 fs.writeFileSync(path.resolve(to, 'config'), oldConfig);
46 ui.log('ok', 'Migration successful. Note that linked packages will need to be relinked.');
47 }
48 catch (e) {
49 ui.log('err', 'Error migrating to new jspm folder\n' + (e && e.stack || e));
50 }
51 }
52
53 // Begin file lock
54 this.lock();
55
56 // after loading, we'll dprepend all defaults to `this.config` in this `try` block
57 this.config = readJSONSync(this.globalConfigFile);
58
59 // NB can deprecate with jspm 0.14
60 if (!this.config.defaultRegistry && this.config.registry)
61 this.config.defaultRegistry = this.config.registry;
62 if (!this.config.registries && this.config.endpoints)
63 this.config.registries = this.config.endpoints;
64
65 // NB add this to deprecate 0.14
66 // delete this.config.registry;
67 // delete this.config.endpoints;
68
69 // config upgrade paths
70 // NB can deprecate with jspm < 10
71 if (this.config.github) {
72 dprepend(this.config.registries.github, this.config.github);
73 delete this.config.github;
74 }
75
76 // populate default registry configuration
77 dprepend(this.config, {
78 defaultRegistry: 'jspm',
79 strictSSL: true,
80 registries: {
81 github: {
82 handler: 'jspm-github',
83 remote: 'https://github.jspm.io'
84 },
85 npm: {
86 handler: 'jspm-npm',
87 remote: 'https://npm.jspm.io'
88 },
89 jspm: {
90 handler: 'jspm-registry',
91 remote: 'https://registry.jspm.io'
92 }
93 }
94 });
95
96 this.save();
97 // end file lock
98 this.unlock();
99}
100
101GlobalConfigFile.prototype.constructor = GlobalConfigFile;
102
103GlobalConfigFile.prototype.save = function() {
104 try {
105 mkdirp.sync(path.dirname(this.globalConfigFile));
106 }
107 catch (e) {
108 if (e.code !== 'EEXIST')
109 throw 'Unable to create jspm system folder\n' + e.stack;
110 }
111 try {
112 this.lock();
113 var existing = readJSONSync(this.globalConfigFile);
114 // only write to a new file if the local changes are different
115 if (JSON.stringify(existing) != JSON.stringify(this.config)) {
116 fs.writeFileSync(this.globalConfigFile, stringify(this.config));
117 }
118 }
119 catch (e) {
120 ui.log('err', 'Unable to write global configuration file\n' + e.stack);
121 }
122 finally {
123 this.unlock();
124 }
125};
126
127GlobalConfigFile.prototype.set = function(name, val) {
128 var nameParts = name.split('.');
129
130 var config = this.config;
131 var part;
132 while (nameParts.length > 1) {
133 part = nameParts.shift();
134 config[part] = typeof config[part] === 'object' ? config[part] : {};
135 config = config[part];
136 }
137 if (val !== undefined) {
138 config[nameParts[0]] = val;
139 }
140 else {
141 // If no value is specified, then remove property from config
142 delete config[nameParts[0]];
143 }
144
145 this.save();
146};
147
148GlobalConfigFile.prototype.lock = function() {
149 if (!this._unlock) {
150 try {
151 this._unlock = lockFile.lockSync(this.globalConfigFile, {
152 retries: {
153 retries: 10,
154 minTimeout: 20,
155 maxTimeout: 300,
156 randomize: true
157 },
158 realpath: false
159 });
160 } catch (e) {
161 if (e.code === 'ELOCKED')
162 throw 'Unable to lock global config file %' + this.globalConfigFile + '%, not overwriting';
163 }
164 }
165};
166GlobalConfigFile.prototype.unlock = function() {
167 if (this._unlock) {
168 this._unlock();
169 this._unlock = undefined;
170 }
171};
172
173// Map SIGINT & SIGTERM to process exit
174// so that lockfile removes the lockfile automatically
175process
176.once('SIGINT', function () {
177 process.exit(1);
178})
179.once('SIGTERM', function () {
180 process.exit(1);
181});
182
183module.exports = new GlobalConfigFile(HOME);