Port node build tool to 0.97

This commit is contained in:
Filip Maciejewski 2019-05-09 02:24:58 +02:00
parent 15c8ec22fd
commit d628c4c3f0
No known key found for this signature in database
GPG Key ID: 53D1504CC3DBCD46
12 changed files with 5367 additions and 1 deletions

View File

@ -11,3 +11,27 @@ jobs:
- run:
name: Validate Config style
command: python tools/config_style_checker.py
pack:
docker:
- image: circleci/node
steps:
- checkout
- run:
name: Install dependencies
command: npm install --loglevel=error
working_directory: ~/project/tools/buildtool
- run:
name: Pack PBOs
command: npx gulp
working_directory: ~/project/tools/buildtool
- store_artifacts:
path: ~/project/_build/pbo
destination: 'KP-Liberation'
workflows:
version: 2
build:
jobs:
- pack
- validate

3
.gitignore vendored
View File

@ -47,4 +47,5 @@ Temporary Items
.apdisk
# Build directory
build/
_build/
node_modules/

24
tools/build.bat Normal file
View File

@ -0,0 +1,24 @@
@echo off
rem Check that https://nodejs.org/en/download/ exists before continuing
where /q node
if ERRORLEVEL 1 (
echo node is missing. Ensure it is installed. It can be downloaded from:
echo https://nodejs.org/en/download/
timeout 30
exit /b
)
rem CD into build tool directory
cd %~dp0buildtool
rem Install dependencies and build missions
call npm install --loglevel=error
call npx gulp
cd ..
echo.
pause
exit /b

84
tools/buildtool/README.md Normal file
View File

@ -0,0 +1,84 @@
# KP Liberation builder
## Requirements
nodejs version >=7.
## Usage
```bash
# Install dependencies
npm install
# Run mission build
npm run build
# Run task with local gulp via npx
npx gulp <task_name>
# With gulp-cli and gulp 4 installed globally
gulp <task_name>
```
| Task | Desc |
| ----------- | ---------------------------------------------- |
| clean | removes `build/` dir |
| build | assembles missionfolder and sets config values |
| pbo | packs missionfolders into PBOs |
| zip | creates release ZIPs |
| __default__ | runs _build_, _pbo_ and _zip_ |
Build files will be outputted to `build/` dir.
## Configuration
### presets.json
This file should contain an JSON __array__ of `Presets`, for every preset one mission file will be built.
Every `Preset` entry should have following structure:
```javascript
{
// Source folder with mission.sqm, relative to <missionsFolder>
// If mission.sqm is in root of <missionsFolder> should be set to empty string
"sourceFolder": "kp_liberation.Altis",
// Name and map is used to build output directory: <missionName>.<map>
// Name different than source allows to build multiple version of mission on same map
// Combination of <missionName> and <map> should be unique for every preset
"missionName": "kp_liberation",
"map": "Altis",
// Keys of <variables> object represent variables in <configFile>.
// These variables values will be set to corresponding value in <variables>
"configFile": "kp_liberation_config.sqf",
"variables": {
"KP_liberation_preset_blufor": 0,
"KP_liberation_preset_opfor": 0,
"KP_liberation_preset_resistance": 0,
"KP_liberation_preset_civilians": 0,
"KP_liberation_arsenal": 0
}
}
```
### gulpfile.ts
`paths` variable in _gulpfile_ holds filesystem paths required to build missions.
```typescript
/**
* Mission folders configuration
*/
const paths: FolderStructureInfo = {
// Folder with mission scripts
frameworkFolder: resolve('..', 'Missionframework'),
// Folder with base mission.sqm folders
missionsFolder: resolve('..', 'Missionbasefiles'),
// Output directory
workDir: resolve("./build")
};
```

View File

@ -0,0 +1,10 @@
[
{
"sourceFolder": "kp_liberation.Altis",
"missionName": "kp_liberation",
"map": "Altis",
"configFile": "KPLIB_config.sqf",
"variables": {
}
}
]

