1
1
'use strict' ;
2
2
const fs = require ( 'fs-extra' ) ;
3
+ const os = require ( 'os' ) ;
3
4
const path = require ( 'path' ) ;
4
5
const fkill = require ( 'fkill' ) ;
5
- const spawn = require ( 'child_process' ) . spawn ;
6
+ const childProcess = require ( 'child_process' ) ;
6
7
const isRunning = require ( 'is-running' ) ;
7
8
8
9
const errors = require ( '../errors' ) ;
@@ -28,8 +29,14 @@ class LocalProcess extends ProcessManager {
28
29
* @public
29
30
*/
30
31
start ( cwd , environment ) {
32
+ // Check that content folder is owned by the current user
33
+ if ( ! this . _checkContentFolder ( cwd ) ) {
34
+ return Promise . reject ( new errors . SystemError ( `The content folder is not owned by the current user.
35
+ Please ensure the content folder has correct permissions and try again.` ) ) ;
36
+ }
37
+
31
38
return new Promise ( ( resolve , reject ) => {
32
- const cp = spawn ( 'node' , [ process . argv [ 1 ] , 'run' ] , {
39
+ const cp = childProcess . spawn ( 'node' , [ process . argv [ 1 ] , 'run' ] , {
33
40
cwd : cwd ,
34
41
detached : true ,
35
42
stdio : [ 'ignore' , 'ignore' , 'ignore' , 'ipc' ] ,
@@ -39,7 +46,12 @@ class LocalProcess extends ProcessManager {
39
46
// Stick the pid into the pidfile so we can stop the process later
40
47
fs . writeFileSync ( path . join ( cwd , PID_FILE ) , cp . pid ) ;
41
48
42
- cp . on ( 'error' , reject ) ;
49
+ cp . on ( 'error' , ( error ) => {
50
+ reject ( new errors . CliError ( {
51
+ message : 'An error occurred while starting Ghost.' ,
52
+ err : error
53
+ } ) ) ;
54
+ } ) ;
43
55
44
56
cp . on ( 'exit' , ( code ) => {
45
57
fs . removeSync ( path . join ( cwd , PID_FILE ) ) ;
@@ -50,8 +62,7 @@ class LocalProcess extends ProcessManager {
50
62
cp . on ( 'message' , ( msg ) => {
51
63
if ( msg . error ) {
52
64
fs . removeSync ( path . join ( cwd , PID_FILE ) ) ;
53
-
54
- return reject ( new errors . GhostError ( msg ) ) ;
65
+ return reject ( new errors . GhostError ( msg . error ) ) ;
55
66
}
56
67
57
68
if ( msg . started ) {
@@ -80,18 +91,24 @@ class LocalProcess extends ProcessManager {
80
91
} catch ( e ) {
81
92
if ( e . code === 'ENOENT' ) {
82
93
// pid was not found, exit
83
- return ;
94
+ return Promise . resolve ( ) ;
84
95
}
85
96
86
- throw e ;
97
+ return Promise . reject ( new errors . CliError ( {
98
+ message : 'An unexpected error occurred when reading the pidfile.' ,
99
+ error : e
100
+ } ) ) ;
87
101
}
88
102
89
- const isWindows = process . platform === 'win32' ;
103
+ const isWindows = os . platform ( ) === 'win32' ;
90
104
91
105
return fkill ( pid , { force : isWindows } ) . catch ( ( error ) => {
92
106
// TODO: verify windows outputs same error message as mac/linux
93
107
if ( ! error . message . match ( / N o s u c h p r o c e s s / ) ) {
94
- throw error ;
108
+ return Promise . reject ( new errors . CliError ( {
109
+ message : 'An unexpected error occurred while stopping Ghost.' ,
110
+ err : error
111
+ } ) ) ;
95
112
}
96
113
} ) . then ( ( ) => {
97
114
fs . removeSync ( path . join ( cwd , PID_FILE ) ) ;
@@ -151,6 +168,21 @@ class LocalProcess extends ProcessManager {
151
168
return running ;
152
169
}
153
170
171
+ /**
172
+ * Check that the content folder is owned by the current user
173
+ *
174
+ * @param {String } cwd current working directory
175
+ * @return {Boolean } true if ownership is correct, otherwise false
176
+ */
177
+ _checkContentFolder ( cwd ) {
178
+ if ( os . platform ( ) === 'win32' ) {
179
+ return true ;
180
+ }
181
+
182
+ const stat = fs . lstatSync ( path . join ( cwd , 'content' ) ) ;
183
+ return stat . uid === process . getuid ( ) ;
184
+ }
185
+
154
186
/**
155
187
* Because this process manager should work on every system,
156
188
* just return true here
0 commit comments