153 lines
4.8 KiB
TypeScript
153 lines
4.8 KiB
TypeScript
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
// Licensed under the MIT license.
|
|
|
|
import AdmZip from "adm-zip";
|
|
import fs from "fs";
|
|
import fsExtra from "fs-extra";
|
|
import path from "path";
|
|
import util from "util";
|
|
import { exec } from "child_process";
|
|
import { convert } from "office-addin-manifest-converter";
|
|
import { ExpectedError } from "office-addin-usage-data";
|
|
|
|
/* global console process */
|
|
|
|
const execAsync = util.promisify(exec);
|
|
const skipBackup: string[] = ["node_modules"];
|
|
|
|
export async function convertProject(
|
|
manifestPath: string = "./manifest.xml",
|
|
backupPath: string = "./backup.zip",
|
|
projectDir: string = "",
|
|
devPreview: boolean = false
|
|
) {
|
|
if (manifestPath.endsWith(".json")) {
|
|
throw new ExpectedError(`The convert command only works on xml manifest based projects`);
|
|
}
|
|
|
|
if (!fs.existsSync(manifestPath)) {
|
|
throw new ExpectedError(`The manifest file '${manifestPath}' does not exist`);
|
|
}
|
|
|
|
const outputPath: string = path.dirname(manifestPath);
|
|
const currentDir: string = process.cwd();
|
|
|
|
await backupProject(backupPath);
|
|
try {
|
|
// assume project dir is the same as manifest dir if not specified
|
|
projectDir = projectDir === "" ? outputPath : projectDir;
|
|
process.chdir(projectDir);
|
|
|
|
if (!devPreview) {
|
|
await convert(manifestPath, outputPath, false /* imageDownload */);
|
|
} else {
|
|
// override the schema used in the json manifest to use the devPreview schema
|
|
await convert(
|
|
manifestPath,
|
|
outputPath,
|
|
false /* imageDownload */,
|
|
"https://developer.microsoft.com/json-schemas/teams/vDevPreview/MicrosoftTeams.schema.json",
|
|
"devPreview"
|
|
);
|
|
}
|
|
await updatePackages();
|
|
await updateManifestXmlReferences();
|
|
fs.unlinkSync(manifestPath);
|
|
} catch (err: any) {
|
|
console.log(`Error in conversion. Restoring project initial state.`);
|
|
await restoreBackup(backupPath);
|
|
throw err;
|
|
} finally {
|
|
process.chdir(currentDir);
|
|
}
|
|
}
|
|
|
|
async function backupProject(backupPath: string) {
|
|
const zip: AdmZip = new AdmZip();
|
|
const outputPath: string = path.resolve(backupPath);
|
|
const rootDir: string = path.resolve();
|
|
|
|
const files: string[] = fs.readdirSync(rootDir);
|
|
files.forEach((entry) => {
|
|
const fullPath = path.resolve(entry);
|
|
const entryStats = fs.lstatSync(fullPath);
|
|
|
|
if (skipBackup.includes(entry)) {
|
|
// Don't add it to the backup
|
|
} else if (entryStats.isDirectory()) {
|
|
zip.addLocalFolder(entry, entry);
|
|
} else {
|
|
zip.addLocalFile(entry);
|
|
}
|
|
});
|
|
|
|
fsExtra.ensureDirSync(path.dirname(outputPath));
|
|
if (await zip.writeZipPromise(outputPath)) {
|
|
console.log(`A backup of your project was created to ${outputPath}`);
|
|
} else {
|
|
throw new Error(`Error writting zip file to ${outputPath}`);
|
|
}
|
|
}
|
|
|
|
async function restoreBackup(backupPath: string) {
|
|
var zip = new AdmZip(backupPath); // reading archives
|
|
zip.extractAllTo("./", true); // overwrite
|
|
}
|
|
|
|
async function updatePackages(): Promise<void> {
|
|
// Contains name of the package and minimum version
|
|
const depedentPackages: string[] = ["office-addin-debugging", "office-addin-manifest"];
|
|
let command: string = "npm install";
|
|
let messageToBePrinted: string = "Installing latest versions of";
|
|
|
|
for (let i = 0; i < depedentPackages.length; i++) {
|
|
const depedentPackage = depedentPackages[i];
|
|
command += ` ${depedentPackage}@latest`;
|
|
messageToBePrinted += ` ${depedentPackage}`;
|
|
|
|
if (i === depedentPackages.length - 2) {
|
|
messageToBePrinted += " and";
|
|
} else {
|
|
messageToBePrinted += ",";
|
|
}
|
|
}
|
|
|
|
command += ` --save-dev`;
|
|
console.log(messageToBePrinted.slice(0, -1));
|
|
await execAsync(command);
|
|
}
|
|
|
|
async function updateManifestXmlReferences(): Promise<void> {
|
|
await updatePackageJson();
|
|
await updateWebpackConfig();
|
|
}
|
|
|
|
async function updatePackageJson(): Promise<void> {
|
|
const packageJson = `./package.json`;
|
|
const readFileAsync = util.promisify(fs.readFile);
|
|
const data = await readFileAsync(packageJson, "utf8");
|
|
let content = JSON.parse(data);
|
|
|
|
// Change .xml references to .json
|
|
Object.keys(content.scripts).forEach(function (key) {
|
|
content.scripts[key] = content.scripts[key].replace(/manifest.xml/gi, `manifest.json`);
|
|
});
|
|
|
|
// write updated json to file
|
|
const writeFileAsync = util.promisify(fs.writeFile);
|
|
await writeFileAsync(packageJson, JSON.stringify(content, null, 2));
|
|
}
|
|
|
|
async function updateWebpackConfig(): Promise<void> {
|
|
const weppackConfig = `./webpack.config.js`;
|
|
const readFileAsync = util.promisify(fs.readFile);
|
|
const data = await readFileAsync(weppackConfig, "utf8");
|
|
|
|
// switching to json extension is the easy fix.
|
|
// TODO: update to remove the manifest copy plugin since it's not needed in webpack
|
|
let content = data.replace(/"(manifest\*\.)xml"/gi, '"$1json"');
|
|
|
|
const writeFileAsync = util.promisify(fs.writeFile);
|
|
await writeFileAsync(weppackConfig, content);
|
|
}
|