Skip to content

Commit

Permalink
move to DockerfileCompiler
Browse files Browse the repository at this point in the history
  • Loading branch information
kla committed Aug 10, 2024
1 parent 99e2b8a commit 3080479
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 89 deletions.
91 changes: 2 additions & 89 deletions src/staxfile/compiler.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'path'
import { readFileSync } from 'fs'
import { load } from 'js-yaml'
import { exit, fileExists } from '~/utils'
import DockerfileCompiler from './dockerfile_compiler'

export default class Compiler {
public staxfile: string
Expand All @@ -21,96 +21,9 @@ export default class Compiler {

try {
process.chdir(this.baseDir)
this.createDockerfile()
new DockerfileCompiler(this.data.defaults.build).compile()
} finally {
process.chdir(cwd)
}
}

private createDockerfile() {
const modules = this.loadModules()
const base = this.parseBase(this.data.build.dockerfile, modules)
console.log(base)
}

private loadModules(): Record<string, string> {
if (!this.data.build.modules)
return {}

const dir = path.resolve(path.dirname(this.data.build.dockerfile))
const modules: Record<string, string> = {}
this.data.build.modules.forEach(item => this.parseModuleFile(`${dir}/modules/${item}`, modules))
return modules
}

private parseModuleFile(file: string, modules: Record<string, string>) {
if (!fileExists(file))
exit(1, `Module file not found: ${file}`)

const contents = readFileSync(file, 'utf-8')
let sectionName: string

this.verifyVariables(file, contents)

if (!contents.includes('# $stax.append_to'))
exit(1, `Must specify at least one "# $stax.append_to" directive in module: ${file}`)

contents.split("\n").forEach((line) => {
let matches = line.match(/# \$stax\.append_to (.*?)$/)

if (matches && matches[1]) {
sectionName = matches[1]
modules[sectionName] ||= ''
if (modules[sectionName] != '') modules[sectionName] += '\n'
modules[sectionName] += `# ${sectionName}: ${file}`
} else if (sectionName)
modules[sectionName] += `\n${line}`
})
return modules
}

private verifyVariables(file: string, contents: string) {
const matches = contents.match(/#{(.*?)}/g)

if (!matches)
return

matches.forEach((match) => {
const name = match.slice(2, -1)

if (!this.data.build.args[name])
exit(1, `Variable ${name} must be defined for ${file}`)
})
}

private args(): string {
return Object.entries(this.data.build.args).map(([name, value]) => `ARG ${name}="${value}"\n`).join('')
}

private parseBase(file: string, modules: Record<string, string>) {
let text = ""

if (!fileExists(file))
exit(1, `File not found: ${file}`)

readFileSync(this.data.build.dockerfile, 'utf-8').split("\n").forEach((line) => {
const matches = line.trim().match(/# \$stax\.section +(.*?)$/)

if (matches && matches[1] && modules[matches[1]])
text += modules[matches[1]]
else
text += line + "\n"
})

text = this.substituteVariables(text)
text = text.replaceAll('# $stax.section args', this.args())
return text
}

private substituteVariables(dockerfile: string): string {
for (const [name, value] of Object.entries(this.data.build.args)) {
dockerfile = dockerfile.replaceAll(`#{${name}}`, value)
}
return dockerfile
}
}
81 changes: 81 additions & 0 deletions src/staxfile/dockerfile_compiler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import path from 'path'
import { readFileSync } from 'fs'
import { exit, fileExists } from '~/utils'

interface BuildOptions {
dockerfile: string;
args: Record<string, string>;
modules: string[];
}

export default class DockerfileCompiler {
public build: BuildOptions

constructor(options: BuildOptions) {
this.build = options
}

public compile() {
const contents: string = readFileSync(this.build.dockerfile, 'utf-8')
const base = this.parse()
console.log(base)
}

private args(): string {
return Object.entries(this.build.args).map(([name, value]) => `ARG ${name}="${value}"\n`).join('')
}

private parse() {
const modules = this.loadModules()
let text = ""

if (!fileExists(this.build.dockerfile))
exit(1, `File not found: ${this.build.dockerfile}`)

readFileSync(this.build.dockerfile, 'utf-8').split("\n").forEach((line) => {
const matches = line.trim().match(/# \$stax\.section +(.*?)$/)

if (matches && matches[1] && modules[matches[1]])
text += modules[matches[1]]
else
text += line + "\n"
})

text = text.replaceAll('# $stax.section args', this.args())
return text
}

private loadModules(): Record<string, string> {
if (!this.build.modules)
return {}

const dir = path.resolve(path.dirname(this.build.dockerfile))
const modules: Record<string, string> = {}
this.build.modules.forEach(item => this.parseModuleFile(`${dir}/modules/${item}`, modules))
return modules
}

private parseModuleFile(file: string, modules: Record<string, string>) {
if (!fileExists(file))
exit(1, `Module file not found: ${file}`)

const contents = readFileSync(file, 'utf-8')
let sectionName: string

if (!contents.includes('# $stax.append_to'))
exit(1, `Must specify at least one "# $stax.append_to" directive in module: ${file}`)

contents.split("\n").forEach((line) => {
let matches = line.match(/# \$stax\.append_to (.*?)$/)

if (matches && matches[1]) {
sectionName = matches[1]
modules[sectionName] ||= ''
if (modules[sectionName] != '') modules[sectionName] += '\n'
modules[sectionName] += `# ${sectionName}: ${file}`
} else if (sectionName)
modules[sectionName] += `\n${line}`
})
return modules
}
}

0 comments on commit 3080479

Please sign in to comment.