-
Notifications
You must be signed in to change notification settings - Fork 37
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
attempt to fix autoreload file watching
- Loading branch information
Showing
6 changed files
with
226 additions
and
0 deletions.
There are no files selected for viewing
138 changes: 138 additions & 0 deletions
138
src/build/experimental/commands/compile/file_watcher/file_watcher.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import { Actor, ActorMethod, ActorSubclass } from '@dfinity/agent'; | ||
import { watch } from 'chokidar'; | ||
import { writeFile } from 'fs/promises'; | ||
|
||
import { createAuthenticatedAgent } from '../../../../../../dfx'; | ||
import { generateUploaderIdentity } from '../../upload_assets/uploader_identity'; | ||
import { compile as compileJavaScript } from '../javascript'; | ||
|
||
type ActorReloadJs = ActorSubclass<_SERVICE>; | ||
interface _SERVICE { | ||
_azle_reload_js: ActorMethod< | ||
[bigint, bigint, Uint8Array, bigint, number], | ||
void | ||
>; | ||
} | ||
|
||
// We have made this mutable to help with speed | ||
// We don't want to have to create the agent on each file change | ||
let actor: ActorReloadJs | undefined; | ||
|
||
const reloadedJsPath = process.argv[2]; | ||
const canisterId = process.argv[3]; | ||
const mainPath = process.argv[4]; | ||
const wasmedgeQuickJsPath = process.argv[5]; | ||
const esmAliases = JSON.parse(process.argv[6]); | ||
const esmExternals = JSON.parse(process.argv[7]); | ||
const canisterName = process.argv[8]; | ||
const postUpgradeIndex = Number(process.argv[9]); | ||
|
||
// TODO https://github.com/demergent-labs/azle/issues/1664 | ||
const watcher = watch([`**/*.ts`, `**/*.js`], { | ||
ignored: ['**/.dfx/**', '**/.azle/**', '**/node_modules/**', '**/target/**'] | ||
}); | ||
|
||
watcher.on('all', async (event, path) => { | ||
if (actor === undefined) { | ||
actor = await createActorReloadJs(canisterName); | ||
} | ||
|
||
if (process.env.AZLE_VERBOSE === 'true') { | ||
console.info('event', event); | ||
console.info('path', path); | ||
} | ||
|
||
if (event === 'change') { | ||
try { | ||
await reloadJs( | ||
actor, | ||
reloadedJsPath, | ||
mainPath, | ||
wasmedgeQuickJsPath | ||
); | ||
} catch (error) { | ||
console.error(error); | ||
} | ||
} | ||
}); | ||
|
||
async function reloadJs( | ||
actor: ActorReloadJs, | ||
reloadedJsPath: string, | ||
mainPath: string, | ||
wasmedgeQuickJsPath: string | ||
): Promise<void> { | ||
const javaScript = await compileJavaScript( | ||
mainPath, | ||
wasmedgeQuickJsPath, | ||
esmAliases, | ||
esmExternals | ||
); | ||
|
||
const reloadedJs = Buffer.from(javaScript); | ||
|
||
const chunkSize = 2_000_000; // The current message limit is about 2 MiB | ||
const timestamp = process.hrtime.bigint(); | ||
let chunkNumber = 0n; | ||
|
||
for (let i = 0; i < reloadedJs.length; i += chunkSize) { | ||
const chunk = reloadedJs.slice(i, i + chunkSize); | ||
|
||
if (process.env.AZLE_VERBOSE === 'true') { | ||
console.info( | ||
`Uploading chunk: ${timestamp}, ${chunkNumber}, ${chunk.length}, ${reloadedJs.length}` | ||
); | ||
} | ||
|
||
actor | ||
._azle_reload_js( | ||
timestamp, | ||
chunkNumber, | ||
chunk, | ||
BigInt(reloadedJs.length), | ||
postUpgradeIndex | ||
) | ||
.catch((error) => { | ||
if (process.env.AZLE_VERBOSE === 'true') { | ||
console.error(error); | ||
} | ||
}); | ||
|
||
chunkNumber += 1n; | ||
} | ||
|
||
if (process.env.AZLE_VERBOSE === 'true') { | ||
console.info(`Finished uploading chunks`); | ||
} | ||
|
||
await writeFile(reloadedJsPath, reloadedJs); | ||
} | ||
|
||
async function createActorReloadJs( | ||
canisterName: string | ||
): Promise<ActorReloadJs> { | ||
const identityName = generateUploaderIdentity(canisterName); | ||
const agent = await createAuthenticatedAgent(identityName); | ||
|
||
return Actor.createActor( | ||
({ IDL }) => { | ||
return IDL.Service({ | ||
_azle_reload_js: IDL.Func( | ||
[ | ||
IDL.Nat64, | ||
IDL.Nat64, | ||
IDL.Vec(IDL.Nat8), | ||
IDL.Nat64, | ||
IDL.Int32 | ||
], | ||
[], | ||
[] | ||
) | ||
}); | ||
}, | ||
{ | ||
agent, | ||
canisterId | ||
} | ||
); | ||
} |
4 changes: 4 additions & 0 deletions
4
src/build/experimental/commands/compile/file_watcher/file_watcher_loader.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#!/usr/bin/env node | ||
|
||
import 'tsx'; | ||
import('./file_watcher.ts'); |
61 changes: 61 additions & 0 deletions
61
src/build/experimental/commands/compile/file_watcher/setup_file_watcher.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
import { spawn } from 'child_process'; | ||
import { join } from 'path'; | ||
|
||
import { execSyncPretty } from '../../../../stable/utils/exec_sync_pretty'; | ||
import { AZLE_PACKAGE_PATH } from '../../../../stable/utils/global_paths'; | ||
|
||
export function setupFileWatcher( | ||
reloadedJsPath: string, | ||
canisterId: string, | ||
mainPath: string, | ||
wasmedgeQuickJsPath: string, | ||
esmAliases: Record<string, string>, | ||
esmExternals: string[], | ||
canisterName: string, | ||
postUpgradeIndex: number | ||
): void { | ||
try { | ||
// TODO should we check that this was successful in killing | ||
// TODO the process and then warn the user if not? | ||
// TODO should we figure out why the || true | ||
// TODO does not result in a 0 exit code | ||
// TODO and look into removing the try catch? | ||
execSyncPretty(`pkill -f ./file_watcher_loader.js || true`); | ||
} catch (error) { | ||
// For some reason pkill throws even with || true | ||
} | ||
|
||
if (process.env.AZLE_AUTORELOAD !== 'true') { | ||
return; | ||
} | ||
|
||
const watcherProcess = spawn( | ||
'node', | ||
[ | ||
join( | ||
AZLE_PACKAGE_PATH, | ||
'src', | ||
'build', | ||
'experimental', | ||
'commands', | ||
'compile', | ||
'file_watcher', | ||
'file_watcher_loader.js' | ||
), | ||
reloadedJsPath, | ||
canisterId, | ||
mainPath, | ||
wasmedgeQuickJsPath, | ||
JSON.stringify(esmAliases), | ||
JSON.stringify(esmExternals), | ||
canisterName, | ||
postUpgradeIndex.toString() | ||
], | ||
{ | ||
detached: true, | ||
stdio: 'inherit' | ||
} | ||
); | ||
|
||
watcherProcess.unref(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters