Skip to content

Commit

Permalink
Compile mods as part of the deploy
Browse files Browse the repository at this point in the history
  • Loading branch information
m417z committed Dec 21, 2024
1 parent f201b64 commit 8bbf181
Show file tree
Hide file tree
Showing 2 changed files with 133 additions and 60 deletions.
22 changes: 22 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,30 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Clone last deployed content
run: git clone --branch gh-pages --single-branch --depth 1 https://github.com/ramensoftware/windhawk-mods.git ${{ runner.temp }}/last_deploy
- name: Cache Windhawk
id: cache-windhawk
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/windhawk
key: v1-${{ runner.os }}-1.5.1
- name: Extract Windhawk
if: steps.cache-windhawk.outputs.cache-hit != 'true'
run: |
installer_url="https://github.com/ramensoftware/windhawk/releases/download/v1.5.1/windhawk_setup.exe"
installer_path="${{ runner.temp }}/windhawk_setup.exe"
echo "Downloading $installer_url to $installer_path"
curl -L "$installer_url" -o "$installer_path"
extract_path="${{ runner.temp }}\windhawk"
echo "Extracting $installer_path to $extract_path"
MSYS_NO_PATHCONV=1 "$installer_path" /S /PORTABLE "/D=$extract_path"
- name: Install dependencies
run: npm install
env:
WINDHAWK_MODS_LAST_DEPLOY_PATH: ${{ runner.temp }}\last_deploy
WINDHAWK_PATH: ${{ runner.temp }}\windhawk
- name: Prepare static content
run: npx tsx deploy.ts
- name: Deploy
Expand Down
171 changes: 111 additions & 60 deletions deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,64 +81,35 @@ function getModModifiedTime(modId: string) {
return time * 1000;
}

