From 443fe44cfc1ca00efb1db8651bbb27e0057e6fa0 Mon Sep 17 00:00:00 2001 From: Firebelley Date: Fri, 28 Apr 2023 17:14:40 -0400 Subject: [PATCH] add godot startup prior to build --- .github/workflows/build-example.yml | 2 +- .nvmrc | 2 +- README.md | 4 +- dist/index.js | 203 +++++++++++++++------------- package.json | 6 +- src/godot.ts | 11 ++ yarn.lock | 24 ++-- 7 files changed, 140 insertions(+), 112 deletions(-) diff --git a/.github/workflows/build-example.yml b/.github/workflows/build-example.yml index a9adb503..a5452d5f 100644 --- a/.github/workflows/build-example.yml +++ b/.github/workflows/build-example.yml @@ -17,7 +17,7 @@ jobs: echo "WINE_PATH=$(which wine64)" >> $GITHUB_OUTPUT - name: export game id: export - uses: firebelley/godot-export@v5.0.0 + uses: firebelley/godot-export@v5.1.0 with: godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0/Godot_v4.0-stable_linux.x86_64.zip godot_export_templates_download_url: https://downloads.tuxfamily.org/godotengine/4.0/Godot_v4.0-stable_export_templates.tpz diff --git a/.nvmrc b/.nvmrc index 56bfee43..53a42214 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -v16.10.0 +v16.13.2 diff --git a/README.md b/README.md index b74a300f..364b7a90 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ jobs: - name: export game id: export # Use latest version (see releases for all versions) - uses: firebelley/godot-export@v5.0.0 + uses: firebelley/godot-export@v5.1.0 with: # Defining all the required inputs godot_executable_download_url: https://downloads.tuxfamily.org/godotengine/4.0/Godot_v4.0-stable_linux.x86_64.zip @@ -137,7 +137,7 @@ In order to configure this action to update your game's Windows exe icon, includ # Any other intermediate steps can go here - name: export game - uses: firebelley/godot-export@v5.0.0 + uses: firebelley/godot-export@v5.1.0 with: # ...supply your other options here wine_path: ${{ steps.wine_install.outputs.WINE_PATH }} # set the wine path here which is the output of the wine_install step diff --git a/dist/index.js b/dist/index.js index 3373dc5f..cc9bb6ab 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3031,11 +3031,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }; var _a; Object.defineProperty(exports, "__esModule", ({ value: true })); -exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rename = exports.readlink = exports.readdir = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; +exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; const fs = __importStar(__nccwpck_require__(7147)); const path = __importStar(__nccwpck_require__(1017)); -_a = fs.promises, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; +_a = fs.promises +// export const {open} = 'fs' +, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; +// export const {open} = 'fs' exports.IS_WINDOWS = process.platform === 'win32'; +// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691 +exports.UV_FS_O_EXLOCK = 0x10000000; +exports.READONLY = fs.constants.O_RDONLY; function exists(fsPath) { return __awaiter(this, void 0, void 0, function* () { try { @@ -3216,12 +3222,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", ({ value: true })); exports.findInPath = exports.which = exports.mkdirP = exports.rmRF = exports.mv = exports.cp = void 0; const assert_1 = __nccwpck_require__(9491); -const childProcess = __importStar(__nccwpck_require__(2081)); const path = __importStar(__nccwpck_require__(1017)); -const util_1 = __nccwpck_require__(3837); const ioUtil = __importStar(__nccwpck_require__(1962)); -const exec = util_1.promisify(childProcess.exec); -const execFile = util_1.promisify(childProcess.execFile); /** * Copies a file or folder. * Based off of shelljs - https://github.com/shelljs/shelljs/blob/9237f66c52e5daa40458f94f9565e18e8132f5a6/src/cp.js @@ -3302,61 +3304,23 @@ exports.mv = mv; function rmRF(inputPath) { return __awaiter(this, void 0, void 0, function* () { if (ioUtil.IS_WINDOWS) { - // Node doesn't provide a delete operation, only an unlink function. This means that if the file is being used by another - // program (e.g. antivirus), it won't be deleted. To address this, we shell out the work to rd/del. // Check for invalid characters // https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file if (/[*"<>|]/.test(inputPath)) { throw new Error('File path must not contain `*`, `"`, `<`, `>` or `|` on Windows'); } - try { - const cmdPath = ioUtil.getCmdPath(); - if (yield ioUtil.isDirectory(inputPath, true)) { - yield exec(`${cmdPath} /s /c "rd /s /q "%inputPath%""`, { - env: { inputPath } - }); - } - else { - yield exec(`${cmdPath} /s /c "del /f /a "%inputPath%""`, { - env: { inputPath } - }); - } - } - catch (err) { - // if you try to delete a file that doesn't exist, desired result is achieved - // other errors are valid - if (err.code !== 'ENOENT') - throw err; - } - // Shelling out fails to remove a symlink folder with missing source, this unlink catches that - try { - yield ioUtil.unlink(inputPath); - } - catch (err) { - // if you try to delete a file that doesn't exist, desired result is achieved - // other errors are valid - if (err.code !== 'ENOENT') - throw err; - } } - else { - let isDir = false; - try { - isDir = yield ioUtil.isDirectory(inputPath); - } - catch (err) { - // if you try to delete a file that doesn't exist, desired result is achieved - // other errors are valid - if (err.code !== 'ENOENT') - throw err; - return; - } - if (isDir) { - yield execFile(`rm`, [`-rf`, `${inputPath}`]); - } - else { - yield ioUtil.unlink(inputPath); - } + try { + // note if path does not exist, error is silent + yield ioUtil.rm(inputPath, { + force: true, + maxRetries: 3, + recursive: true, + retryDelay: 300 + }); + } + catch (err) { + throw new Error(`File was unable to be removed ${err}`); } }); } @@ -3533,50 +3497,71 @@ function copyFile(srcFile, destFile, force) { const { hasOwnProperty } = Object.prototype -/* istanbul ignore next */ -const eol = typeof process !== 'undefined' && - process.platform === 'win32' ? '\r\n' : '\n' - -const encode = (obj, opt) => { +const encode = (obj, opt = {}) => { + if (typeof opt === 'string') { + opt = { section: opt } + } + opt.align = opt.align === true + opt.newline = opt.newline === true + opt.sort = opt.sort === true + opt.whitespace = opt.whitespace === true || opt.align === true + /* istanbul ignore next */ + opt.platform = opt.platform || process?.platform + opt.bracketedArray = opt.bracketedArray !== false + + /* istanbul ignore next */ + const eol = opt.platform === 'win32' ? '\r\n' : '\n' + const separator = opt.whitespace ? ' = ' : '=' const children = [] - let out = '' - if (typeof opt === 'string') { - opt = { - section: opt, - whitespace: false, - } - } else { - opt = opt || Object.create(null) - opt.whitespace = opt.whitespace === true + const keys = opt.sort ? Object.keys(obj).sort() : Object.keys(obj) + + let padToChars = 0 + // If aligning on the separator, then padToChars is determined as follows: + // 1. Get the keys + // 2. Exclude keys pointing to objects unless the value is null or an array + // 3. Add `[]` to array keys + // 4. Ensure non empty set of keys + // 5. Reduce the set to the longest `safe` key + // 6. Get the `safe` length + if (opt.align) { + padToChars = safe( + ( + keys + .filter(k => obj[k] === null || Array.isArray(obj[k]) || typeof obj[k] !== 'object') + .map(k => Array.isArray(obj[k]) ? `${k}[]` : k) + ) + .concat(['']) + .reduce((a, b) => safe(a).length >= safe(b).length ? a : b) + ).length } - const separator = opt.whitespace ? ' = ' : '=' + let out = '' + const arraySuffix = opt.bracketedArray ? '[]' : '' - for (const k of Object.keys(obj)) { + for (const k of keys) { const val = obj[k] if (val && Array.isArray(val)) { for (const item of val) { - out += safe(k + '[]') + separator + safe(item) + eol + out += safe(`${k}${arraySuffix}`).padEnd(padToChars, ' ') + separator + safe(item) + eol } } else if (val && typeof val === 'object') { children.push(k) } else { - out += safe(k) + separator + safe(val) + eol + out += safe(k).padEnd(padToChars, ' ') + separator + safe(val) + eol } } if (opt.section && out.length) { - out = '[' + safe(opt.section) + ']' + eol + out + out = '[' + safe(opt.section) + ']' + (opt.newline ? eol + eol : eol) + out } for (const k of children) { - const nk = dotSplit(k).join('\\.') + const nk = splitSections(k, '.').join('\\.') const section = (opt.section ? opt.section + '.' : '') + nk - const { whitespace } = opt const child = encode(obj[k], { + ...opt, section, - whitespace, }) if (out.length && child.length) { out += eol @@ -3588,24 +3573,44 @@ const encode = (obj, opt) => { return out } -const dotSplit = str => - str.replace(/\1/g, '\u0002LITERAL\\1LITERAL\u0002') - .replace(/\\\./g, '\u0001') - .split(/\./) - .map(part => - part.replace(/\1/g, '\\.') - .replace(/\2LITERAL\\1LITERAL\2/g, '\u0001')) +function splitSections (str, separator) { + var lastMatchIndex = 0 + var lastSeparatorIndex = 0 + var nextIndex = 0 + var sections = [] + + do { + nextIndex = str.indexOf(separator, lastMatchIndex) + + if (nextIndex !== -1) { + lastMatchIndex = nextIndex + separator.length + + if (nextIndex > 0 && str[nextIndex - 1] === '\\') { + continue + } + + sections.push(str.slice(lastSeparatorIndex, nextIndex)) + lastSeparatorIndex = nextIndex + separator.length + } + } while (nextIndex !== -1) + + sections.push(str.slice(lastSeparatorIndex)) -const decode = str => { + return sections +} + +const decode = (str, opt = {}) => { + opt.bracketedArray = opt.bracketedArray !== false const out = Object.create(null) let p = out let section = null - // section |key = value - const re = /^\[([^\]]*)\]$|^([^=]+)(=(.*))?$/i + // section |key = value + const re = /^\[([^\]]*)\]\s*$|^([^=]+)(=(.*))?$/i const lines = str.split(/[\r\n]+/g) + const duplicates = {} for (const line of lines) { - if (!line || line.match(/^\s*[;#]/)) { + if (!line || line.match(/^\s*[;#]/) || line.match(/^\s*$/)) { continue } const match = line.match(re) @@ -3624,7 +3629,13 @@ const decode = str => { continue } const keyRaw = unsafe(match[2]) - const isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]' + let isArray + if (opt.bracketedArray) { + isArray = keyRaw.length > 2 && keyRaw.slice(-2) === '[]' + } else { + duplicates[keyRaw] = (duplicates?.[keyRaw] || 0) + 1 + isArray = duplicates[keyRaw] > 1 + } const key = isArray ? keyRaw.slice(0, -2) : keyRaw if (key === '__proto__') { continue @@ -3665,7 +3676,7 @@ const decode = str => { // see if the parent section is also an object. // if so, add it to that, and mark this one for deletion - const parts = dotSplit(k) + const parts = splitSections(k, '.') p = out const l = parts.pop() const nl = l.replace(/\\\./g, '.') @@ -5093,6 +5104,9 @@ async function exportBuilds() { if (WINE_PATH) { configureWindowsExport(); } + if (!USE_GODOT_3) { + await importProject(); + } core.startGroup('✨ Export binaries'); const results = await doExport(); core.endGroup(); @@ -5141,9 +5155,6 @@ async function prepareExecutable() { throw new Error('Could not find Godot executable'); } core.info(`Found executable at ${executablePath}`); - // const finalGodotPath = path.join(path.dirname(executablePath), 'godot'); - // await exec('mv', [executablePath, finalGodotPath]); - // core.addPath(path.dirname(executablePath)); await (0,exec.exec)('chmod', ['+x', executablePath]); godotExecutablePath = executablePath; } @@ -5299,6 +5310,12 @@ async function addEditorSettings() { await io.cp(editorSettingsDist, editorSettingsPath, { force: false }); core.info(`Wrote editor settings to ${editorSettingsPath}`); } +/** Open the editor in headless mode once, to import all assets, creating the `.godot` directory if it doesn't exist. */ +async function importProject() { + core.startGroup('🎲 Import project'); + await (0,exec.exec)(godotExecutablePath, [GODOT_PROJECT_FILE_PATH, '--headless', '-e', '--quit']); + core.endGroup(); +} ;// CONCATENATED MODULE: ./src/file.ts diff --git a/package.json b/package.json index 5a19c5e9..bca21c5a 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,13 @@ "dependencies": { "@actions/core": "^1.10.0", "@actions/exec": "^1.1.1", - "@actions/io": "^1.1.2", - "ini": "^3.0.1", + "@actions/io": "^1.1.3", + "ini": "^4.1.0", "sanitize-filename": "^1.6.3" }, "devDependencies": { "@types/ini": "^1.3.31", - "@types/node": "^17.0.42", + "@types/node": "^18.16.2", "@typescript-eslint/eslint-plugin": "^5.50.0", "@typescript-eslint/parser": "^5.50.0", "@vercel/ncc": "^0.36.1", diff --git a/src/godot.ts b/src/godot.ts index 9e0fe011..c3d52bf4 100644 --- a/src/godot.ts +++ b/src/godot.ts @@ -49,6 +49,10 @@ async function exportBuilds(): Promise { configureWindowsExport(); } + if (!USE_GODOT_3) { + await importProject(); + } + core.startGroup('✨ Export binaries'); const results = await doExport(); core.endGroup(); @@ -286,4 +290,11 @@ async function addEditorSettings(): Promise { core.info(`Wrote editor settings to ${editorSettingsPath}`); } +/** Open the editor in headless mode once, to import all assets, creating the `.godot` directory if it doesn't exist. */ +async function importProject(): Promise { + core.startGroup('🎲 Import project'); + await exec(godotExecutablePath, [GODOT_PROJECT_FILE_PATH, '--headless', '-e', '--quit']); + core.endGroup(); +} + export { exportBuilds }; diff --git a/yarn.lock b/yarn.lock index a5ca30b8..b447638c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -29,10 +29,10 @@ resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.0.1.tgz#81a9418fe2bbdef2d2717a8e9f85188b9c565aca" integrity sha512-rhq+tfZukbtaus7xyUtwKfuiCRXd1hWSfmJNEpFgBQJ4woqPEpsBw04awicjwz9tyG2/MVhAEMfVn664Cri5zA== -"@actions/io@^1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.1.2.tgz#766ac09674a289ce0f1550ffe0a6eac9261a8ea9" - integrity sha512-d+RwPlMp+2qmBfeLYPLXuSRykDIFEwdTA0MMxzS9kh4kvP1ftrc/9fzy6pX6qAjthdXruHQ6/6kjT/DNo5ALuw== +"@actions/io@^1.1.3": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.1.3.tgz#4cdb6254da7962b07473ff5c335f3da485d94d71" + integrity sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q== "@babel/runtime@^7.20.7": version "7.20.13" @@ -137,10 +137,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/node@^17.0.42": - version "17.0.42" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.42.tgz#d7e8f22700efc94d125103075c074396b5f41f9b" - integrity sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ== +"@types/node@^18.16.2": + version "18.16.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.2.tgz#2f610ea71034b3971c312192377f8a7178eb57f1" + integrity sha512-GQW/JL/5Fz/0I8RpeBG9lKp0+aNcXEaVL71c0D2Q0QHDTFvlYKT7an0onCUXj85anv7b4/WesqdfchLc0jtsCg== "@types/semver@^7.3.12": version "7.3.13" @@ -1299,10 +1299,10 @@ inherits@2: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -ini@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ini/-/ini-3.0.1.tgz#c76ec81007875bc44d544ff7a11a55d12294102d" - integrity sha512-it4HyVAUTKBc6m8e1iXWvXSTdndF7HbdN713+kvLrymxTaU4AUBWrJ4vEooP+V7fexnVD3LKcBshjGGPefSMUQ== +ini@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-4.1.0.tgz#3bca65a0ae224f07f8f8b3392d8c94a7f1bb007b" + integrity sha512-HLR38RSF2iulAzc3I/sma4CoYxQP844rPYCNfzGDOHqa/YqVlwuuZgBx6M50/X8dKgzk0cm1qRg3+47mK2N+cQ== internal-slot@^1.0.3: version "1.0.3"