@ovipakla/gm-cli 1.0.4 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GMFileWatcher.js +1 -1
- package/README.md +2 -41
- package/app.js +455 -98
- package/package.json +1 -1
package/GMFileWatcher.js
CHANGED
|
@@ -83,7 +83,7 @@ function syncWatcherHook() {
|
|
|
83
83
|
* --------------------------------------------------------- */
|
|
84
84
|
class GMFileWatcher {
|
|
85
85
|
constructor(gmPackage, modulesDir, watch = false) {
|
|
86
|
-
this.gmPath = resolvePath(gmPackage.main);
|
|
86
|
+
this.gmPath = path.dirname(resolvePath(gmPackage.main));
|
|
87
87
|
this.modulesDirName = modulesDir;
|
|
88
88
|
this.modulesDirPath = resolvePath(modulesDir);
|
|
89
89
|
this.timestamp = "";
|
package/README.md
CHANGED
|
@@ -7,49 +7,10 @@ Gamemaker CLI toolkit. Watch & sync gml sources with yyp project.
|
|
|
7
7
|
|
|
8
8
|
# Install
|
|
9
9
|
```bash
|
|
10
|
-
npm install
|
|
10
|
+
npm install -g
|
|
11
11
|
```
|
|
12
12
|
|
|
13
13
|
# Usage
|
|
14
14
|
```bash
|
|
15
|
-
gm-cli
|
|
15
|
+
gm-cli
|
|
16
16
|
```
|
|
17
|
-
|
|
18
|
-
# Project structure
|
|
19
|
-
```
|
|
20
|
-
- gm_modules:
|
|
21
|
-
- core: git repo with gml `*.gml` files
|
|
22
|
-
- visu: git repo with gml `*.gml` files
|
|
23
|
-
- yyp:
|
|
24
|
-
- datafiles: directory created by gamemaker
|
|
25
|
-
- extensions: directory created by gamemaker
|
|
26
|
-
- fonts: directory created by gamemaker
|
|
27
|
-
- objects: directory created by gamemaker
|
|
28
|
-
- options: directory created by gamemaker
|
|
29
|
-
- rooms: directory created by gamemaker
|
|
30
|
-
- scripts: directory created by gamemaker
|
|
31
|
-
- shaders: directory created by gamemaker
|
|
32
|
-
- sounds: directory created by gamemaker
|
|
33
|
-
- sprites: directory created by gamemaker
|
|
34
|
-
- game.resource_order: file created by gamemaker
|
|
35
|
-
- game.yyp: file created by gamemaker
|
|
36
|
-
- package-gm.json: Equivalent of `npm` "package.json"
|
|
37
|
-
```
|
|
38
|
-
Content of `package-gm.json`:
|
|
39
|
-
```json
|
|
40
|
-
{
|
|
41
|
-
"name": "visu",
|
|
42
|
-
"version": "1.0.0",
|
|
43
|
-
"description": "Visu",
|
|
44
|
-
"main": "yyp",
|
|
45
|
-
"author": "Alkapivo",
|
|
46
|
-
"license": "ISC",
|
|
47
|
-
"dependencies": {
|
|
48
|
-
"core": "^1.0.0",
|
|
49
|
-
"visu": "^1.0.0"
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
```
|
|
53
|
-
Note:
|
|
54
|
-
- `main` is a relative directory path, where `*.yyp` file (gamemaker studio 2.3 project).
|
|
55
|
-
- `dependencies` - keys should match names in `gm_modules` folder
|
package/app.js
CHANGED
|
@@ -2,14 +2,107 @@
|
|
|
2
2
|
|
|
3
3
|
import { watch, sync } from './GMFileWatcher.js';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import {
|
|
5
|
+
import { Command } from 'commander';
|
|
6
6
|
import { spawn, execSync } from 'child_process';
|
|
7
7
|
import fs from 'fs';
|
|
8
8
|
import readline from 'readline';
|
|
9
9
|
|
|
10
|
+
function findFileUpwardsSync(filename, maxLevels = 99) {
|
|
11
|
+
let currentDir = process.cwd();
|
|
12
|
+
for (let i = 0; i < maxLevels; i++) {
|
|
13
|
+
const candidate = path.join(currentDir, filename);
|
|
14
|
+
if (fs.existsSync(candidate)) {
|
|
15
|
+
return candidate;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const parentDir = path.dirname(currentDir);
|
|
19
|
+
if (parentDir === currentDir) {
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
currentDir = parentDir;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getPackageGM() {
|
|
30
|
+
const file = findFileUpwardsSync("package-gm.json");
|
|
31
|
+
if (file === null) {
|
|
32
|
+
throw new Error('❌ package-gm.json was not found')
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
file: file,
|
|
37
|
+
data: JSON.parse(fs.readFileSync(file, "utf8")),
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function backupPackageGM(packageGM) {
|
|
42
|
+
console.log(`📝 Backup package-gm.json: ${packageGM.file}.old`);
|
|
43
|
+
fs.copyFileSync(packageGM.file, `${packageGM.file}.old`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function savePackageGM(packageGM) {
|
|
47
|
+
fs.writeFileSync(packageGM.file, JSON.stringify(packageGM.data, null, 2), "utf8");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function clamp(value, min, max) {
|
|
51
|
+
return Math.min(Math.max(value, min), max);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function getPSMonitorRAMCommand(processName, interval, name) {
|
|
55
|
+
const psCommand = `
|
|
56
|
+
\$processName = "${processName}"
|
|
57
|
+
\$interval = ${interval}
|
|
58
|
+
\$reportFile = "${name}"
|
|
59
|
+
\$timestamp = Get-Date -Format "yyyy-MM-dd_hh-mm"
|
|
60
|
+
if (\$reportFile -eq "") {
|
|
61
|
+
\$reportFile = "\$processName_\$timestamp-ram-report.csv"
|
|
62
|
+
}
|
|
10
63
|
|
|
11
|
-
|
|
12
|
-
|
|
64
|
+
if (-not (Test-Path \$reportFile)) {
|
|
65
|
+
"date,RAM_MB" | Out-File -FilePath \$reportFile -Encoding UTF8
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
echo "Monitoring RAM usage..."
|
|
69
|
+
|
|
70
|
+
while (\$true) {
|
|
71
|
+
\$date = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
|
|
72
|
+
try {
|
|
73
|
+
\$process = Get-Process -Name \$processName -ErrorAction Stop
|
|
74
|
+
\$ramMB = [math]::Round(\$process.WorkingSet64 / 1MB, 2)
|
|
75
|
+
"\$date,\$ramMB" | Out-File -Append -Encoding utf8 -FilePath \$reportFile
|
|
76
|
+
echo "\$date TEST [${processName}::monitor-ram]: \$ramMB"
|
|
77
|
+
} catch {
|
|
78
|
+
#"\$date,PROCESS_NOT_RUNNING" | Out-File -Append -Encoding utf8 -FilePath \$reportFile
|
|
79
|
+
echo "\$date TEST [${processName}::monitor-ram]: PROCESS_NOT_RUNNING"
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Start-Sleep -Milliseconds \$interval
|
|
83
|
+
}
|
|
84
|
+
`
|
|
85
|
+
|
|
86
|
+
return psCommand
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const program = new Command()
|
|
90
|
+
.version('2.0.1', '-v, --version, ', 'output the current version');
|
|
91
|
+
|
|
92
|
+
const config = program
|
|
93
|
+
.command('config')
|
|
94
|
+
.description('Manage configuration');
|
|
95
|
+
|
|
96
|
+
const configSet = config
|
|
97
|
+
.command('set')
|
|
98
|
+
.description('Set config values');
|
|
99
|
+
|
|
100
|
+
const configUnset = config
|
|
101
|
+
.command('unset')
|
|
102
|
+
.description('Unset config values');
|
|
103
|
+
|
|
104
|
+
program
|
|
105
|
+
.command('init')
|
|
13
106
|
.description('CLI creator for package-gm.json')
|
|
14
107
|
.action(async () => {
|
|
15
108
|
const rl = readline.createInterface({
|
|
@@ -24,28 +117,34 @@ program.command('init')
|
|
|
24
117
|
|
|
25
118
|
const projectPath = process.cwd();
|
|
26
119
|
const basename = path.basename(projectPath);
|
|
27
|
-
const version = "
|
|
120
|
+
const version = "0.0.1";
|
|
28
121
|
const propertyPackage = await askQuestion(`package name: (${basename}) `);
|
|
29
122
|
const propertyVersion = await askQuestion(`version: (${version}) `);
|
|
30
123
|
const propertyDescription = await askQuestion('description: ');
|
|
31
|
-
const
|
|
124
|
+
const propertyYYP = await askQuestion('gamemaker project file (.yyp): ');
|
|
32
125
|
const propertyTest = await askQuestion('test command: ');
|
|
33
126
|
const propertyGit = await askQuestion('git repository: ');
|
|
34
127
|
const propertyKeywords = await askQuestion('keywords: ');
|
|
35
128
|
const propertyAuthor = await askQuestion('author: ');
|
|
36
129
|
const propertyLicense = await askQuestion('license: (ISC) ');
|
|
37
130
|
const data = {
|
|
38
|
-
|
|
39
|
-
|
|
131
|
+
name: propertyPackage === null || propertyPackage === ''
|
|
132
|
+
? basename
|
|
133
|
+
: propertyPackage,
|
|
134
|
+
version: propertyVersion === null || propertyVersion === ''
|
|
135
|
+
? version
|
|
136
|
+
: propertyVersion,
|
|
40
137
|
description: propertyDescription,
|
|
41
|
-
main:
|
|
42
|
-
test: propertyTest,
|
|
138
|
+
main: propertyYYP,
|
|
43
139
|
git: propertyGit,
|
|
44
140
|
keywords: propertyKeywords,
|
|
45
141
|
author: propertyAuthor,
|
|
46
142
|
license: propertyLicense,
|
|
47
|
-
scripts: {
|
|
143
|
+
scripts: {
|
|
144
|
+
test: propertyTest
|
|
145
|
+
},
|
|
48
146
|
dependencies: {},
|
|
147
|
+
runtimes: {},
|
|
49
148
|
};
|
|
50
149
|
|
|
51
150
|
const filePath = path.join(projectPath, 'package-gm.json');
|
|
@@ -65,17 +164,23 @@ program.command('init')
|
|
|
65
164
|
process.exit(0);
|
|
66
165
|
}
|
|
67
166
|
});
|
|
68
|
-
|
|
167
|
+
|
|
168
|
+
program
|
|
169
|
+
.command('watch')
|
|
69
170
|
.description('Watch modules dir and copy code to gamemaker project')
|
|
70
171
|
.action(() => {
|
|
71
172
|
watch(path.normalize(path.join(process.cwd(), 'package-gm.json')))
|
|
72
173
|
});
|
|
73
|
-
|
|
174
|
+
|
|
175
|
+
program
|
|
176
|
+
.command('sync')
|
|
74
177
|
.description('Copy code from modules dir to gamemaker project')
|
|
75
178
|
.action(() => {
|
|
76
179
|
sync(path.normalize(path.join(process.cwd(), 'package-gm.json')))
|
|
77
180
|
});
|
|
78
|
-
|
|
181
|
+
|
|
182
|
+
program
|
|
183
|
+
.command('install')
|
|
79
184
|
.description('Install dependencies listed in package-gm.json to gm_modules folder')
|
|
80
185
|
.option('-c, --clean', 'remove existing gm_modules')
|
|
81
186
|
.option('-s, --shallow', 'git clone will use depth=1 branch=REVISION')
|
|
@@ -83,7 +188,6 @@ program.command('install')
|
|
|
83
188
|
const options = this.opts();
|
|
84
189
|
const clean = options.clean !== undefined;
|
|
85
190
|
const shallow = options.shallow !== undefined;
|
|
86
|
-
const packageJsonPath = 'package-gm.json';
|
|
87
191
|
const modulesDir = 'gm_modules';
|
|
88
192
|
|
|
89
193
|
if (!fs.existsSync(modulesDir)) {
|
|
@@ -93,8 +197,8 @@ program.command('install')
|
|
|
93
197
|
fs.mkdirSync(modulesDir);
|
|
94
198
|
}
|
|
95
199
|
|
|
96
|
-
const
|
|
97
|
-
const dependencies =
|
|
200
|
+
const packageGM = getPackageGM()
|
|
201
|
+
const dependencies = packageGM.data.dependencies;
|
|
98
202
|
Object.entries(dependencies).forEach(([key, dependency]) => {
|
|
99
203
|
console.log(`\n📦️ Install ${key}\n===========${"=".repeat(key.length)}`)
|
|
100
204
|
const modulePath = path.join(modulesDir, key);
|
|
@@ -123,7 +227,9 @@ program.command('install')
|
|
|
123
227
|
console.log('\n\n✅ All dependencies processed.');
|
|
124
228
|
process.exit(0);
|
|
125
229
|
})
|
|
126
|
-
|
|
230
|
+
|
|
231
|
+
program
|
|
232
|
+
.command('run')
|
|
127
233
|
.description('Run the script named <foo>')
|
|
128
234
|
.argument('<foo>', 'script name')
|
|
129
235
|
.action((foo) => {
|
|
@@ -133,9 +239,8 @@ program.command('run')
|
|
|
133
239
|
return process.exit(1);
|
|
134
240
|
}
|
|
135
241
|
|
|
136
|
-
const
|
|
137
|
-
const
|
|
138
|
-
const scriptData = packageData.scripts[foo]
|
|
242
|
+
const packageGM = getPackageGM()
|
|
243
|
+
const scriptData = packageGM.data.scripts[foo]
|
|
139
244
|
if (typeof scriptData !== 'string') {
|
|
140
245
|
console.log(`script ${foo} wasn't found`);
|
|
141
246
|
console.log(`Exited with code 1`);
|
|
@@ -143,6 +248,8 @@ program.command('run')
|
|
|
143
248
|
}
|
|
144
249
|
|
|
145
250
|
const shellScript = `#!/bin/bash
|
|
251
|
+
cd ${path.dirname(packageGM.file).replaceAll("\\", "/")}
|
|
252
|
+
|
|
146
253
|
${scriptData}
|
|
147
254
|
`;
|
|
148
255
|
const bashProcess = spawn("bash", ["-s"], { stdio: ["pipe", "inherit", "inherit"] });
|
|
@@ -153,7 +260,9 @@ program.command('run')
|
|
|
153
260
|
process.exit(code);
|
|
154
261
|
});
|
|
155
262
|
});
|
|
156
|
-
|
|
263
|
+
|
|
264
|
+
program
|
|
265
|
+
.command('generate')
|
|
157
266
|
.description('Generate *.yyp IncludedFiles section')
|
|
158
267
|
.action(function() {
|
|
159
268
|
function getFilesRecursively(dir, root) {
|
|
@@ -171,25 +280,6 @@ program.command('generate')
|
|
|
171
280
|
return files;
|
|
172
281
|
}
|
|
173
282
|
|
|
174
|
-
function findFileUpwardsSync(filename = "gm-cli.env", maxLevels = 99) {
|
|
175
|
-
let currentDir = process.cwd();
|
|
176
|
-
for (let i = 0; i < maxLevels; i++) {
|
|
177
|
-
const candidate = path.join(currentDir, filename);
|
|
178
|
-
if (fs.existsSync(candidate)) {
|
|
179
|
-
return candidate;
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
const parentDir = path.dirname(currentDir);
|
|
183
|
-
if (parentDir === currentDir) {
|
|
184
|
-
break;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
currentDir = parentDir;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
|
|
193
283
|
function parseEnvFile(filePath) {
|
|
194
284
|
const content = fs.readFileSync(filePath, "utf8");
|
|
195
285
|
const result = new Map();
|
|
@@ -209,28 +299,24 @@ program.command('generate')
|
|
|
209
299
|
return result;
|
|
210
300
|
}
|
|
211
301
|
|
|
212
|
-
const envFile = findFileUpwardsSync();
|
|
302
|
+
const envFile = findFileUpwardsSync(".gm-cli.env");
|
|
213
303
|
if (envFile === null) {
|
|
214
|
-
console.error('gm-cli.env was not found')
|
|
304
|
+
console.error('.gm-cli.env was not found')
|
|
215
305
|
return
|
|
216
306
|
}
|
|
217
307
|
|
|
218
|
-
const
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
console.error(`GMS_PROJECT_PATH was not defined in ${envFile}`)
|
|
222
|
-
return
|
|
308
|
+
const packageGM = getPackageGM()
|
|
309
|
+
if (packageGM === null) {
|
|
310
|
+
return null
|
|
223
311
|
}
|
|
224
312
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
const projectPath = path.join(envPath, envMap.get("GMS_PROJECT_PATH")).replaceAll("\\", "/");
|
|
231
|
-
const yypPath = path.join(projectPath, `${envMap.get("GMS_PROJECT_NAME")}.yyp`).replaceAll("\\", "/");
|
|
232
|
-
const yypOldPath = path.join(projectPath, `${envMap.get("GMS_PROJECT_NAME")}.yyp.old`).replaceAll("\\", "/");
|
|
313
|
+
const envPath = path.dirname(envFile).replaceAll("\\", "/");
|
|
314
|
+
const envMap = parseEnvFile(envFile);
|
|
315
|
+
const projectPath = path.dirname(path.join(path.dirname(packageGM.file), packageGM.data.main.replaceAll("\\", "/")));
|
|
316
|
+
const yypPath = path.join(path.dirname(packageGM.file), packageGM.data.main.replaceAll("\\", "/"));
|
|
317
|
+
const yypOldPath = `${yypPath}.old`
|
|
233
318
|
const yyp = fs.readFileSync(yypPath, "utf8");
|
|
319
|
+
console.log(`📝 Backup yyp:`, yypOldPath);
|
|
234
320
|
fs.copyFileSync(yypPath, yypOldPath);
|
|
235
321
|
|
|
236
322
|
const datafilesPath = path.join(projectPath, "datafiles").replaceAll("\\", "/")
|
|
@@ -238,9 +324,12 @@ program.command('generate')
|
|
|
238
324
|
const replaced = yyp.replace(/"IncludedFiles"\s*:\s*\[(.*?)\]/s, `"IncludedFiles":[
|
|
239
325
|
${datafiles.join("\n ")}
|
|
240
326
|
]`);
|
|
327
|
+
console.log(`📝 Save yyp:`, yypPath);
|
|
241
328
|
fs.writeFileSync(yypPath, replaced, "utf8");
|
|
242
329
|
});
|
|
243
|
-
|
|
330
|
+
|
|
331
|
+
program
|
|
332
|
+
.command('make')
|
|
244
333
|
.description('Build and run gamemaker project')
|
|
245
334
|
.option('-t, --target <target>', 'available targets: windows')
|
|
246
335
|
.option('-r, --runtime <type>', 'use VM or YYC runtime')
|
|
@@ -248,15 +337,18 @@ program.command('make')
|
|
|
248
337
|
.option('-l, --launch', 'launch the executable after building')
|
|
249
338
|
.option('-c, --clean', 'make clean build')
|
|
250
339
|
.action(function() {
|
|
340
|
+
const packageGM = getPackageGM()
|
|
251
341
|
const targetMap = new Map([ [ 'windows', 'win' ] ])
|
|
252
342
|
const options = this.opts();
|
|
253
343
|
const config = {
|
|
254
|
-
runtime: '$
|
|
255
|
-
target: '$
|
|
256
|
-
targetExt: 'win',
|
|
344
|
+
runtime: '$GM_CLI_DEFAULT_RUNTIME',
|
|
345
|
+
target: '$GM_CLI_DEFAULT_TARGET',
|
|
257
346
|
clean: 'false',
|
|
258
347
|
launch: 'PackageZip',
|
|
259
|
-
name:
|
|
348
|
+
name: packageGM.data.name,
|
|
349
|
+
zip: packageGM.data.name,
|
|
350
|
+
yyp: path.basename(packageGM.data.main).replaceAll("\\", "/"),
|
|
351
|
+
path: path.join(path.dirname(packageGM.file), path.dirname(packageGM.data.main)).replaceAll("\\", "/"),
|
|
260
352
|
};
|
|
261
353
|
|
|
262
354
|
if (options.runtime !== undefined) {
|
|
@@ -277,25 +369,25 @@ program.command('make')
|
|
|
277
369
|
}
|
|
278
370
|
|
|
279
371
|
if (options.name !== undefined && typeof options.name === 'string' && options.name.trim() !== '') {
|
|
280
|
-
config.
|
|
372
|
+
config.zip = options.name;
|
|
281
373
|
}
|
|
282
374
|
|
|
283
375
|
const shellScript = `#!/bin/bash
|
|
284
376
|
function log_info {
|
|
285
377
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
286
|
-
echo -e "$timestamp
|
|
378
|
+
echo -e "\\\e[90m$timestamp\\\e[0m \\\e[32mINFO\\\e[0m \\\e[35m[gm-cli::make]\\\e[0m $1"
|
|
287
379
|
}
|
|
288
380
|
|
|
289
381
|
function log_error {
|
|
290
382
|
local timestamp=$(date +"%Y-%m-%d %H:%M:%S")
|
|
291
|
-
echo -e "$timestamp
|
|
383
|
+
echo -e "\\\e[90m$timestamp\\\e[0m \\\e[31mERROR\\\e[0m \\\e[35m[gm-cli::make]\\\e[0m $1"
|
|
292
384
|
}
|
|
293
385
|
|
|
294
386
|
gm_cli_env_path=""
|
|
295
387
|
dir=$(realpath "$PWD")
|
|
296
388
|
while [ "$dir" != "/" ]; do
|
|
297
|
-
if [ -f "$dir
|
|
298
|
-
gm_cli_env_path="$dir
|
|
389
|
+
if [ -f "$dir/.gm-cli.env" ]; then
|
|
390
|
+
gm_cli_env_path="$dir/.gm-cli.env"
|
|
299
391
|
log_info "Load configuration '$gm_cli_env_path'"
|
|
300
392
|
set -a
|
|
301
393
|
. "$gm_cli_env_path"
|
|
@@ -305,60 +397,59 @@ program.command('make')
|
|
|
305
397
|
dir=$(dirname "$dir")
|
|
306
398
|
done
|
|
307
399
|
|
|
308
|
-
|
|
400
|
+
runtime_path=$GM_CLI_RUNTIME_PATH
|
|
401
|
+
if [ -z "$runtime_path" ]; then
|
|
402
|
+
log_error "GM_CLI_RUNTIME_PATH must be defined! exit 1"
|
|
403
|
+
exit 1
|
|
404
|
+
fi
|
|
405
|
+
runtime_path=$(realpath $runtime_path)
|
|
406
|
+
|
|
407
|
+
igor_path="$\{GM_CLI_RUNTIME_PATH%/\}/bin/igor/windows/x64/Igor.exe"
|
|
309
408
|
if [ -z "$igor_path" ]; then
|
|
310
|
-
log_error "
|
|
409
|
+
log_error "GM_CLI_RUNTIME_PATH must be defined! exit 1"
|
|
311
410
|
exit 1
|
|
312
411
|
fi
|
|
412
|
+
igor_path=$(realpath $igor_path)
|
|
313
413
|
|
|
314
|
-
project_name=$
|
|
414
|
+
project_name=${config.name}
|
|
315
415
|
if [ -z "$project_name" ]; then
|
|
316
|
-
log_error "
|
|
416
|
+
log_error "package-gm.json name field must be defined! exit 1"
|
|
317
417
|
exit 1
|
|
318
418
|
fi
|
|
319
419
|
|
|
320
|
-
|
|
420
|
+
project_yyp=${config.yyp}
|
|
421
|
+
if [ -z "$project_yyp" ]; then
|
|
422
|
+
log_error "package-gm.json yyp field must be defined! exit 1"
|
|
423
|
+
exit 1
|
|
424
|
+
fi
|
|
425
|
+
|
|
426
|
+
project_path=${config.path}
|
|
321
427
|
if [ -z "$project_path" ]; then
|
|
322
|
-
log_error "
|
|
428
|
+
log_error "package-gm.json yyp field must be defined! exit 1"
|
|
323
429
|
exit 1
|
|
324
430
|
fi
|
|
325
|
-
|
|
326
|
-
project_path=$(dirname "$gm_cli_env_path")/$project_path
|
|
327
431
|
project_path=$(realpath $project_path)
|
|
328
432
|
|
|
329
|
-
user_path=$
|
|
433
|
+
user_path=$GM_CLI_USER_PATH
|
|
330
434
|
if [ -z "$user_path" ]; then
|
|
331
|
-
log_error "
|
|
435
|
+
log_error "GM_CLI_USER_PATH must be defined! exit 1"
|
|
332
436
|
exit 1
|
|
333
437
|
fi
|
|
334
438
|
user_path=$(realpath $user_path)
|
|
335
439
|
|
|
336
|
-
runtime_path=$GMS_RUNTIME_PATH
|
|
337
|
-
if [ -z "$runtime_path" ]; then
|
|
338
|
-
log_error "GMS_RUNTIME_PATH must be defined! exit 1"
|
|
339
|
-
exit 1
|
|
340
|
-
fi
|
|
341
|
-
runtime_path=$(realpath $runtime_path)
|
|
342
|
-
|
|
343
440
|
runtime=${config.runtime}
|
|
344
441
|
if [ -z "$runtime" ]; then
|
|
345
|
-
log_error "
|
|
442
|
+
log_error "GM_CLI_DEFAULT_RUNTIME must be defined! exit 1"
|
|
346
443
|
exit 1
|
|
347
444
|
fi
|
|
348
445
|
|
|
349
446
|
target=${config.target}
|
|
350
447
|
if [ -z "$target" ]; then
|
|
351
|
-
log_error "
|
|
448
|
+
log_error "GM_CLI_DEFAULT_TARGET must be defined! exit 1"
|
|
352
449
|
exit 1
|
|
353
450
|
fi
|
|
354
451
|
|
|
355
|
-
|
|
356
|
-
if [ -z "$target_ext" ]; then
|
|
357
|
-
log_error "GMS_TARGET_EXT must be defined! exit 1"
|
|
358
|
-
exit 1
|
|
359
|
-
fi
|
|
360
|
-
|
|
361
|
-
zip_name=${config.name}
|
|
452
|
+
zip_name=${config.zip}
|
|
362
453
|
echo $zip_name
|
|
363
454
|
if [ -z "$zip_name" ]; then
|
|
364
455
|
log_error "--name must be defined! exit 1"
|
|
@@ -370,20 +461,20 @@ program.command('make')
|
|
|
370
461
|
log_info "Clean '$project_path/tmp/igor'"
|
|
371
462
|
rm -rf $project_path/tmp/igor
|
|
372
463
|
|
|
373
|
-
log_info "Execute shell command:\n$igor_path \\ \n --runtimePath="$runtime_path" \\ \n --runtime=$runtime \\ \n --project="$\{project_path\}/$\{
|
|
464
|
+
log_info "Execute shell command:\n\\\e[33m$igor_path \\ \n --runtimePath="$runtime_path" \\ \n --runtime=$runtime \\ \n --project="$\{project_path\}/$\{project_yyp\}" \\ \n -- $target Clean\n\\\e[0m"
|
|
374
465
|
$igor_path \
|
|
375
466
|
--runtimePath="$runtime_path" \
|
|
376
467
|
--runtime=$runtime \
|
|
377
|
-
--project="$\{project_path\}/$\{
|
|
378
|
-
-- $target Clean
|
|
468
|
+
--project="$\{project_path\}/$\{project_yyp\}" \
|
|
469
|
+
-- $target Clean | GREP_COLORS='mt=01;31' grep --color=always -E 'Error : |$'
|
|
379
470
|
fi
|
|
380
471
|
|
|
381
472
|
log_info "Clean '$\{project_path\}/tmp/igor/out'"
|
|
382
473
|
rm -rf $\{project_path\}/tmp/igor/out
|
|
383
474
|
|
|
384
|
-
log_info "Execute shell command:\n$igor_path \\ \n --project="$\{project_path\}/$\{
|
|
475
|
+
log_info "Execute shell command:\n\\\e[33m$igor_path \\ \n --project="$\{project_path\}/$\{project_yyp\}" \\ \n --user="$user_path" \\ \n --runtimePath="$runtime_path" \\ \n --runtime=$runtime \\ \n --cache="$\{project_path\}/tmp/igor/cache" \\ \n --temp="$\{project_path\}/tmp/igor/temp" \\ \n --of="$\{project_path\}/tmp/igor/out/$\{project_name\}.win" \\ \n --tf="$\{zip_name\}.zip" \\ \n -- $target ${config.launch}\\\e[0m"
|
|
385
476
|
$igor_path \
|
|
386
|
-
--project="$\{project_path\}/$\{
|
|
477
|
+
--project="$\{project_path\}/$\{project_yyp\}" \
|
|
387
478
|
--user="$user_path" \
|
|
388
479
|
--runtimePath="$runtime_path" \
|
|
389
480
|
--runtime=$runtime \
|
|
@@ -391,7 +482,7 @@ program.command('make')
|
|
|
391
482
|
--temp="$\{project_path\}/tmp/igor/temp" \
|
|
392
483
|
--of="$\{project_path\}/tmp/igor/out/$\{project_name\}.win" \
|
|
393
484
|
--tf="$\{zip_name\}.zip" \
|
|
394
|
-
-- $target ${config.launch};
|
|
485
|
+
-- $target ${config.launch} | GREP_COLORS='mt=01;31' grep --color=always -E 'Error : |$'
|
|
395
486
|
|
|
396
487
|
exit 0
|
|
397
488
|
`;
|
|
@@ -404,4 +495,270 @@ program.command('make')
|
|
|
404
495
|
process.exit(code);
|
|
405
496
|
});
|
|
406
497
|
});
|
|
407
|
-
|
|
498
|
+
|
|
499
|
+
program
|
|
500
|
+
.command('env')
|
|
501
|
+
.description('CLI creator for .gm-cli.env')
|
|
502
|
+
.action(async () => {
|
|
503
|
+
const rl = readline.createInterface({
|
|
504
|
+
input: process.stdin,
|
|
505
|
+
output: process.stdout
|
|
506
|
+
});
|
|
507
|
+
const askQuestion = (query) => new Promise(resolve => rl.question(query, resolve));
|
|
508
|
+
|
|
509
|
+
try {
|
|
510
|
+
console.log("This utility will walk you through creating a .gm-cli.env file.");
|
|
511
|
+
|
|
512
|
+
const runtimes = [ "VM", "YYC" ]
|
|
513
|
+
const targets = [ "windows" ]
|
|
514
|
+
|
|
515
|
+
const projectPath = process.cwd();
|
|
516
|
+
const propertyDefaultRuntime = await askQuestion('Default runtime [ VM, YYC ]: ');
|
|
517
|
+
const propertyDefaultTarget = await askQuestion('Default target [ windows ]: ');
|
|
518
|
+
const propertyRuntimePath = await askQuestion('Path to gamemaker runtime: ');
|
|
519
|
+
const propertyUserPath = await askQuestion('Path to gamemaker user: ');
|
|
520
|
+
const data = {
|
|
521
|
+
GM_CLI_DEFAULT_RUNTIME: runtimes.includes(propertyDefaultRuntime) ? propertyDefaultRuntime : runtimes[0],
|
|
522
|
+
GM_CLI_DEFAULT_TARGET: runtimes.includes(propertyDefaultTarget) ? propertyDefaultTarget : targets[0],
|
|
523
|
+
GM_CLI_RUNTIME_PATH: path.normalize(propertyRuntimePath),
|
|
524
|
+
GM_CLI_USER_PATH: path.normalize(propertyUserPath)
|
|
525
|
+
};
|
|
526
|
+
|
|
527
|
+
const filePath = path.join(projectPath, '.gm-cli.env');
|
|
528
|
+
const dataString = Object.entries(data)
|
|
529
|
+
.map(([key, value]) => `${key}="${value}"`)
|
|
530
|
+
.join("\n");
|
|
531
|
+
|
|
532
|
+
console.log(`About to write to ${filePath}:\n\n${dataString}\n\n`);
|
|
533
|
+
const response = await askQuestion(`Is this OK? (yes) `)
|
|
534
|
+
if (typeof response === 'string' && (response.includes('y') || response.includes('Y'))) {
|
|
535
|
+
fs.writeFileSync(filePath, dataString, 'utf8');
|
|
536
|
+
} else {
|
|
537
|
+
console.log('Aborted.\n');
|
|
538
|
+
}
|
|
539
|
+
} catch (error) {
|
|
540
|
+
console.error('An error occurred:', error);
|
|
541
|
+
} finally {
|
|
542
|
+
rl.close();
|
|
543
|
+
process.exit(0);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
546
|
+
|
|
547
|
+
program
|
|
548
|
+
.command('monitor-ram')
|
|
549
|
+
.description('Monitor RAM usage and save it to csv file')
|
|
550
|
+
.option('-i, --interval <interval>', 'step value in seconds (default = 15)')
|
|
551
|
+
.option('-n, --name <name>', 'name of binary')
|
|
552
|
+
.option('-r, --report <report>', 'name of CSV report file')
|
|
553
|
+
.action((options) => {
|
|
554
|
+
const packageGM = getPackageGM()
|
|
555
|
+
const interval = clamp((Number.isNaN(Number(options.interval)) ? 15.0 : Number(options.interval)), 1.0 / 60.0, 999.0)
|
|
556
|
+
const name = options.name === undefined ? packageGM.data.name : options.name
|
|
557
|
+
const report = options.report === undefined ? '' : options.report
|
|
558
|
+
const psCommand = getPSMonitorRAMCommand(name, 1000.0 * interval, report)
|
|
559
|
+
const ps = spawn('powershell.exe', [
|
|
560
|
+
'-NoProfile',
|
|
561
|
+
'-Command',
|
|
562
|
+
psCommand
|
|
563
|
+
]);
|
|
564
|
+
|
|
565
|
+
ps.stdout.on('data', data => {
|
|
566
|
+
console.log(data.toString().replace(/\r?\n$/, ''));
|
|
567
|
+
});
|
|
568
|
+
|
|
569
|
+
ps.stderr.on('data', data => {
|
|
570
|
+
console.error(data.toString().replace(/\r?\n$/, ''));
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
ps.on('close', code => {
|
|
574
|
+
console.log(`Exited with code ${code}`);
|
|
575
|
+
});
|
|
576
|
+
})
|
|
577
|
+
|
|
578
|
+
program
|
|
579
|
+
.command('test')
|
|
580
|
+
.description('Run tests')
|
|
581
|
+
.option('-t, --tests <tests>', 'List of paths to json test cases')
|
|
582
|
+
.option('-b, --build <build>', 'Path to executable')
|
|
583
|
+
.option('-m, --monitorRAM', 'Monitor RAM while testing')
|
|
584
|
+
.action((options) => {
|
|
585
|
+
const packageGM = getPackageGM()
|
|
586
|
+
|
|
587
|
+
const shellMonitorRAMScript = options.monitorRAM === undefined ? `` : `
|
|
588
|
+
set -m
|
|
589
|
+
gm-cli monitor-ram --name \$\{EXE_FILE%.exe\} &
|
|
590
|
+
pid=\$!
|
|
591
|
+
trap "kill -- -\$pid 2>/dev/null" EXIT INT TERM
|
|
592
|
+
`;
|
|
593
|
+
|
|
594
|
+
const shellBuildScript = options.build !== undefined ? `
|
|
595
|
+
cd ${path.dirname(options.build).replaceAll("\\", "/")}
|
|
596
|
+
build_name="\$\{PWD##*/\}"
|
|
597
|
+
|
|
598
|
+
EXE_FILE="${path.basename(options.build)}"
|
|
599
|
+
EXE_COUNT=1
|
|
600
|
+
` : `
|
|
601
|
+
build_name="${packageGM.data.name}_test"
|
|
602
|
+
rm -rf \$build_name.zip
|
|
603
|
+
rm -rf \$build_name
|
|
604
|
+
gm-cli make --name \$build_name
|
|
605
|
+
unzip \$build_name.zip -d \$build_name
|
|
606
|
+
cd \$build_name
|
|
607
|
+
|
|
608
|
+
EXE_FILE=\$(find . -maxdepth 1 -type f -name "*.exe" -printf "%f\n" 2>/dev/null)
|
|
609
|
+
EXE_COUNT=\$(printf "%s\n" "\$EXE_FILE" | grep -c .)
|
|
610
|
+
`;
|
|
611
|
+
|
|
612
|
+
const shellTestScript = options.tests === undefined ? `
|
|
613
|
+
TESTS=\$(find . -type f -name "*test.json" -print0 | xargs -0 echo | sed 's/ /, /g')
|
|
614
|
+
` : `
|
|
615
|
+
TESTS=\"${options.tests}\"
|
|
616
|
+
`
|
|
617
|
+
|
|
618
|
+
const shellCommandScript = `
|
|
619
|
+
TIMESTAMP=\$(date +"%Y-%m-%d_%H-%M")
|
|
620
|
+
OUTPUT_FILE="\$\{TIMESTAMP\}_\$\{EXE_FILE%.exe\}_run-test.log"
|
|
621
|
+
COMMAND="./\$EXE_FILE -output \"\$OUTPUT_FILE\" --tests \\\"\$TESTS\\\""
|
|
622
|
+
|
|
623
|
+
if [ "\$EXE_COUNT" -eq 0 ]; then
|
|
624
|
+
echo "ERROR 1: binary was not found"
|
|
625
|
+
exit 1
|
|
626
|
+
elif [ "\$EXE_COUNT" -gt 1 ]; then
|
|
627
|
+
echo "ERROR 2: found more executables: \$EXE_FILE"
|
|
628
|
+
exit 2
|
|
629
|
+
fi
|
|
630
|
+
`;
|
|
631
|
+
|
|
632
|
+
const shellScript = `#!/bin/bash
|
|
633
|
+
cd ${path.dirname(packageGM.file).replaceAll("\\", "/")}
|
|
634
|
+
|
|
635
|
+
${shellBuildScript}
|
|
636
|
+
|
|
637
|
+
${shellTestScript}
|
|
638
|
+
|
|
639
|
+
${shellCommandScript}
|
|
640
|
+
|
|
641
|
+
${shellMonitorRAMScript}
|
|
642
|
+
|
|
643
|
+
eval "\$COMMAND" | cat
|
|
644
|
+
`
|
|
645
|
+
|
|
646
|
+
const bashProcess = spawn("bash", ["-s"], { stdio: ["pipe", "inherit", "inherit"] });
|
|
647
|
+
bashProcess.stdin.write(shellScript);
|
|
648
|
+
bashProcess.stdin.end();
|
|
649
|
+
bashProcess.on("exit", (code) => {
|
|
650
|
+
console.log(`Exited with code ${code}`);
|
|
651
|
+
process.exit(code);
|
|
652
|
+
});
|
|
653
|
+
})
|
|
654
|
+
|
|
655
|
+
configSet
|
|
656
|
+
.command('dependency <name> <revision>')
|
|
657
|
+
.description('Manage dependencies in package-gm.json')
|
|
658
|
+
.option('--remote <remote>')
|
|
659
|
+
.action((name, revision, options) => {
|
|
660
|
+
const resolve = () => {
|
|
661
|
+
const current = packageGM.data.dependencies[name] ?? {};
|
|
662
|
+
|
|
663
|
+
packageGM.data.dependencies[name] = {
|
|
664
|
+
...current,
|
|
665
|
+
...(options.remote !== undefined && { remote: options.remote }),
|
|
666
|
+
...(revision !== undefined && { revision }),
|
|
667
|
+
};
|
|
668
|
+
|
|
669
|
+
console.log("🔨 Set dependency", name, "as", packageGM.data.dependencies[name])
|
|
670
|
+
};
|
|
671
|
+
|
|
672
|
+
const packageGM = getPackageGM()
|
|
673
|
+
|
|
674
|
+
backupPackageGM(packageGM)
|
|
675
|
+
resolve()
|
|
676
|
+
savePackageGM(packageGM)
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
configSet
|
|
680
|
+
.command('script <name> [command]')
|
|
681
|
+
.description('Manage scripts in package-gm.json')
|
|
682
|
+
.action((name, command = '') => {
|
|
683
|
+
const resolve = () => {
|
|
684
|
+
packageGM.data.scripts[name] = command !== undefined ? command : ''
|
|
685
|
+
console.log("🔨 Set script", name, "as", packageGM.data.scripts[name])
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const packageGM = getPackageGM()
|
|
689
|
+
|
|
690
|
+
backupPackageGM(packageGM)
|
|
691
|
+
resolve()
|
|
692
|
+
savePackageGM(packageGM)
|
|
693
|
+
});
|
|
694
|
+
|
|
695
|
+
configSet
|
|
696
|
+
.command('runtime <name> [supported]')
|
|
697
|
+
.description('Manage runtimes in package-gm.json')
|
|
698
|
+
.action((name, supported = 'true') => {
|
|
699
|
+
const resolve = () => {
|
|
700
|
+
packageGM.data.runtimes[name] = supported === "false" ? supported : "true"
|
|
701
|
+
console.log("🔨 Set runtime", name, "as", supported === "false" ? "false" : "true")
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
const packageGM = getPackageGM()
|
|
705
|
+
|
|
706
|
+
backupPackageGM(packageGM)
|
|
707
|
+
resolve()
|
|
708
|
+
savePackageGM(packageGM)
|
|
709
|
+
});
|
|
710
|
+
|
|
711
|
+
configUnset
|
|
712
|
+
.command('dependency <name>')
|
|
713
|
+
.description('Remove dependencies from package-gm.json')
|
|
714
|
+
.action((name) => {
|
|
715
|
+
const resolve = () => {
|
|
716
|
+
if (name in packageGM.data.dependencies) {
|
|
717
|
+
console.log("🗑️ Unset dependency", name)
|
|
718
|
+
delete packageGM.data.dependencies[name]
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const packageGM = getPackageGM()
|
|
723
|
+
|
|
724
|
+
backupPackageGM(packageGM)
|
|
725
|
+
resolve()
|
|
726
|
+
savePackageGM(packageGM)
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
configUnset
|
|
730
|
+
.command('script <name>')
|
|
731
|
+
.description('Remove scripts from package-gm.json')
|
|
732
|
+
.action((name) => {
|
|
733
|
+
const resolve = () => {
|
|
734
|
+
if (name in packageGM.data.scripts) {
|
|
735
|
+
console.log("🗑️ Unset script", name)
|
|
736
|
+
delete packageGM.data.scripts[name]
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
const packageGM = getPackageGM()
|
|
741
|
+
|
|
742
|
+
backupPackageGM(packageGM)
|
|
743
|
+
resolve()
|
|
744
|
+
savePackageGM(packageGM)
|
|
745
|
+
});
|
|
746
|
+
|
|
747
|
+
configUnset
|
|
748
|
+
.command('runtime <name>')
|
|
749
|
+
.description('Remove runtimes from package-gm.json')
|
|
750
|
+
.action((name) => {
|
|
751
|
+
const resolve = () => {
|
|
752
|
+
if (name in packageGM.data.scripts) {
|
|
753
|
+
console.log("🗑️ Unset runtime", name)
|
|
754
|
+
delete packageGM.data.runtimes[name]
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const packageGM = getPackageGM()
|
|
759
|
+
backupPackageGM(packageGM)
|
|
760
|
+
resolve()
|
|
761
|
+
savePackageGM(packageGM)
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
program.parse(process.argv);
|