chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
import {
|
||||
formatFiles,
|
||||
generateFiles,
|
||||
GeneratorCallback,
|
||||
readNxJson,
|
||||
readProjectConfiguration,
|
||||
runTasksInSerial,
|
||||
Tree,
|
||||
updateProjectConfiguration,
|
||||
detectPackageManager,
|
||||
workspaceRoot,
|
||||
offsetFromRoot,
|
||||
joinPathFragments,
|
||||
} from '@nx/devkit';
|
||||
import { initGenerator as dockerInitGenerator } from '@nx/docker/generators';
|
||||
import { SetUpDockerOptions } from './schema';
|
||||
import { join } from 'path';
|
||||
import { existsSync } from 'fs';
|
||||
|
||||
function normalizeOptions(
|
||||
tree: Tree,
|
||||
setupOptions: SetUpDockerOptions
|
||||
): SetUpDockerOptions {
|
||||
return {
|
||||
...setupOptions,
|
||||
project: setupOptions.project ?? readNxJson(tree).defaultProject,
|
||||
targetName: setupOptions.targetName ?? 'docker:build',
|
||||
buildTarget: setupOptions.buildTarget ?? 'build',
|
||||
skipDockerPlugin: setupOptions.skipDockerPlugin ?? false,
|
||||
};
|
||||
}
|
||||
|
||||
function sanitizeProjectName(projectName: string): string {
|
||||
return projectName
|
||||
.toLowerCase()
|
||||
.replace(/[@\/]/g, '-')
|
||||
.replace(/[^a-z0-9._-]/g, '-')
|
||||
.replace(/-+/g, '-')
|
||||
.replace(/^-|-$/g, '');
|
||||
}
|
||||
|
||||
async function addDocker(tree: Tree, options: SetUpDockerOptions) {
|
||||
let installTask = () => {};
|
||||
if (!options.skipDockerPlugin) {
|
||||
installTask = await dockerInitGenerator(tree, { skipFormat: true });
|
||||
}
|
||||
const projectConfig = readProjectConfiguration(tree, options.project);
|
||||
|
||||
const outputPath =
|
||||
projectConfig.targets[options.buildTarget]?.options['outputPath'];
|
||||
|
||||
if (!projectConfig) {
|
||||
throw new Error(`Cannot find project configuration for ${options.project}`);
|
||||
}
|
||||
|
||||
if (!outputPath && !options.outputPath) {
|
||||
throw new Error(
|
||||
`The output path for the project ${options.project} is not defined. Please provide it as an option to the generator.`
|
||||
);
|
||||
}
|
||||
|
||||
const sanitizedProjectName = sanitizeProjectName(options.project);
|
||||
const finalOutputPath = options.outputPath ?? outputPath;
|
||||
|
||||
// Calculate build location based on skipDockerPlugin flag
|
||||
let buildLocation: string;
|
||||
if (options.skipDockerPlugin) {
|
||||
// Legacy mode: use workspace-relative paths
|
||||
// docker target is set to run at project root, so ensure offset to workspace root
|
||||
buildLocation = joinPathFragments(
|
||||
offsetFromRoot(projectConfig.root),
|
||||
finalOutputPath
|
||||
);
|
||||
} else {
|
||||
// New mode: use project-relative paths
|
||||
// Remove the project root prefix from the output path
|
||||
const projectRootWithSlash = projectConfig.root + '/';
|
||||
buildLocation = finalOutputPath.startsWith(projectRootWithSlash)
|
||||
? finalOutputPath.substring(projectRootWithSlash.length)
|
||||
: finalOutputPath.startsWith(projectConfig.root)
|
||||
? finalOutputPath.substring(projectConfig.root.length)
|
||||
: 'dist';
|
||||
}
|
||||
|
||||
const packageManager = existsSync(projectConfig.root)
|
||||
? detectPackageManager(projectConfig.root)
|
||||
: detectPackageManager(workspaceRoot);
|
||||
|
||||
generateFiles(tree, join(__dirname, './files'), projectConfig.root, {
|
||||
tmpl: '',
|
||||
buildLocation,
|
||||
project: options.project,
|
||||
projectPath: projectConfig.root,
|
||||
sanitizedProjectName,
|
||||
skipDockerPlugin: options.skipDockerPlugin,
|
||||
packageManager,
|
||||
});
|
||||
|
||||
return installTask;
|
||||
}
|
||||
|
||||
export function updateProjectConfig(tree: Tree, options: SetUpDockerOptions) {
|
||||
let projectConfig = readProjectConfiguration(tree, options.project);
|
||||
|
||||
if (options.skipDockerPlugin) {
|
||||
// Use sanitized project name for Docker image tag
|
||||
const sanitizedProjectName = sanitizeProjectName(options.project);
|
||||
|
||||
projectConfig.targets[`${options.targetName}`] = {
|
||||
dependsOn: [`${options.buildTarget}`, 'prune'],
|
||||
command: `docker build . -t ${sanitizedProjectName}`,
|
||||
options: {
|
||||
cwd: projectConfig.root,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
projectConfig.targets[`${options.targetName}`] = {
|
||||
dependsOn: [`${options.buildTarget}`, 'prune'],
|
||||
};
|
||||
}
|
||||
|
||||
updateProjectConfiguration(tree, options.project, projectConfig);
|
||||
}
|
||||
|
||||
export async function setupDockerGenerator(
|
||||
tree: Tree,
|
||||
setupOptions: SetUpDockerOptions
|
||||
) {
|
||||
const tasks: GeneratorCallback[] = [];
|
||||
const options = normalizeOptions(tree, setupOptions);
|
||||
|
||||
const installTask = await addDocker(tree, options);
|
||||
tasks.push(installTask);
|
||||
updateProjectConfig(tree, options);
|
||||
|
||||
if (!options.skipFormat) {
|
||||
await formatFiles(tree);
|
||||
}
|
||||
|
||||
return runTasksInSerial(...tasks);
|
||||
}
|
||||
|
||||
export default setupDockerGenerator;
|
||||
Reference in New Issue
Block a user