async function enrichCatalog(catalog: Record<string, any>) {
const url = 'https://update.windhawk.net/mods_catalog_enrichment.json';
const enrichment = await fetchJson(url);

const app = {
version: enrichment.app.version,
};

const mods: Record<string, any> = {};
for (const [id, metadata] of Object.entries(catalog)) {
const { id: idFromMetadata, ...rest } = metadata;
if (id !== idFromMetadata) {
throw new Error(`Expected ${id} === ${idFromMetadata}`);
}

mods[id] = {
metadata: rest,
details: {
published: getModCreatedTime(id),
updated: getModModifiedTime(id),
defaultSorting: 0,
rating: 0,
users: 0,
ratingUsers: 0,
...enrichment.mods[id]?.details,
},
};

if (enrichment.mods[id]?.featured) {
mods[id].featured = true;
}
function findCachedMod(modId: string, version: string, arch: string) {
const lastDeployPath = process.env.WINDHAWK_MODS_LAST_DEPLOY_PATH;
if (!lastDeployPath) {
throw new Error('WINDHAWK_MODS_LAST_DEPLOY_PATH is not set');
}

return {
app,
mods,
};
const modFile = path.join(lastDeployPath, 'mods', modId, `${version}_${arch}.dll`);
return fs.existsSync(modFile) ? modFile : null;
}

async function generateModCatalog() {
const modSourceUtils = new ModSourceUtils('mods');
const catalog = modSourceUtils.getMetadataOfMods('en-US');
return await enrichCatalog(catalog);
}

function getModChangelogTextForVersion(modId: string, modVersion: string, commitMessage: string) {
const overridePath = path.join('changelog_override', modId, `${modVersion}.md`);
if (fs.existsSync(overridePath)) {
return fs.readFileSync(overridePath, 'utf8').trim();
function compileMod(modFilePath: string, output32FilePath: string, output64FilePath: string) {
const windhawkPath = process.env.WINDHAWK_PATH;
if (!windhawkPath) {
throw new Error('WINDHAWK_PATH is not set');
}

let messageTrimmed = commitMessage.trim();
if (messageTrimmed.includes('\n')) {
// Remove first line.
return messageTrimmed.replace(/^.* \(#\d+\)\n\n/, '').trim();
} else {
// Only remove trailing PR number if it's the only line.
return messageTrimmed.replace(/ \(#\d+\)$/, '').trim();
const result = child_process.spawnSync('py', [
'scripts/compile_mod.py',
'-w',
windhawkPath,
'-f',
modFilePath,
'-o32',
output32FilePath,
'-o64',
output64FilePath,
], { encoding: 'utf8', stdio: 'inherit' });
if (result.status !== 0) {
throw new Error('Compiling ' + modFilePath + ' failed with status ' + result.status);
}
}

Expand Down Expand Up @@ -195,6 +166,17 @@ function generateModData(modId: string, changelogPath: string, modDir: string) {

fs.writeFileSync(modVersionFilePath, modFile);

const modVersionCompiled32FilePath = path.join(modDir, `${metadata.version}_32.dll`);
const modVersionCompiled64FilePath = path.join(modDir, `${metadata.version}_64.dll`);
const cachedMod32Path = findCachedMod(modId, metadata.version, '32');
const cachedMod64Path = findCachedMod(modId, metadata.version, '64');
if (cachedMod32Path && cachedMod64Path) {
fs.copyFileSync(cachedMod32Path, modVersionCompiled32FilePath);
fs.copyFileSync(cachedMod64Path, modVersionCompiled64FilePath);
} else {
compileMod(modVersionFilePath, modVersionCompiled32FilePath, modVersionCompiled64FilePath);
}

const commitTime = parseInt(gitExec([
'log',
'--format=%ct',
Expand Down Expand Up @@ -229,16 +211,86 @@ function generateModData(modId: string, changelogPath: string, modDir: string) {
fs.writeFileSync(versionsPath, JSON.stringify(versions));
}

function generateModsData(modIds: string[]) {
function generateModsData() {
const changelogDir = 'changelogs';
if (!fs.existsSync(changelogDir)) {
fs.mkdirSync(changelogDir);
}

for (const modId of modIds) {
const changelogPath = path.join(changelogDir, `${modId}.md`);
const modDir = path.join('mods', modId);
generateModData(modId, changelogPath, modDir);
const modsSourceDir = fs.opendirSync('mods');
try {
let modsSourceDirEntry: fs.Dirent | null;
while ((modsSourceDirEntry = modsSourceDir.readSync()) !== null) {
if (modsSourceDirEntry.isFile() && modsSourceDirEntry.name.endsWith('.wh.cpp')) {
const modId = modsSourceDirEntry.name.slice(0, -'.wh.cpp'.length);
const changelogPath = path.join(changelogDir, `${modId}.md`);
const modDir = path.join('mods', modId);
generateModData(modId, changelogPath, modDir);
}
}
} finally {
modsSourceDir.closeSync();
}
}

async function enrichCatalog(catalog: Record<string, any>) {
const url = 'https://update.windhawk.net/mods_catalog_enrichment.json';
const enrichment = await fetchJson(url);

const app = {
version: enrichment.app.version,
};

const mods: Record<string, any> = {};
for (const [id, metadata] of Object.entries(catalog)) {
const { id: idFromMetadata, ...rest } = metadata;
if (id !== idFromMetadata) {
throw new Error(`Expected ${id} === ${idFromMetadata}`);
}

mods[id] = {
metadata: rest,
details: {
published: getModCreatedTime(id),
updated: getModModifiedTime(id),
defaultSorting: 0,
rating: 0,
users: 0,
ratingUsers: 0,
...enrichment.mods[id]?.details,
},
};

if (enrichment.mods[id]?.featured) {
mods[id].featured = true;
}
}

return {
app,
mods,
};
}

async function generateModCatalog() {
const modSourceUtils = new ModSourceUtils('mods');
const catalog = modSourceUtils.getMetadataOfMods('en-US');
return await enrichCatalog(catalog);
}

function getModChangelogTextForVersion(modId: string, modVersion: string, commitMessage: string) {
const overridePath = path.join('changelog_override', modId, `${modVersion}.md`);
if (fs.existsSync(overridePath)) {
return fs.readFileSync(overridePath, 'utf8').trim();
}

let messageTrimmed = commitMessage.trim();
if (messageTrimmed.includes('\n')) {
// Remove first line.
return messageTrimmed.replace(/^.* \(#\d+\)\n\n/, '').trim();
} else {
// Only remove trailing PR number if it's the only line.
return messageTrimmed.replace(/ \(#\d+\)$/, '').trim();
}
}

Expand Down Expand Up @@ -370,12 +422,11 @@ function generateRssFeed() {
}

async function main() {
generateModsData();

const catalog = await generateModCatalog();
fs.writeFileSync('catalog.json', JSONstringifyOrder(catalog, 4));

const modIds = Object.keys(catalog.mods);
generateModsData(modIds);

fs.writeFileSync('updates.atom', generateRssFeed());

const srcPath = 'public';
Expand Down

0 comments on commit 8bbf181

Please sign in to comment.