Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Commit

Permalink
fix(generate): keep steps before first stage of base dockerfile
Browse files Browse the repository at this point in the history
 fixes #350
  • Loading branch information
rudxde committed Apr 15, 2022
1 parent 28f0af7 commit 9427d3f
Show file tree
Hide file tree
Showing 17 changed files with 302 additions and 121 deletions.
2 changes: 1 addition & 1 deletion packages/generate/src/extended-docker-syntax.ts
Expand Up @@ -29,7 +29,7 @@ async function applyExtendedDockerSyntaxCopy(step: string, pkg: Package): Promis
const [_, fromStage, chown, ifExistsFlag, slimFlag, filesList, destination] = step.match(isCopy)!;
if (fromStage) {
const [_, fromStageName] = fromStage.match(/--from=(\S*)/) ?? [];
const isLocalStage = pkg.dockerFile!.find(x => x.originalName === fromStageName);
const isLocalStage = pkg.dockerFile!.stages.find(x => x.originalName === fromStageName);
if (isLocalStage) {
return `COPY --from=${isLocalStage.name} ${chown || ''} ${filesList} ${destination}`;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/generate/src/iterate-dependencies.ts
Expand Up @@ -3,15 +3,15 @@ import { PackageGraph } from '@lerna/package-graph';
import { runTopologically } from '@lerna/run-topologically';
import { IGenerateArgs } from './args';
import { Package } from './package';
import { DockerStage } from './read-dockerfile';
import { Dockerfile } from './read-dockerfile';

export async function iterateDependencies(
args: IGenerateArgs,
lernaPackages: lernaPackage[],
packageGraph: PackageGraph,
concurrency: number,
rejectCycles?: boolean,
defaultDockerFile?: DockerStage[],
defaultDockerFile?: Dockerfile,
): Promise<Package[]> {
const packages: Package[] = [];
await runTopologically(
Expand Down
10 changes: 6 additions & 4 deletions packages/generate/src/lerna-command.ts
Expand Up @@ -32,11 +32,13 @@ export class Dockerize extends Command {
defaultDockerFile = await readDockerfile(templateDockerFileName);
}

const baseStage = baseDockerFile[baseDockerFile.length - 1];
const baseStage = baseDockerFile.stages[baseDockerFile.stages.length - 1];
baseStage.name = 'base';

const result: string[] = [];
for (let baseStage of baseDockerFile) {
const result: string[] = [
...baseDockerFile.preStage,
];
for (let baseStage of baseDockerFile.stages) {
result.push(getDockerFileFromInstruction(baseStage.baseImage, baseStage.name, baseStage.platform));
result.push(...baseStage.stepsBeforeInstall);
if (baseStage.install) {
Expand Down Expand Up @@ -93,7 +95,7 @@ export class Dockerize extends Command {

// overwrite final docker stage
if (finalDockerfileName) {
finalStages = await readDockerfile(finalDockerfileName);
finalStages = (await readDockerfile(finalDockerfileName)).stages;
}

for (let finalStage of finalStages) {
Expand Down
19 changes: 11 additions & 8 deletions packages/generate/src/package.ts
@@ -1,6 +1,6 @@
import { PackageGraphNode } from '@lerna/package-graph';
import { Package as LernaPackage } from '@lerna/package';
import { DockerStage, readDockerfile } from './read-dockerfile';
import { Dockerfile, DockerStage, readDockerfile } from './read-dockerfile';
import { promises } from 'fs';
import { join as joinPath, relative } from 'path';
import { getDependenciesTransitive } from './get-dependencies-transitive';
Expand All @@ -15,7 +15,7 @@ export type PackageMap = Map<string, Package>;

export class Package {

dockerFile?: DockerStage[];
dockerFile?: Dockerfile;

constructor(
public name: string,
Expand Down Expand Up @@ -46,7 +46,7 @@ export class Package {
return undefined;
}

async loadDockerfile(defaultDockerFile?: DockerStage[]): Promise<DockerStage[]> {
async loadDockerfile(defaultDockerFile?: Dockerfile): Promise<Dockerfile> {
const dockerFileName = await this.findDockerfile();
if (!dockerFileName && !defaultDockerFile) {
throw new Error(`No Dockerfile for the package ${this.name} and no default docker file was found!`);
Expand All @@ -58,7 +58,10 @@ export class Package {
getLogger().info(`using custom dockerfile for package ${this.name}`);
this.dockerFile = await readDockerfile(dockerFileName);
}
this.dockerFile = this.dockerFile!.map((stage, i) => this.scopeDockerStage(stage, i));
this.dockerFile = {
stages: this.dockerFile!.stages.map((stage, i) => this.scopeDockerStage(stage, i)),
preStage: this.dockerFile!.preStage,
};
return this.dockerFile!;
}

Expand All @@ -76,7 +79,7 @@ export class Package {
if (!this.args.addPrepareStages) {
return this.getBuildStageName();
}
return this.dockerFile[this.dockerFile.length - 1].prepareStageName;
return this.dockerFile.stages[this.dockerFile.stages.length - 1].prepareStageName;
}

getBuildStageName(): string | undefined {
Expand All @@ -87,7 +90,7 @@ export class Package {
if (!this.dockerFile) {
return undefined;
}
return this.dockerFile[this.dockerFile.length - 1];
return this.dockerFile.stages[this.dockerFile.stages.length - 1];
}

stageHasInstall(stage?: DockerStage): boolean {
Expand All @@ -102,9 +105,9 @@ export class Package {
return [];
}
const result: string[] = [];
for (let stage of this.dockerFile) {
for (let stage of this.dockerFile.stages) {
let baseImage = stage.baseImage;
const baseImageIsLocalStage = this.dockerFile!.find(x => x.originalName === baseImage);
const baseImageIsLocalStage = this.dockerFile!.stages.find(x => x.originalName === baseImage);
if (baseImageIsLocalStage) {
baseImage = baseImageIsLocalStage.name!;
}
Expand Down
23 changes: 19 additions & 4 deletions packages/generate/src/read-dockerfile.ts
Expand Up @@ -19,32 +19,45 @@ export interface DockerStage {
install?: IInstallOptions;
}

export interface Dockerfile {
stages: DockerStage[];
preStage: string[];
}


export async function readDockerfile(path: string): Promise<DockerStage[]> {
export async function readDockerfile(path: string): Promise<Dockerfile> {
const dockerfile = (await promises.readFile(path)).toString();
const steps = splitInSteps(dockerfile);
const result = [];
let currentStep = 0;
let preStage: string[] = [];
while (true) {
const readStageResult = readStage(steps, currentStep);
if (!readStageResult) {
break;
}
currentStep = readStageResult.endIndex + 1;
result.push(readStageResult.stage);
if (preStage.length === 0 && readStageResult.preStage.length > 0) {
preStage = readStageResult.preStage;
}
}
if (result.length === 0) {
getLogger().warn(`The dockerfile '${path}' appears to be empty.`);
}
return result;
return {
preStage: preStage,
stages: result,
};
}

export function readStage(steps: string[], startIndex: number): { stage: DockerStage; endIndex: number } | undefined {
export function readStage(steps: string[], startIndex: number): { stage: DockerStage; endIndex: number; preStage: string[] } | undefined {
let i = startIndex;
let baseImage;
let stageName;
let platform;
const isStageFromClause = /(FROM|from)(\s--platform=(\S+))? ([a-zA-Z0-9:_\-@.\/]*)( as ([a-zA-Z0-9:_-]*))?/;
const preStage = [];
const isStageFromClause = /(FROM|from)(\s--platform=(\S+))? ([a-zA-Z0-9:_\-@.\/${}]*)( as ([a-zA-Z0-9:_-]*))?/;
for (; ; i++) {
if (i >= steps.length) {
return undefined;
Expand All @@ -57,6 +70,7 @@ export function readStage(steps: string[], startIndex: number): { stage: DockerS
i++;
break;
}
preStage.push(steps[i]);
}
const stepsBeforeInstall: string[] = [];
const stepsAfterInstall: string[] = [];
Expand Down Expand Up @@ -93,6 +107,7 @@ export function readStage(steps: string[], startIndex: number): { stage: DockerS
stepsAfterInstall,
install: installHit,
},
preStage,
};
}

Expand Down

0 comments on commit 9427d3f

Please sign in to comment.