+70
-40
@@ -1,53 +1,83 @@
|
||||
const os = require('os');
|
||||
const fs = require("fs");
|
||||
const osutil = require("../util/osutil")
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const { execFileSync } = require("child_process");
|
||||
|
||||
function matchDistName(cur, dists){
|
||||
const list = []
|
||||
for (let dist of dists) {
|
||||
if ( cur.curOS === dist.os && cur.curPlatform === dist.platform) {
|
||||
list.push( dist )
|
||||
}
|
||||
else if ( cur.curOS === dist.os && "cross" === dist.platform) {
|
||||
list.unshift( dist )
|
||||
}
|
||||
else if ( "cross" === dist.os && cur.curPlatform === dist.platform) {
|
||||
list.unshift( dist )
|
||||
}
|
||||
}
|
||||
return list
|
||||
function now() {
|
||||
return new Date().toISOString();
|
||||
}
|
||||
|
||||
function verifyChecksum(filePath, checksum) {
|
||||
if (!checksum) {
|
||||
return;
|
||||
}
|
||||
const [alg, expected] = checksum.split(":", 2);
|
||||
if (!alg || !expected) {
|
||||
return;
|
||||
}
|
||||
const crypto = require("crypto");
|
||||
const actual = crypto.createHash(alg).update(fs.readFileSync(filePath)).digest("hex");
|
||||
if (actual !== expected) {
|
||||
throw new Error(`文件校验失败 ${filePath}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = async function install(remote, id){
|
||||
const cur = osutil.cur();
|
||||
|
||||
if ( ! id ) {
|
||||
id = "kit"
|
||||
function unpackArtifact(artifact, localPath, versionDir) {
|
||||
if (artifact.type !== "archive" || !artifact.unpack) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取本地版本
|
||||
const localInfo = osutil.choise([
|
||||
require("../windows/local").getModuleInfo,
|
||||
require("../linux/local").getModuleInfo,
|
||||
])( id )
|
||||
const extractDir = path.resolve(path.dirname(localPath), "_extracted");
|
||||
fs.mkdirSync(extractDir, { recursive: true });
|
||||
const format = artifact.archive_format || "zip";
|
||||
if (format === "zip") {
|
||||
if (process.platform === "win32") {
|
||||
const source = localPath.replace(/'/g, "''");
|
||||
const target = extractDir.replace(/'/g, "''");
|
||||
execFileSync("powershell.exe", ["-NoProfile", "-Command", `Expand-Archive -Path '${source}' -DestinationPath '${target}' -Force`], { stdio: "inherit" });
|
||||
} else {
|
||||
execFileSync("unzip", ["-o", localPath, "-d", extractDir], { stdio: "inherit" });
|
||||
}
|
||||
} else if (["tar", "tar.gz", "tgz", "tar.xz"].includes(format)) {
|
||||
execFileSync("tar", ["-xf", localPath, "-C", extractDir], { stdio: "inherit" });
|
||||
}
|
||||
|
||||
$logger.info("local version", localInfo.version)
|
||||
artifact.extracted_path = path.relative(versionDir, extractDir).replace(/\\/g, "/");
|
||||
if (artifact.entry_point) {
|
||||
artifact.extracted_entry_point = path.posix.join(artifact.extracted_path, artifact.entry_point.replace(/\\/g, "/"));
|
||||
}
|
||||
}
|
||||
|
||||
// 确认远程版本文件是否存在
|
||||
const remoteInfo = await remote.wGetModuleInfo(id)
|
||||
$logger.info("remote latest version", remoteInfo.latest.version)
|
||||
module.exports = async function install(remote, id) {
|
||||
const parsed = remote.parseProjectVersion(id || "kit");
|
||||
const projectId = parsed.projectId;
|
||||
const project = await remote.getProjectMetadata(projectId);
|
||||
const version = parsed.version || project.latest_version;
|
||||
if (!version) {
|
||||
throw new Error(`远程模块没有可安装版本 ${projectId}`);
|
||||
}
|
||||
|
||||
const dists = matchDistName(cur, remoteInfo.latest.dist)
|
||||
const dist = dists.pop()
|
||||
const versionMeta = await remote.getVersionMetadata(projectId, version);
|
||||
const artifacts = remote.getMatchingArtifacts(versionMeta);
|
||||
if (artifacts.length < 1) {
|
||||
throw new Error(`没有匹配当前平台的文件 ${projectId}@${version}`);
|
||||
}
|
||||
|
||||
await remote.wDownload(
|
||||
"/modules/" + id + "/" + remoteInfo.latest.version + "/" + cur.curOS + "/" + cur.curPlatform + "/" + dist.filename,
|
||||
localInfo.homeDir + "/" + dist.filename,
|
||||
)
|
||||
const root = remote.getLocalModuleRoot(projectId);
|
||||
const versionDir = path.resolve(root, "versions", version);
|
||||
fs.mkdirSync(versionDir, { recursive: true });
|
||||
|
||||
fs.writeFileSync( localInfo.homeDir + "/version", remoteInfo.latest.version );
|
||||
for (const artifact of artifacts) {
|
||||
const localPath = await remote.downloadArtifact(projectId, version, artifact, versionDir);
|
||||
verifyChecksum(localPath, artifact.checksum || (versionMeta.checksums && versionMeta.checksums[artifact.path]));
|
||||
unpackArtifact(artifact, localPath, versionDir);
|
||||
}
|
||||
|
||||
$logger.info("当前版本", remoteInfo.latest.version )
|
||||
const localVersionMeta = Object.assign({}, versionMeta, { installed_at: now(), artifacts });
|
||||
fs.writeFileSync(path.resolve(versionDir, ".version.json"), JSON.stringify(localVersionMeta, null, 4), "utf-8");
|
||||
|
||||
}
|
||||
const state = remote.getInstallState(projectId);
|
||||
const action = state.current_version ? "switch" : "install";
|
||||
await remote.activate(projectId, version, action);
|
||||
$logger.info(`当前版本 ${projectId}@${version}`);
|
||||
return version;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user