fix: 更新初始化和pack的 cmd
This commit is contained in:
@@ -6,7 +6,6 @@ import FormData from 'form-data';
|
||||
import { getBaseURL, query, storage } from '@/module/query.ts';
|
||||
import { getConfig } from '@/module/index.ts';
|
||||
import inquirer from 'inquirer';
|
||||
import { packLib, unpackLib } from './publish.ts';
|
||||
import chalk from 'chalk';
|
||||
import { installDeps } from '@/uitls/npm.ts';
|
||||
import { upload } from '@/module/download/upload.ts';
|
||||
@@ -293,42 +292,3 @@ const deployLoad = new Command('deploy-load')
|
||||
});
|
||||
app.addCommand(deployLoad);
|
||||
|
||||
const local = new Command('local')
|
||||
.description('本地部署')
|
||||
.argument('<key>', 'key')
|
||||
.option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段')
|
||||
.option('-u, --update', 'query查询 127.0.0.1:11015/api/router?path=local-apps&key=detect')
|
||||
.action(async (key, opts) => {
|
||||
console.log('local deploy');
|
||||
const { outputFilePath } = await packLib(opts?.ignore);
|
||||
const mainAppPath = getConfig().mainAppPath;
|
||||
const appsPath = getConfig().appsPath || path.join(mainAppPath, 'apps');
|
||||
if (!key) {
|
||||
console.error(chalk.red('key is required'));
|
||||
return;
|
||||
}
|
||||
const appPath = path.join(appsPath, key);
|
||||
if (!fs.existsSync(appPath)) {
|
||||
fs.mkdirSync(appPath, { recursive: true });
|
||||
}
|
||||
// 复制应用到apps目录下
|
||||
if (outputFilePath) {
|
||||
await unpackLib(outputFilePath, appPath);
|
||||
fs.unlinkSync(outputFilePath);
|
||||
installDeps({ appPath });
|
||||
if (opts?.update) {
|
||||
const res = await query.post(
|
||||
{ path: 'local-apps', key: 'detect' },
|
||||
{
|
||||
url: `http://127.0.0.1:11015/api/router?path=local-apps&key=detect`,
|
||||
},
|
||||
);
|
||||
if (res.code === 200) {
|
||||
console.log('local deploy success');
|
||||
} else {
|
||||
console.error('local deploy failed', res.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
app.addCommand(local);
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import fs, { createReadStream } from 'fs';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import * as tar from 'tar';
|
||||
import glob from 'fast-glob';
|
||||
import { program, Command } from '@/program.ts';
|
||||
import { getConfig, query } from '@/module/index.ts';
|
||||
import { fileIsExist } from '@/uitls/file.ts';
|
||||
import ignore from 'ignore';
|
||||
import { chalk } from '@/module/chalk.ts';
|
||||
import * as backServices from '@/query/services/index.ts';
|
||||
import inquirer from 'inquirer';
|
||||
@@ -33,43 +31,11 @@ async function collectFileInfo(filePath: string, baseDir = '.'): Promise<any[]>
|
||||
|
||||
return [];
|
||||
}
|
||||
// 解析 .npmignore 文件
|
||||
async function loadNpmIgnore(cwd: string): Promise<ignore.Ignore> {
|
||||
const npmIgnorePath = path.join(cwd, '.npmignore');
|
||||
const ig = ignore();
|
||||
|
||||
try {
|
||||
const content = fs.readFileSync(npmIgnorePath, 'utf-8');
|
||||
ig.add(content);
|
||||
} catch (err) {
|
||||
console.warn('.npmignore not found, using default ignore rules');
|
||||
// 如果没有 .npmignore 文件,使用默认规则
|
||||
ig.add(['node_modules', '.git']);
|
||||
}
|
||||
|
||||
return ig;
|
||||
}
|
||||
// 获取文件列表,兼容 .npmignore
|
||||
async function getFiles(cwd: string, patterns: string[]): Promise<string[]> {
|
||||
const ig = await loadNpmIgnore(cwd);
|
||||
|
||||
// 使用 fast-glob 匹配文件
|
||||
const allFiles = await glob(patterns, {
|
||||
cwd,
|
||||
dot: true, // 包括隐藏文件
|
||||
onlyFiles: false, // 包括目录
|
||||
followSymbolicLinks: true,
|
||||
});
|
||||
|
||||
// 过滤忽略的文件
|
||||
const filteredFiles = allFiles.filter((file) => !ig.ignores(file));
|
||||
return filteredFiles;
|
||||
}
|
||||
/**
|
||||
* 复制文件到 pack-dist
|
||||
* @param files 文件列表
|
||||
* @param files 文件列表, 或者文件夹列表
|
||||
* @param cwd 当前工作目录
|
||||
* @param packDist 打包目录
|
||||
* @param packDist 打包目录 pack-dist
|
||||
*/
|
||||
export const copyFilesToPackDist = async (files: string[], cwd: string, packDist = 'pack-dist') => {
|
||||
const packDistPath = path.join(cwd, packDist);
|
||||
@@ -80,10 +46,16 @@ export const copyFilesToPackDist = async (files: string[], cwd: string, packDist
|
||||
}
|
||||
files.forEach((file) => {
|
||||
const stat = fs.statSync(path.join(cwd, file));
|
||||
let outputFile = file;
|
||||
if (file.startsWith('dist/')) {
|
||||
outputFile = file.replace(/^dist\//, '');
|
||||
} else if (file === 'dist') {
|
||||
outputFile = '';
|
||||
}
|
||||
if (stat.isDirectory()) {
|
||||
fs.cpSync(path.join(cwd, file), path.join(packDistPath, file), { recursive: true });
|
||||
fs.cpSync(path.join(cwd, file), path.join(packDistPath, outputFile), { recursive: true });
|
||||
} else {
|
||||
fs.copyFileSync(path.join(cwd, file), path.join(packDistPath, file), fs.constants.COPYFILE_EXCL);
|
||||
fs.copyFileSync(path.join(cwd, file), path.join(packDistPath, outputFile));
|
||||
}
|
||||
});
|
||||
const packageInfo = await getPackageInfo();
|
||||
@@ -117,10 +89,11 @@ ${filesString}
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
fs.writeFileSync(indexHtmlPath, indexHtmlContent);
|
||||
if (!fileIsExist(indexHtmlPath)) {
|
||||
fs.writeFileSync(indexHtmlPath, indexHtmlContent);
|
||||
}
|
||||
};
|
||||
export const pack = async (opts: { isTar: boolean; packDist?: string }) => {
|
||||
const isTar = opts.isTar;
|
||||
export const pack = async (opts: { packDist?: string }) => {
|
||||
const cwd = process.cwd();
|
||||
const collection: Record<string, any> = {};
|
||||
const packageJsonPath = path.join(cwd, 'package.json');
|
||||
@@ -137,22 +110,17 @@ export const pack = async (opts: { isTar: boolean; packDist?: string }) => {
|
||||
console.error('Invalid package.json:', error);
|
||||
return;
|
||||
}
|
||||
|
||||
let outputFileName = `${packageJson.name}-${packageJson.version}.tgz`
|
||||
.replace('@', '') // 替换特殊字符 @
|
||||
.replace(/[\/\\:*?"<>|]/g, '-'); // 替换特殊字符
|
||||
|
||||
// 当 opts.isTar 为 true 时,输出文件为 tgz 文件
|
||||
const outputFilePath = path.join(cwd, outputFileName);
|
||||
let files = packageJson.files;
|
||||
|
||||
// 从 package.json 的 files 字段收集文件
|
||||
const filesToInclude = packageJson.files
|
||||
? await glob(packageJson.files, {
|
||||
cwd: cwd,
|
||||
dot: true, // 包括隐藏文件
|
||||
onlyFiles: false, // 包括目录
|
||||
followSymbolicLinks: true, // 处理符号链接
|
||||
})
|
||||
const filesToInclude = files
|
||||
? await glob(files, {
|
||||
cwd: cwd,
|
||||
dot: true, // 包括隐藏文件
|
||||
onlyFiles: false, // 包括目录
|
||||
followSymbolicLinks: true, // 处理符号链接
|
||||
ignore: ['node_modules/**', ".git/**", opts.packDist ? opts.packDist + '/**' : ''],
|
||||
})
|
||||
: [];
|
||||
// 确保 README.md 和 dist 存在(忽略大小写检测 README.md)
|
||||
const readmeFile = await findFileInsensitive('README.md');
|
||||
@@ -166,38 +134,23 @@ export const pack = async (opts: { isTar: boolean; packDist?: string }) => {
|
||||
const allFiles = (await Promise.all(filesToInclude.map((file) => collectFileInfo(file)))).flat();
|
||||
|
||||
// 输出文件详细信息
|
||||
console.log('Tarball Contents:');
|
||||
console.log('文件列表:');
|
||||
allFiles.forEach((file) => {
|
||||
console.log(`${file.size}B ${file.path}`);
|
||||
});
|
||||
const totalSize = allFiles.reduce((sum, file) => sum + file.size, 0);
|
||||
const packageSize = (totalSize / 1024).toFixed(2) + ' kB';
|
||||
|
||||
collection.files = allFiles;
|
||||
collection.packageJson = packageJson;
|
||||
collection.totalSize = totalSize;
|
||||
collection.tags = packageJson.app?.tags || packageJson.keywords || [];
|
||||
|
||||
console.log('\nTarball Details');
|
||||
console.log('\n基本信息');
|
||||
console.log(`name: ${packageJson.name}`);
|
||||
console.log(`version: ${packageJson.version}`);
|
||||
isTar && console.log(`filename: ${outputFileName}`);
|
||||
isTar && console.log(`package size: ${packageSize}`);
|
||||
console.log(`total files: ${allFiles.length}`);
|
||||
opts?.isTar && console.log(`Created package: ${outputFileName}`);
|
||||
try {
|
||||
if (opts.isTar) {
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputFilePath,
|
||||
cwd: cwd,
|
||||
},
|
||||
filesToInclude,
|
||||
);
|
||||
} else {
|
||||
copyFilesToPackDist(filesToInclude, cwd, opts.packDist);
|
||||
}
|
||||
copyFilesToPackDist(filesToInclude, cwd, opts.packDist);
|
||||
} catch (error) {
|
||||
console.error('Error creating tarball:', error);
|
||||
}
|
||||
@@ -206,7 +159,7 @@ export const pack = async (opts: { isTar: boolean; packDist?: string }) => {
|
||||
const readmeContent = fs.readFileSync(readme, 'utf-8');
|
||||
collection.readme = readmeContent;
|
||||
}
|
||||
return { collection, outputFilePath, dir: cwd };
|
||||
return { collection, dir: cwd };
|
||||
};
|
||||
export const getPackageInfo = async () => {
|
||||
const cwd = process.cwd();
|
||||
@@ -220,104 +173,16 @@ export const getPackageInfo = async () => {
|
||||
}
|
||||
};
|
||||
|
||||
type PackByIgnoreOpts = {
|
||||
isTar: boolean;
|
||||
packDist?: string;
|
||||
};
|
||||
export const packByIgnore = async (opts: PackByIgnoreOpts) => {
|
||||
let collection: Record<string, any> = {};
|
||||
const cwd = process.cwd();
|
||||
const patterns = ['**/*']; // 匹配所有文件
|
||||
const packageJsonPath = path.join(cwd, 'package.json');
|
||||
let packageJson;
|
||||
try {
|
||||
const packageContent = fs.readFileSync(packageJsonPath, 'utf-8');
|
||||
packageJson = JSON.parse(packageContent);
|
||||
} catch (error) {
|
||||
console.error('Invalid package.json:', error);
|
||||
return;
|
||||
}
|
||||
|
||||
let outputFileName = `${packageJson.name}-${packageJson.version}.tgz`
|
||||
.replace('@', '') // 替换特殊字符 @
|
||||
.replace(/[\/\\:*?"<>|]/g, '-'); // 替换特殊字符
|
||||
|
||||
const outputFilePath = path.join(cwd, outputFileName);
|
||||
|
||||
// 获取符合条件的文件列表
|
||||
const files = await getFiles(cwd, patterns);
|
||||
|
||||
console.log('Files to include in the package:');
|
||||
// files 获取 size 和 path
|
||||
const filesInfo = await Promise.all(files.map((file) => collectFileInfo(file)));
|
||||
const allFiles = filesInfo.flat();
|
||||
allFiles.forEach((file) => {
|
||||
console.log(`${file.size}B ${file.path}`);
|
||||
});
|
||||
|
||||
const totalSize = allFiles.reduce((sum, file) => sum + file.size, 0);
|
||||
const packageSize = (totalSize / 1024).toFixed(2) + ' kB';
|
||||
|
||||
collection.files = allFiles;
|
||||
collection.packageJson = packageJson;
|
||||
collection.totalSize = totalSize;
|
||||
collection.tags = packageJson.app?.tags || packageJson.keywords || [];
|
||||
|
||||
console.log('\nTarball Details');
|
||||
console.log(`package size: ${packageSize}`);
|
||||
console.log(`total files: ${allFiles.length}`);
|
||||
const filesToInclude = files.map((file) => path.relative(cwd, file));
|
||||
try {
|
||||
if (opts.isTar) {
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputFilePath,
|
||||
cwd: cwd,
|
||||
},
|
||||
filesToInclude,
|
||||
);
|
||||
} else {
|
||||
copyFilesToPackDist(filesToInclude, cwd, opts.packDist);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating tarball:', error);
|
||||
}
|
||||
const readme = await findFileInsensitive('README.md');
|
||||
if (readme) {
|
||||
const readmeContent = fs.readFileSync(readme, 'utf-8');
|
||||
collection.readme = readmeContent;
|
||||
}
|
||||
return { collection, outputFilePath, dir: cwd };
|
||||
};
|
||||
/**
|
||||
* 打包应用
|
||||
* @param ignore 是否忽略 .npmignore 文件
|
||||
* @returns 打包结果
|
||||
*/
|
||||
export const packLib = async ({
|
||||
ignore = false,
|
||||
tar = false,
|
||||
packDist = 'pack-dist',
|
||||
}: {
|
||||
ignore?: boolean;
|
||||
tar?: boolean;
|
||||
packDist?: string;
|
||||
}): Promise<{ collection: Record<string, any>; outputFilePath: string; dir: string }> => {
|
||||
if (ignore) {
|
||||
return await packByIgnore({ isTar: tar, packDist });
|
||||
}
|
||||
return await pack({ isTar: tar, packDist });
|
||||
};
|
||||
export const unpackLib = async (filePath: string, cwd: string) => {
|
||||
try {
|
||||
await tar.x({
|
||||
file: filePath,
|
||||
cwd: cwd,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Error extracting tarball:', error);
|
||||
}
|
||||
}): Promise<{ collection: Record<string, any>; dir: string }> => {
|
||||
return await pack({ packDist });
|
||||
};
|
||||
const publishCommand = new Command('publish')
|
||||
.description('发布应用')
|
||||
@@ -384,12 +249,10 @@ const deployLoadFn = async (id: string, fileKey: string, force = false, install
|
||||
};
|
||||
|
||||
const packCommand = new Command('pack')
|
||||
.description('打包应用, 默认使用 package.json 中的 files 字段')
|
||||
.option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段')
|
||||
.description('打包应用, 使用 package.json 中的 files 字段,如果是 dist 的路径,直接复制到 pack-dist 的根目录')
|
||||
.option('-p, --publish', '打包并发布')
|
||||
.option('-u, --update', '发布后显示更新命令, show command for deploy to server')
|
||||
.option('-t, --tar', '打包为 tgz 文件')
|
||||
.option('-d, --packDist <dist>', '打包目录')
|
||||
.option('-d, --packDist <dist>', '打包到的目录')
|
||||
.option('-y, --yes', '确定,直接打包', true)
|
||||
.option('-c, --clean', '清理 package.json中的 devDependencies')
|
||||
.action(async (opts) => {
|
||||
@@ -435,8 +298,6 @@ const packCommand = new Command('pack')
|
||||
appKey = answers.appKey || appKey;
|
||||
}
|
||||
let value = await packLib({
|
||||
ignore: opts.ignore,
|
||||
tar: opts.tar,
|
||||
packDist,
|
||||
});
|
||||
if (opts?.clean) {
|
||||
@@ -448,7 +309,7 @@ const packCommand = new Command('pack')
|
||||
// 运行 deploy 命令
|
||||
// const runDeployCommand = 'envision pack-deploy ' + value.outputFilePath + ' -k ' + appKey;
|
||||
const [_app, _command] = process.argv;
|
||||
let deployDist = opts.isTar ? value.outputFilePath : packDist;
|
||||
let deployDist = packDist;
|
||||
const deployCommand = [_app, _command, 'deploy', deployDist, '-k', appKey, '-v', version, '-u', '-d'];
|
||||
if (opts.org) {
|
||||
deployCommand.push('-o', opts.org);
|
||||
@@ -504,10 +365,14 @@ enum AppType {
|
||||
* pm2 启动
|
||||
*/
|
||||
Pm2SystemApp = 'pm2-system-app',
|
||||
/**
|
||||
* 脚本应用
|
||||
*/
|
||||
ScriptApp = 'script-app',
|
||||
}
|
||||
type ServiceItem = {
|
||||
key: string;
|
||||
status: 'inactive' | 'running' | 'stop' | 'error';
|
||||
status: 'inactive' | 'running' | 'stop' | 'error' | 'unknown';
|
||||
type: AppType;
|
||||
description: string;
|
||||
version: string;
|
||||
|
||||
Reference in New Issue
Block a user