Skip to content
This repository was archived by the owner on Dec 8, 2025. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
83 changes: 47 additions & 36 deletions cli/src/build.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { basename, dirname, join, relative, resolve } from "node:path"
import { readFileSync, writeFileSync, existsSync, readdirSync } from "node:fs"
import { readFileSync, writeFileSync, existsSync, readdirSync, constants } from "node:fs"
import { ensureDirSync, mkdirp, removeSync } from "fs-extra"
import {
compileWithHost,
Expand Down Expand Up @@ -36,7 +36,7 @@ import {
import glob from "fast-glob"

import type { DevsModule } from "@devicescript/vm"
import { readFile, writeFile } from "node:fs/promises"
import { readFile, writeFile, access } from "node:fs/promises"
import { printDmesg } from "./vmworker"
import { EXIT_CODE_COMPILATION_ERROR } from "./exitcodes"
import {
Expand All @@ -58,14 +58,14 @@ export function setupWebsocket() {
require("websocket-polyfill")
// @ts-ignore
global.Blob = require("buffer").Blob
global.WebSocket.prototype.send = function (this: any, data: any) {
global.WebSocket.prototype.send = function(this: any, data: any) {
if (typeof data.valueOf() === "string")
this.connection_.sendUTF(data)
else {
this.connection_.sendBytes(Buffer.from(data))
}
}
global.WebSocket.prototype.close = function (this: any, code, reason) {
global.WebSocket.prototype.close = function(this: any, code, reason) {
this.state_ = WebSocket.CLOSING
if (this.connection_) {
if (code === undefined) this.connection_.sendCloseFrame()
Expand All @@ -81,11 +81,13 @@ export function readDebugInfo() {
let dbg: DebugInfo
try {
dbg = readJSON5Sync(join(BINDIR, DEVS_DBG_FILE))
} catch {}
} catch {
}
return dbg
}

let devsInst: DevsModule

export function setDevsDmesg() {
if (devsInst) {
const dbg = readDebugInfo()
Expand Down Expand Up @@ -160,7 +162,7 @@ export async function devsStartWithNetwork(options: {
export async function getHost(
buildConfig: ResolvedBuildConfig,
options: BuildOptions,
folder: string
folder: string,
) {
const inst = options.verify === false ? undefined : await devsFactory()
const outdir = resolve(options.cwd ?? ".", options.outDir || BINDIR)
Expand Down Expand Up @@ -199,6 +201,7 @@ export async function getHost(
}
return devsHost
}

function toDevsDiag(d: jdspec.Diagnostic): DevsDiagnostic {
return {
category: 1,
Expand Down Expand Up @@ -237,7 +240,7 @@ function compilePackageJson(
tsdir: string,
entryPoint: string,
lcfg: LocalBuildConfig,
errors: DevsDiagnostic[]
errors: DevsDiagnostic[],
) {
const pkgJsonPath = join(tsdir, "package.json")
if (existsSync(pkgJsonPath)) {
Expand All @@ -247,10 +250,10 @@ function compilePackageJson(
let version = pkgJSON.version ?? "(no version)"
if (isGit()) {
const head = execCmd(
"git describe --tags --match 'v[0-9]*' --always"
"git describe --tags --match 'v[0-9]*' --always",
)
let dirty = execCmd(
"git status --porcelain --untracked-file=no --ignore-submodules=untracked"
"git status --porcelain --untracked-file=no --ignore-submodules=untracked",
)
if (!head) dirty = "yes"
const exact = !dirty && head[0] == "v" && !head.includes("-")
Expand Down Expand Up @@ -289,33 +292,33 @@ function compilePackageJson(
}

verboseLog(
`compile: ${lcfg.hwInfo["@name"]} ${lcfg.hwInfo["@version"] ?? ""}`
`compile: ${lcfg.hwInfo["@name"]} ${lcfg.hwInfo["@version"] ?? ""}`,
)
}

function compileServiceSpecs(
tsdir: string,
lcfg: LocalBuildConfig,
errors: DevsDiagnostic[]
errors: DevsDiagnostic[],
) {
const dir = join(tsdir, "services")
lcfg.addServices = []

if (existsSync(dir)) {
const includes: Record<string, jdspec.ServiceSpec> = {}
jacdacDefaultSpecifications.forEach(
spec => (includes[spec.shortId] = spec)
spec => (includes[spec.shortId] = spec),
)
const markdowns = readdirSync(dir, { encoding: "utf-8" }).filter(
fn => /\.md$/i.test(fn) && !/README\.md$/i.test(fn)
fn => /\.md$/i.test(fn) && !/README\.md$/i.test(fn),
)
for (const mdf of markdowns) {
const fn = join(dir, mdf)
const content = readFileSync(fn, { encoding: "utf-8" })
const json = parseServiceSpecificationMarkdownToJSON(
content,
includes,
fn
fn,
)
json.catalog = false
if (json?.errors?.length)
Expand Down Expand Up @@ -346,21 +349,21 @@ export function validateBoard(board: DeviceConfig, baseCfg: RepoInfo) {
function compileBoards(
tsdir: string,
lcfg: LocalBuildConfig,
errors: DevsDiagnostic[]
errors: DevsDiagnostic[],
) {
const dir = join(tsdir, "boards")
lcfg.addBoards = []
const baseCfg = resolveBuildConfig()

if (existsSync(dir)) {
const boards = readdirSync(dir, { encoding: "utf-8" }).filter(fn =>
fn.endsWith(".board.json")
fn.endsWith(".board.json"),
)
for (const boardFn of boards) {
const fullName = join(dir, boardFn)
try {
const board: DeviceConfig = JSON.parse(
readFileSync(fullName, "utf-8")
readFileSync(fullName, "utf-8"),
)
const bid = basename(boardFn, ".board.json")
if (board.id && board.id != bid)
Expand All @@ -375,7 +378,7 @@ function compileBoards(
file: fullName,
line: 1,
message: e.message,
})
}),
)
}
}
Expand All @@ -384,6 +387,7 @@ function compileBoards(

export class CompilationError extends Error {
static NAME = "CompilationError"

constructor(message: string) {
super(message)
this.name = CompilationError.NAME
Expand All @@ -393,7 +397,7 @@ export class CompilationError extends Error {
export function buildConfigFromDir(
dir: string,
entryPoint: string = "",
options: BuildOptions = {}
options: BuildOptions = {},
) {
const lcfg: LocalBuildConfig = {
hwInfo: {},
Expand All @@ -418,7 +422,7 @@ export function buildConfigFromDir(

export async function compileFile(
fn: string,
options: BuildOptions = {}
options: BuildOptions = {},
): Promise<CompilationResult> {
const exists = existsSync(fn)
if (!exists) throw new Error(`source file "${fn}" not found`)
Expand All @@ -438,7 +442,7 @@ export async function compileFile(
const { errors, buildConfig } = buildConfigFromDir(
folder,
entryPoint,
options
options,
)

await saveLibFiles(buildConfig, options)
Expand All @@ -455,7 +459,7 @@ export async function compileFile(
verboseLog(`sha: ${res.dbg.binarySHA256}`)
writeFileSync(
join(folder, outDir, DEVS_DBG_FILE),
JSON.stringify(res.dbg)
JSON.stringify(res.dbg),
)
}

Expand All @@ -471,7 +475,7 @@ export async function compileFile(

export async function saveLibFiles(
buildConfig: ResolvedBuildConfig,
options: BuildOptions
options: BuildOptions,
) {
// pass the user-provided services so they are included in devicescript-specs.d.ts
const prelude = preludeFiles(buildConfig)
Expand All @@ -484,16 +488,18 @@ export async function saveLibFiles(
) {
verboseLog(`not saving files in ${libpath} (source build)`)
} else {
await mkdirp(libpath)
if (!existsSync(libpath))
await mkdirp(libpath)

verboseLog(`saving lib files in ${libpath}`)
for (const fn of Object.keys(prelude)) {
const fnpath = join(pref, fn)
await mkdirp(dirname(fnpath))
const ex = await readFile(fnpath, "utf-8").then(
r => r,
_ => null
)
if (prelude[fn] != ex) await writeFile(fnpath, prelude[fn])
if (!existsSync(libpath))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't sneak in unrelated changes.

await mkdirp(dirname(fnpath))

const ex = readFileSync(fnpath, { encoding: "utf-8" })

if (prelude[fn] != ex) writeFileSync(fnpath, prelude[fn])
}
}

Expand All @@ -518,13 +524,18 @@ export async function saveLibFiles(
// json specs
{
const dir = join(pref, GENDIR)
await mkdirp(dir)
if (!existsSync(dir))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated changes, move to different PR

await mkdirp(dir)

if (existsSync(join(dir, `services.json`)))
return

await writeFile(
join(dir, `services.json`),
JSON.stringify(customServices, null, 2),
{
encoding: "utf-8",
}
},
)
}
}
Expand Down Expand Up @@ -566,9 +577,9 @@ async function buildOnce(file: string, options: BuildOptions) {
const { sizes, functions } = dbg
log(
" " +
Object.keys(sizes)
.map(name => `${name}: ${prettySize(sizes[name])}`)
.join(", ")
Object.keys(sizes)
.map(name => `${name}: ${prettySize(sizes[name])}`)
.join(", "),
)
log(` functions:`)
const resolver = SrcMapResolver.from(dbg)
Expand All @@ -577,7 +588,7 @@ async function buildOnce(file: string, options: BuildOptions) {
.forEach(fn => {
log(` ${fn.name} (${prettySize(fn.size)})`)
fn.users.forEach(user =>
debug(` <-- ${resolver.posToString(user[0])}`)
debug(` <-- ${resolver.posToString(user[0])}`),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this , added by prettier? it kind of add noise to the PR

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, must be prettier. Do you want to remove it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, in general this kind of formatting changes really add noise to a PR and makes the review harder. If you have user settings overriding the repo .prettierrc file, you should disable them.

)
})
}
Expand Down
3 changes: 2 additions & 1 deletion cli/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { dcfg } from "./dcfg"
import {
incVerbose,
setConsoleColors,
setDeveloperMode,
setDeveloperMode, setInteractiveMode,
setQuiet,
verboseLog,
} from "./command"
Expand Down Expand Up @@ -429,6 +429,7 @@ export async function mainCli() {
.action(binPatch)

program.on("option:quiet", () => setQuiet(true))
program.on("option:disable-interactive-mode", () => setInteractiveMode(false))
program.on("option:verbose", incVerbose)
program.on("option:no-colors", () => setConsoleColors(false))
program.on("option:dev", () => {
Expand Down
5 changes: 5 additions & 0 deletions cli/src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ export function logToConsole(priority: LoggerPriority, message: string) {

export let isVerbose = 0
export let isQuiet = false
export let isInteractiveMode = true

export function incVerbose() {
isVerbose++
Expand All @@ -80,6 +81,10 @@ export function setQuiet(v: boolean) {
isQuiet = v
}

export function setInteractiveMode(v: boolean) {
isInteractiveMode = v
}

export function verboseLog(msg: string) {
if (isVerbose) console.debug(wrapColor(90, msg))
}
4 changes: 3 additions & 1 deletion cli/src/devtools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ export async function devtools(
const traceFd = options.trace ? await open(options.trace, "w") : null

// passive bus to sniff packets
const transports = createTransports(options)
const transports = await createTransports(options)
const bus = new JDBus(transports, {
client: false,
disableRoleManager: true,
Expand Down Expand Up @@ -430,6 +430,8 @@ async function rebuild(args: BuildReqArgs) {
opts.verify = false
opts.quiet = true

await compileFile(args.filename, opts);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are we compiling twice now?


const res = await compileFile(args.filename, opts)

let deployStatus = ""
Expand Down
17 changes: 7 additions & 10 deletions cli/src/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { addBoard } from "./addboard"
import { readJSON5Sync } from "./jsonc"
import { MARKETPLACE_EXTENSION_ID } from "@devicescript/interop"
import { TSDOC_TAGS } from "@devicescript/compiler"
import { getPackageInstallerCommand, isYarnRepo } from "./packageInstaller"

const MAIN = "src/main.ts"
const GITIGNORE = ".gitignore"
Expand Down Expand Up @@ -408,16 +409,12 @@ function writeFiles(dir: string, options: InitOptions, files: FileSet) {
return cwd
}

function isYarn(cwd: string, options: InitOptions) {
const yarnlock = pathExistsSync(join(cwd, "yarn.lock"))
return yarnlock || options.yarn
}

async function runInstall(cwd: string, options: InitOptions) {
if (options.install) {
const cmd = isYarn(cwd, options) ? "yarn" : "npm"
log(`install dependencies using ${cmd}...`)
spawnSync(cmd, ["install"], {
const [packageManagerCmd, ...packageManagerArgs] = getPackageInstallerCommand();

log(`install dependencies using ${packageManagerCmd}...`)
spawnSync(packageManagerCmd, packageManagerArgs, {
shell: true,
stdio: "inherit",
cwd,
Expand All @@ -442,7 +439,7 @@ export async function init(dir: string | undefined, options: InitOptions) {
log(`Configuring DeviceScript project...`)

const files = { ...optionalFiles }
if (isYarn(".", options)) patchYarnFiles(files)
if (isYarnRepo() || options.yarn) patchYarnFiles(files)

// write template files
const cwd = writeFiles(dir, options, files)
Expand Down Expand Up @@ -681,7 +678,7 @@ export async function addNpm(options: AddNpmOptions) {
files["src/index.ts"] += `export * from "./${fn.slice(0, -3)}"\n`
}

if (isYarn(".", options)) patchYarnFiles(files)
if (isYarnRepo() || options.yarn) patchYarnFiles(files)

const cwd = writeFiles(".", options, files)

Expand Down
Loading