139
tools/buildtool/gulpfile.ts Normal file
View File

@ -0,0 +1,139 @@
import * as gulp from "gulp";
import * as gulpReplace from "gulp-replace";
import * as gulpPbo from "gulp-armapbo";
import * as gulpZip from "gulp-zip";
import * as vinylPaths from "vinyl-paths";
import * as del from "del";
import { resolve } from "path";
import { MissionPaths } from "./src";
import { Preset, FolderStructureInfo } from "./src";
const ROOT_DIR = resolve('..', '..');
const presets: Preset[] = require('./_presets.json');
/**
* Mission folders configuration
*/
const paths: FolderStructureInfo = {
frameworkFolder: resolve(ROOT_DIR, 'Missionframework'),
missionsFolder: resolve(ROOT_DIR, 'Missionbasefiles'),
workDir: resolve(ROOT_DIR, "_build")
};
/**
* Create gulp tasks
*/
let taskNames: string[] = [];
let taskNamesPbo: string[] = [];
let taskNamesZip: string[] = [];
for (let preset of presets) {
const mission = new MissionPaths(preset, paths);
const taskName = [preset.missionName, preset.map].join('.');
taskNames.push('mission_' + taskName);
gulp.task('mission_' + taskName, gulp.series(
/** Copy mission framework to output dir */
function copyFramework() {
return gulp.src(mission.getFrameworkPath().concat('/**/*'))
.pipe(gulp.dest(mission.getOutputDir()));
},
/** Copy mission.sqm to output dir */
function copyMissionSQM() {
return gulp.src(mission.getMissionSqmPath())
.pipe(gulp.dest(mission.getOutputDir()));
},
/** Replace variables values in configuration file */
function replaceVariables() {
let src = gulp.src(mission.getMissionConfigFilePath());
const variables = Object.getOwnPropertyNames(preset.variables);
for (let variable of variables) {
// https://regex101.com/r/YknC8r/1
const regex = new RegExp(`(${variable} += +)(?:\\d+|".+")`, 'ig');
const value = JSON.stringify(preset.variables[variable]);
// replace variable value
src = src.pipe(gulpReplace(regex, `$1${value}`));
}
return src.pipe(gulp.dest(mission.getOutputDir()));
}
));
/**
* Pack PBOs
*/
taskNamesPbo.push('pack_' + taskName);
gulp.task('pack_' + taskName, () => {
return gulp.src(mission.getOutputDir() + '/**/*')
.pipe(gulpPbo({
fileName: mission.getFullName() + '.pbo',
progress: false,
verbose: false,
// Do not compress (SLOW)
compress: true ? [] : [
'**/*.sqf',
'mission.sqm',
'description.ext'
]
}))
.pipe(gulp.dest(mission.getWorkDir() + '/pbo'));
});
/**
* Create ZIP files
*/
taskNamesZip.push('zip_' + taskName);
gulp.task('zip_' + taskName, () => {
return gulp.src([
resolve(ROOT_DIR, 'LICENSE'),
resolve(ROOT_DIR, 'CHANGELOG.md'),
resolve(ROOT_DIR, 'README.md')
], {
base: ROOT_DIR // Change base dir to have correct relative paths in ZIP
})
.pipe(
gulp.src(
resolve(mission.getWorkDir(), 'pbo', mission.getFullName() + '.pbo'), {
base: resolve(mission.getWorkDir(), 'pbo') // Change base dir to have correct relative paths in ZIP
})
)
.pipe(gulpZip(
mission.getFullName() + '.zip'
))
.pipe(gulp.dest(mission.getWorkDir()))
});
}
// Main tasks
gulp.task('clean', () => {
return gulp.src(paths.workDir)
.pipe(vinylPaths(del));
});
gulp.task('build', gulp.series(taskNames));
gulp.task('pbo', gulp.series(taskNamesPbo));
gulp.task('zip', gulp.series(taskNamesZip));
gulp.task('default',
gulp.series(
gulp.task('build'),
gulp.task('pbo'),
// gulp.task('zip'),
)
);

