UNPKG

7.36 kBJavaScriptView Raw
1import Program from "commander";
2import path from "path";
3import fs from "fs";
4import ChildProcess from "child_process";
5import executablePaths from "./executable-paths";
6import FindCommand from "./find-command";
7import packageDetails from "../package.json";
8
9const spawn = ChildProcess.spawn;
10
11const processDir = process.cwd();
12
13const cleanExit = function() { process.exit(); };
14process.on("SIGINT", cleanExit); // catch ctrl-c
15process.on("SIGTERM", cleanExit); // catch kill
16
17
18export default class CliHandler {
19
20 program = Program;
21 projectRoot = null;
22 libRoot = null;
23 searchCommand = null;
24 pawConfigManualPath = false;
25 projectRootManualPath = false;
26
27 constructor() {
28 // Initialize the env with defaults
29 this.initProcessEnv();
30 this.updateConfigPath = this.updateConfigPath.bind(this);
31 this.updateProjectRoot = this.updateProjectRoot.bind(this);
32 this.startServer = this.startServer.bind(this);
33 }
34
35 initProcessEnv() {
36
37 // PawJS library root, i.e. the folder where the script file is located
38 this.libRoot = process.env.__lib_root = path.resolve(path.join(__dirname, ".."));
39
40 // Set paw cache to true by default
41 process.env.PAW_CACHE = "true";
42
43 process.env.PAW_VERBOSE = "false";
44
45 // Set default env as development
46 process.env.PAW_ENV = "development";
47
48 // Project root - Assuming the command is executed from project root
49 process.env.__project_root = (
50 // If already stored then reuse the __project_root
51 process.env.__project_root ||
52
53 // if not try to get the project root from env variable PROJECT_ROOT
54 process.env.PROJECT_ROOT ||
55
56 // If not provided then consider the current directory of the process as project root
57 (processDir + path.sep)
58 );
59 this.updateProjectRoot(process.env.__project_root, false);
60
61 process.env.PAW_CONFIG_PATH = path.join(this.projectRoot, "pawconfig.json");
62 }
63 onSetProjectRoot() {
64
65 const newNodePath = executablePaths(this.projectRoot, this.libRoot).join(path.delimiter);
66 if (!process.env.NODE_PATH) {
67 process.env.NODE_PATH = newNodePath;
68 } else {
69 process.env.NODE_PATH = [process.env.NODE_ENV, newNodePath].join(path.delimiter);
70 }
71 process.env.PATH = process.env.NODE_PATH;
72
73 if (!this.pawConfigManualPath) {
74 process.env.PAW_CONFIG_PATH = path.join(this.projectRoot, "pawconfig.json");
75 }
76
77 this.updateCommandSearch();
78
79 }
80
81 updateCommandSearch() {
82 // get the search command with the executable path list
83 this.searchCommand = FindCommand.factory(executablePaths(this.projectRoot, this.libRoot));
84 }
85
86 /**
87 * Update config path for pawconfig.json
88 * @param configPath
89 * @param manual
90 */
91 updateConfigPath(configPath, manual = true) {
92 // store the absolute value of project root
93 let pawConfig = configPath;
94 if (!path.isAbsolute(configPath)) {
95 pawConfig = path.resolve(processDir, configPath);
96 }
97 let pathStats = fs.lstatSync(pawConfig);
98 if(!pathStats.isFile()) {
99 // eslint-disable-next-line
100 console.warn(`WARNING:: Invalid config file path specified ${configPath}, using ${process.env.PAW_CONFIG_PATH} instead`);
101 return;
102 }
103 if (manual) {
104 this.pawConfigManualPath = true;
105 }
106
107 process.env.PAW_CONFIG_PATH = pawConfig;
108
109 }
110
111 /**
112 * Specify the project root directory
113 * @param projectRootDir
114 * @param manual
115 */
116 updateProjectRoot(projectRootDir, manual = true) {
117 // store the absolute value of project root
118 let pRoot = projectRootDir;
119 if (!path.isAbsolute(projectRootDir)) {
120 pRoot = path.resolve(processDir, projectRootDir);
121 }
122 let pathStats = fs.lstatSync(pRoot);
123 if(!pathStats.isDirectory()) {
124 // eslint-disable-next-line
125 console.warn(`WARNING:: Invalid root directory specified ${projectRootDir}, using ${this.projectRoot} instead`);
126 return;
127 }
128 if (manual) {
129 this.projectRootManualPath = true;
130 }
131 this.projectRoot = process.env.__project_root = pRoot;
132 this.onSetProjectRoot();
133 }
134
135 /**
136 * Start server depending on the env variable
137 */
138 startServer() {
139 require(path.resolve(this.libRoot, "src/server/webpack-start.js"));
140 }
141
142 buildProd = () => {
143 require(path.resolve(this.libRoot, "src/server/webpack-build.js"));
144 };
145
146 test() {
147 const env = Object.create(process.env);
148 env.NODE_ENV = "test";
149 spawn(this.searchCommand("jest"), [], {
150 env,
151 stdio: [process.stdin, process.stdout, "pipe"]
152 });
153 }
154
155 run() {
156 this.program
157 .version(packageDetails.version, "-V, --version");
158
159 this.program.option("-v, --verbose", "Start with detailed comments and explanation");
160 this.program.option("-e, --env <env>","Set the application environment default is dev env");
161 this.program.option("-nc, --no-cache","Disable cache. Ideal for PawJS core/plugin development");
162 this.program.option("-r, --root <projectRootDir>", "Set the project root");
163 this.program.option("-c, --config <configPath>", "Set path to pawconfig.json");
164
165 this.program
166 .command("start")
167 .description("Start the application")
168 .action(this.startServer.bind(this));
169
170 this.program
171 .command("build")
172 .description("Compile the project for production.")
173 .action(this.buildProd.bind(this));
174
175 this.program
176 .command("test")
177 .description("Run the test cases for the project.")
178 .action(this.test.bind(this));
179
180
181 // Set PAW_VERBOSE to true
182 this.program.on("option:verbose", () => {
183 process.env.PAW_VERBOSE = "true";
184 });
185
186 // Set Environment to
187 this.program.on("option:env", env => {
188 if (!env) return;
189 env = env.toLowerCase();
190 if (env === "dev") {
191 // eslint-disable-next-line
192 console.info("NOTE:: Setting env to development. Please use --env=development instead");
193 env = "development";
194 }
195
196 if (env === "prod") {
197 // eslint-disable-next-line
198 console.info("NOTE:: Setting env to production. Please use --env=production instead");
199 env = "production";
200 }
201 process.env.PAW_ENV = env;
202
203 // Force set NODE_ENV & ENV to production
204 if (process.env.PAW_ENV === "production" && typeof process.env.NODE_ENV === "undefined") {
205 process.env.NODE_ENV = "production";
206 process.env.ENV = "production";
207 }
208 });
209
210 this.program.on("option:cache", () => {
211 if (!this.program.cache) {
212 // set PAW_CACHE to false
213 process.env.PAW_CACHE = "false";
214
215 // Disable babel cache if no-cache is specified
216 process.env.BABEL_DISABLE_CACHE = true;
217 }
218
219 });
220
221 // Update the project root based on the root option
222 this.program.on("option:root", this.updateProjectRoot);
223
224 // Update the pawconfig path
225 this.program.on("option:config", this.updateConfigPath);
226
227 this.program.on("command:*", () => {
228 //eslint-disable-next-line
229 console.error("Invalid command: %s\nSee --help for a list of available commands.", Program.args.join(" "));
230 process.exit(1);
231 });
232
233 this.program.parse(process.argv);
234
235 if (!process.argv.slice(2).length) {
236 this.startServer();
237 }
238 }
239}
\No newline at end of file