UNPKG

8.72 kBJavaScriptView Raw
1const fs = require( 'fs' );
2const chalk = require( 'chalk' );
3const nconf = require( 'nconf' );
4const getPort = require( 'get-port' );
5const sh = require( 'shelljs' );
6const p = require( 'path' );
7const app = require( '../lib/app' );
8
9const util = {
10
11 /**
12 * Remove http(s):// + port number from url.
13 * @param {String} url The project's url.
14 * @return {String}
15 */
16 getProjectHostname( url ) {
17 const domain = url.substring( 0, url.lastIndexOf( ':' ) );
18 const hostname = domain.replace( /(^\w+:|^)\/\//, '' );
19
20 return hostname;
21 },
22
23 /**
24 * Get the number of profiles available.
25 * @return {Integer}
26 */
27 getNumberOfProfiles() {
28 const numberOfProfiles = fs.readdirSync( app.profilesDir ).length;
29
30 return numberOfProfiles;
31 },
32
33 /**
34 * Get available profiles.
35 * @return {Array}
36 */
37 getProfiles() {
38 const profiles = [];
39
40 fs.readdirSync( app.profilesDir ).forEach( ( profile ) => {
41 const profilePath = `${app.profilesDir}/${profile}`;
42 profiles.push( profilePath );
43 });
44
45 return profiles;
46 },
47
48 /**
49 * Get the info about a specific project.
50 * @param {Object} dataProjects The remote project data.
51 * @param {String} prj Name of project to get available environments from.
52 */
53 getProjectInfo( dataProjects, prj ) {
54 const project = dataProjects.filter( obj => obj.slug === prj );
55
56 return project[0];
57 },
58
59 /**
60 * Get the info about a specific project type.
61 * @param {String} type The selected type.
62 * @param {Object} dataProjectTypes The remote project type data.
63 * @return {Object}
64 */
65 getProjectTypeInfo( type, dataProjectTypes ) {
66 const typeInfo = dataProjectTypes.filter( obj => obj.name === type );
67
68 return typeInfo[0];
69 },
70
71 /**
72 * Check if object is empty.
73 * @param {Object} obj The object.
74 * @return {Boolean}
75 */
76 isEmptyObject( obj ) {
77 return !Object.keys( obj ).length;
78 },
79
80 /**
81 * Check if project has any environments.
82 * @param {Object} dataProjects Remote project data.
83 * @param {String} prj Name of project to get available environments from.
84 * @return {Boolean}
85 */
86 projectHasEnvs( dataProjects, prj ) {
87 const project = util.getProjectInfo( dataProjects, prj );
88 const envs = project.env;
89
90 if ( envs !== undefined ) {
91 if ( !this.isEmptyObject( envs ) ) {
92 return true;
93 }
94 }
95
96 return false;
97 },
98
99 /**
100 * Get local projects.
101 * @return {Object}
102 */
103 getLocalProjects() {
104 const localProjects = nconf.get( 'local_projects' );
105
106 return localProjects;
107 },
108
109 /**
110 * Check if any local projects are available.
111 * @return {Boolean}
112 */
113 localProjectsExist() {
114 const localProjects = nconf.get( 'local_projects' );
115
116 if ( localProjects === undefined ) {
117 return false;
118 }
119
120 if ( !this.isEmptyObject( localProjects ) ) {
121 return true;
122 }
123
124 return false;
125 },
126
127 /**
128 * Check if an individual project already exists.
129 * @param {String} slug The project's slug.
130 * @return {Boolean}
131 */
132 localProjectExists( slug ) {
133 const localProject = nconf.get( `local_projects:${slug}` );
134
135 if ( localProject === undefined ) {
136 return false;
137 }
138
139 if ( !this.isEmptyObject( localProject ) ) {
140 return true;
141 }
142
143 return false;
144 },
145
146 /**
147 * Get varialbe name.
148 * getVarName({ email })
149 * @param {Object} varObj The variable as a single object.
150 * @return {String} Variable name.
151 */
152 getVarName( varObj ) {
153 return Object.keys( varObj )[0];
154 },
155
156 /**
157 * Increment slug.
158 * @param {String} existingSlug The slug for the project that already exists.
159 * @return {String}
160 */
161 getNextSlugIncrement( existingSlug ) {
162 let newSlug = existingSlug;
163 let firstPart;
164 let lastPart;
165
166 do {
167 firstPart = newSlug.substring( 0, newSlug.lastIndexOf( '_' ) );
168 lastPart = newSlug.split( '_' ).pop();
169
170 if ( !Number.isNaN( lastPart ) && lastPart !== '' && lastPart !== newSlug ) {
171 let num = parseInt( lastPart, 10 );
172 num += 1;
173 newSlug = `${firstPart}_${num}`;
174 } else {
175 newSlug = `${newSlug}_2`;
176 }
177 }
178 while ( this.localProjectExists( newSlug ) );
179
180 return newSlug;
181 },
182
183 /**
184 * Remove multiple adjacent, leading, & trailing whitespace.
185 * @param {String} str
186 * @return {String}
187 */
188 trimWhitespace( str ) {
189 const str1 = str.trim();
190 const str2 = str1.replace( /\s\s+/g, ' ' );
191
192 return str2;
193 },
194
195 /**
196 * Get the ports already being used by slab.
197 * @return {Array}
198 */
199 getReservedSlabPorts() {
200 const localProjects = this.getLocalProjects();
201 const reservedPorts = [];
202
203 Object.keys( localProjects ).forEach( ( key ) => {
204 const reservedPort = nconf.get( `local_projects:${key}:ports` );
205 reservedPorts.push( reservedPort );
206 });
207
208 return reservedPorts;
209 },
210
211 /**
212 * Generate pair of ports that are not already in use.
213 * @return {Array} Port number.
214 */
215 async generatePorts() {
216 const reservedSlabPortsData = this.getReservedSlabPorts();
217 const reservedSlabPorts = [].concat( ...reservedSlabPortsData );
218 const ports = [];
219
220 do {
221 ports[0] = await getPort();
222 }
223 while ( reservedSlabPorts.includes( ports[0] ) );
224
225 return ports;
226 },
227
228 /**
229 * Execute shell command from within a project.
230 * @param {String} path The absolute path to run command from.
231 * @param {String} cmd The shell command to run within the project's root directory.
232 */
233 execFrom( path, cmd ) {
234 if ( path === '' || path === undefined || typeof path === 'undefined' || path === '/' ) {
235 console.log( chalk`{red Illegal path.}` );
236 process.exit( 1 );
237 }
238
239 sh.exec( `cd ${path}; ${cmd}` );
240 },
241
242 /**
243 * Replace project types data placeholders with corresponding project values.
244 * @param {Object} src The source object that has placeholder values.
245 * @param {String} slug The project's slug.
246 * @param {String} path The project's path.
247 * @param {Array} ports The project's reserved ports.
248 * @param {String} url The project's url.
249 * @return {Object}
250 */
251 replacePlaceholders( src, slug, path, ports, url ) {
252 let srcStr = JSON.stringify( src );
253 const email = nconf.get( 'email' );
254
255 if ( src === undefined || src === null || typeof src === 'undefined' ) {
256 console.log( chalk`{red The project has a project type that does not exist.}` );
257 process.exit( 1 );
258 }
259
260 const port1 = ports[0];
261
262 srcStr = srcStr.replace( /\{{email}}/gim, email );
263 srcStr = srcStr.replace( /\{{project_url}}/gim, url );
264 srcStr = srcStr.replace( /\{{project_name}}/gim, slug );
265 srcStr = srcStr.replace( /\{{project_path}}/gim, path );
266 srcStr = srcStr.replace( /\{{project_port_1}}/gim, port1 );
267 srcStr = srcStr.replace( /\{{project_slug}}/gim, slug );
268
269 const srcObj = JSON.parse( srcStr );
270
271 return srcObj;
272 },
273
274 /**
275 * Check if any configuration profiles exists.
276 * @return {Boolean}
277 */
278 profilesExist() {
279 const profileDirExists = fs.existsSync( app.profilesDir );
280
281 if ( profileDirExists ) {
282 const numberOfProfiles = this.getNumberOfProfiles();
283
284 if ( numberOfProfiles > 0 ) {
285 return true;
286 }
287 }
288
289 return false;
290 },
291
292 /**
293 * Get the name of the current profile.
294 * @param {Boolean} output Output name to console.
295 * @return {String}
296 */
297 getCurrentProfileName( output = false ) {
298 nconf.file( app.config );
299
300 const currentProfilePath = nconf.get( 'current_profile' );
301 const name = this.getProfileName( currentProfilePath );
302
303 if ( output ) {
304 console.log( name );
305 }
306
307 return name;
308 },
309
310 /**
311 * Get the path of a specific profile name.
312 * @param {String} name The name of the profile.
313 * @return {String}
314 */
315 getProfilePath( name ) {
316 let path = '';
317
318 if ( name ) {
319 path = `${app.profilesDir}/${name}.json`;
320 }
321
322 return path;
323 },
324
325 /**
326 * Get the name of a specific profile name.
327 * @param {String} path The path of the profile.
328 * @return {String}
329 */
330 getProfileName( path ) {
331 let name = '';
332
333 if ( path ) {
334 name = p.basename( path, p.extname( path ) );
335 }
336
337 return name;
338 },
339
340 /**
341 * Get the path to the current profile.
342 * @return {string}
343 */
344 getCurrentProfilePath() {
345 nconf.file( app.config );
346
347 const currentProfilePath = nconf.get( 'current_profile' );
348
349 return currentProfilePath;
350 },
351
352 /**
353 * Enforce keys to be required.
354 * @param {Array} keys Required keys.
355 */
356 requireKeys( keys ) {
357 const errors = [];
358
359 // Find config errors.
360 keys.forEach( ( key ) => {
361 const value = nconf.get( key );
362
363 if ( value === undefined ) {
364 errors.push({
365 item : key,
366 message : chalk`Cannot find the key {blue ${key}}.`,
367 });
368 }
369 if ( value === '' ) {
370 errors.push({
371 item : key,
372 message : chalk`No value found for {blue ${key}}.`,
373 });
374 }
375 });
376
377 // Report any errors.
378 if ( errors.length ) {
379 errors.forEach( ( error ) => {
380 console.log( chalk`{red Error:} ${error.message}` );
381 });
382 process.exit( 1 );
383 }
384 },
385
386};
387
388module.exports = util;