4912
tools/buildtool/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,25 @@
{
"name": "kp_liberation",
"engines": {
"node": ">=7"
},
"dependencies": {
"@types/del": "^3.0.0",
"@types/gulp": "^4.0.5",
"@types/gulp-replace": "0.0.31",
"@types/gulp-zip": "^4.0.0",
"@types/vinyl-paths": "0.0.31",
"del": "^3.0.0",
"gulp": "^4.0.0",
"gulp-armapbo": "^1.1.3",
"gulp-replace": "^0.6.1",
"gulp-zip": "^4.1.0",
"smart-zip": "0.0.9",
"ts-node": "^4.1.0",
"typescript": "^2.7.1",
"vinyl-paths": "^2.1.0"
},
"scripts": {
"build": "npx gulp"
}
}

View File

@ -0,0 +1,56 @@
export interface Preset {
/**
* Path to folder with mission.sqm relative to "missionsFolder".
* If mission.sqm is in root of "missionsFolder" should be empty string.
*
* @see FolderStructureInfo.missionsFolder
*/
readonly sourceFolder: string;
/**
* Path to file with mission configuration.
* Replacement of variables will be applied here.
*/
readonly configFile: string;
/**
* Name of mission (part before mapname)
*/
readonly missionName: string;
/**
* Map name
*/
readonly map: string;
/**
* key=>val of values to replace in config file
* @see {VariablesReplacements}
*/
readonly variables: VariablesReplacements;
}
export interface VariablesReplacements {
/** Key should be name of variable as set in SQF file, its value will be replaced with one from entry. */
readonly [key: string]: any;
}
export interface FolderStructureInfo {
/**
* Folder of folders with mission.sqm.
* Value of "sourceFolder" from Preset will be appended to this path.
*
* @see {Preset}
*/
readonly missionsFolder: string;
/**
* Path to folder with mission framework files.
*/
readonly frameworkFolder: string;
/**
* Directory containing built missions
*/
readonly workDir: string;
}

View File

@ -0,0 +1,72 @@
import { Preset, FolderStructureInfo } from './Config';
import * as path from "path";
export class MissionPaths {
static readonly missionSQM = 'mission.sqm';
private preset: Preset;
private folderStructure: FolderStructureInfo;
constructor(preset: Preset, folderStructure: FolderStructureInfo) {
this.preset = preset;
this.folderStructure = folderStructure;
}
public getMap(): string {
return this.preset.map;
}
public getName(): string {
return this.preset.missionName;
}
public getFullName(): string {
return [this.getName(), this.getMap()].join('.');
}
public getWorkDir(): string {
return this.folderStructure.workDir;
}
/**
* Get path to source mission.sqm file
*/
public getMissionSqmPath(): string {
return path.resolve(
this.folderStructure.missionsFolder,
this.preset.sourceFolder,
'mission.sqm'
);
}
/**
* Get path to folder with mission framework files.
*/
public getFrameworkPath(): string {
return path.resolve(this.folderStructure.frameworkFolder);
}
/**
* Get path to folder containing mission files
*/
public getOutputDir(): string {
return path.resolve(
this.folderStructure.workDir,
this.getFullName()
);
}
/**
* Get path to file with mission configuration.
* As defined in preset.
*/
public getMissionConfigFilePath(): string {
return path.resolve(
this.getOutputDir(),
this.preset.configFile
);
}
}

View File

@ -0,0 +1,4 @@
export * from "./MissionPaths";
export * from "./Config";

View File

@ -0,0 +1,15 @@
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"strictNullChecks": true,
"module": "commonjs",
"target": "es6",
"noUnusedParameters": true,
"noUnusedLocals": true,
"noImplicitAny": true
},
"include": [
"./src/"
]
}