diff --git a/release/antos-1.2.0.tar.gz b/release/antos-1.2.0.tar.gz index cd51d0a..20bea49 100644 Binary files a/release/antos-1.2.0.tar.gz and b/release/antos-1.2.0.tar.gz differ diff --git a/src/core/vfs.ts b/src/core/vfs.ts index 2697428..4def545 100644 --- a/src/core/vfs.ts +++ b/src/core/vfs.ts @@ -1770,9 +1770,7 @@ namespace OS { * - array: the result will be an Array of bytes (numbers between 0 and 255). * - uint8array : the result will be a Uint8Array. This requires a compatible browser. * - arraybuffer : the result will be a ArrayBuffer. This requires a compatible browser. - * - blob : the result will be a Blob. This requires a compatible browser. - * - nodebuffer : the result will be a nodejs Buffer. This requires nodejs. - * + * - blob : the result will be a Blob. This requires a compatible browser. * * If file_name is not specified, the first file_name in the zip archive will be read * @export * @param {string} file zip file @@ -1784,91 +1782,65 @@ namespace OS { return new Promise(async (resolve, reject) => { try { await API.requires("os://scripts/jszip.min.js"); - try { - const data = await file.asFileHandle().read("binary"); - try { - const zip = await JSZip.loadAsync(data); - if (!file_name) { - for (let name in zip.files) { - file_name = name; - break; - } - } - - try { - const udata = await zip.file(file_name).async(type); - resolve(udata); - } catch (e_2) { - return reject(__e(e_2)); - } - } catch (e_1) { - return reject(__e(e_1)); + const data = await file.asFileHandle().read("binary"); + const zip = await JSZip.loadAsync(data); + if (!file_name) { + for (let name in zip.files) { + file_name = name; + break; } - } catch (e) { - return reject(__e(e)); } - } catch (e_3) { - return reject(__e(e_3)); + const udata = await zip.file(file_name).async(type); + resolve(udata); + } catch (e) { + return reject(__e(e)); } - }); } /** - * Cat al file to a single out-put + * Cat all files to a single out-put * * @export * @param {string[]} list list of VFS files * @param {string} data input data string that will be cat to the files content + * @param {string} join_by join on files content by this string * @return {*} {Promise} */ - export function cat(list: string[], data: string): Promise { - return new Promise((resolve, reject) => { + export function cat(list: string[], data: string, join_by: string = "\n"): Promise { + return new Promise(async (resolve, reject) => { if (list.length === 0) { return resolve(data); } - const file = list.splice(0, 1)[0].asFileHandle(); - return file - .read() - .then((text: string) => { - data = data + "\n" + text; - return cat(list, data) - .then((d) => resolve(d)) - .catch((e) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); + const promises = []; + for (const file of list) { + promises.push(file.asFileHandle().read("text")); + } + try { + const results = await Promise.all(promises); + resolve(`${data}${join_by}${results.join(join_by)}`); + } catch (error) { + reject(__e(error)); + } }); } /** - * Read all files content to on the list + * Read all files content on the list * * @export * @param {string[]} list list of VFS files * @param {GenericObject[]} contents content array - * @return {*} {Promise[]>} + * @return {void} */ - export function read_files(list: string[], contents: GenericObject[]): Promise[]> { - return new Promise((resolve, reject) => { - if (list.length === 0) { - return resolve(contents); - } - const file = list.splice(0, 1)[0].asFileHandle(); - return file - .read() - .then((text: string) => { - contents.push({ - path: file.path, - content: text - }); - return read_files(list, contents) - .then((d) => resolve(d)) - .catch((e) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - }); + export function read_files(list: string[]): Promise[]> { + const promises = []; + for (const file of list) { + promises.push(file.asFileHandle().read("text")); + } + return Promise.all(promises); } @@ -1878,71 +1850,45 @@ namespace OS { * @export * @param {string[]} files list of files * @param {string} to destination folder - * @return {*} {Promise} + * @return {*} {Promise} */ - export function copy(files: string[], to: string): Promise { - return new Promise((resolve, reject) => { - if (files.length === 0) { - return resolve(); - } - const file = files.splice(0, 1)[0].asFileHandle(); - const tof = `${to}/${file.basename}`.asFileHandle(); - return file - .onready() - .then((meta: { type: string }) => { + export function copy(files: string[], to: string): Promise { + const promises = []; + for (const path of files) { + promises.push(new Promise(async (resolve, reject) => { + try { + const file = path.asFileHandle(); + const tof = `${to}/${file.basename}`.asFileHandle(); + const meta = await file.onready(); if (meta.type === "dir") { - // copy directory const desdir = to.asFileHandle(); - return desdir - .mk(file.basename) - .then(() => { - // read the dir content - return file - .read() - .then((data: API.RequestResult) => { - const list = (data.result as API.FileInfoType[]).map( - (v) => v.path - ); - return copy( - list, - `${desdir.path}/${file.basename}` - ) - .then(() => { - return copy(files, to) - .then(() => resolve()) - .catch((e) => - reject(__e(e)) - ); - }) - .catch((e) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - } else { - // copy file - return file - .read("binary") - .then(async (data: ArrayBuffer) => { - const d = await tof - .setCache( - new Blob([data], { - type: file.info.mime, - }) - ) - .write(file.info.mime); - try { - await copy(files, to); - return resolve(); - } catch (e) { - return reject(__e(e)); - } - }) - .catch((e: Error) => reject(__e(e))); + await desdir.mk(file.basename); + const ret = await file.read(); + const files = ret.result.map((v: API.FileInfoType) => v.path); + if (files.length > 0) { + await copy(files, `${desdir.path}/${file.basename}`); + resolve(undefined); + } + else { + resolve(undefined); + } } - }) - .catch((e: Error) => reject(__e(e))); - }); + else { + const content = await file.read("binary"); + await tof + .setCache( + new Blob([content], { + type: file.info.mime, + })) + .write(file.info.mime); + resolve(undefined); + } + } catch (error) { + reject(__e(error)); + } + })); + } + return Promise.all(promises); } /** @@ -1954,69 +1900,38 @@ namespace OS { * @return {*} {Promise} */ function aradd(list: string[], zip: any, base: string): Promise { - return new Promise((resolve, reject) => { - if (list.length === 0) { - return resolve(zip); - } - const path = list.splice(0, 1)[0]; - const file = path.asFileHandle(); - return file - .onready() - .then((meta: { type: string }) => { - if (meta.type === "dir") { - return file - .read() - .then( - (d: { - result: - | Iterable - | ArrayLike; - }) => { - const l = (d.result as API.FileInfoType[]).map( - (v) => v.path - ); - return aradd( - l, - zip, - `${base}${file.basename}/` - ) - .then(() => { - return aradd( - list, - zip, - base - ) - .then(() => resolve(zip)) - .catch((e) => - reject(__e(e)) - ); - }) - .catch((e) => reject(__e(e))); - } - ) - .catch((e: Error) => reject(__e(e))); - } else { - return file - .read("binary") - .then(async (d: any) => { - const zpath = `${base}${file.basename}`.replace( - /^\/+|\/+$/g, - "" - ); - zip.file(zpath, d, { binary: true }); - try { - await aradd(list, zip, base); - return resolve(zip); - } - catch (e) { - return reject(__e(e)); - } - }) - .catch((e: Error) => reject(__e(e))); + const promises = []; + for (const path of list) { + promises.push(new Promise(async (resolve, reject) => { + const file = path.asFileHandle(); + try { + const meta = await file.asFileHandle().onready(); + if (meta.type == "dir") { + const ret = await file.read(); + const dirs: string[] = ret.result.map((v: API.FileInfoType) => v.path); + if (dirs.length > 0) { + await aradd(dirs, zip, `${base}${file.basename}/`); + resolve(undefined); + } + else { + resolve(undefined); + } } - }) - .catch((e: Error) => reject(__e(e))); - }); + else { + const u_data = await file.read("binary"); + const z_path = `${base}${file.basename}`.replace( + /^\/+|\/+$/g, + "" + ); + zip.file(z_path, u_data, { binary: true }); + resolve(undefined); + } + } catch (error) { + reject(__e(error)); + } + })); + } + return Promise.all(promises); } @@ -2024,57 +1939,36 @@ namespace OS { * Create a zip archive from a folder * * @export - * @param {string} src source folder + * @param {string} src source file/folder * @param {string} dest destination archive * @return {*} {Promise} */ export function mkar(src: string, dest: string): Promise { - return new Promise((resolve, reject) => { - return new Promise(async (r, e) => { - try { - await API.requires("os://scripts/jszip.min.js"); - try { - const d = await src.asFileHandle().read(); - return r(d.result); - } catch (ex) { - return e(__e(ex)); - } - } catch (ex_1) { - return e(__e(ex_1)); + console.log(src, dest); + return new Promise(async (resolve, reject) => { + try { + await API.requires("os://scripts/jszip.min.js"); + const zip = new JSZip(); + const fhd = src.asFileHandle(); + const meta = await fhd.onready(); + if(meta.type === "file") + { + await aradd([src], zip, "/"); } - }) - .then((files: API.FileInfoType[]) => { - return new Promise(async (r, e) => { - const zip = new JSZip(); - try { - const z = await aradd( - files.map((v: { path: any }) => v.path), - zip, - "/" - ); - return r(z); - } catch (ex) { - return e(__e(ex)); - } - }); - }) - .then((zip: any) => { - return zip - .generateAsync({ type: "base64" }) - .then((data: string) => { - return dest - .asFileHandle() - .setCache( - "data:application/zip;base64," + data - ) - .write("base64") - .then((r: any) => { - resolve(); - }) - .catch((e: Error) => reject(__e(e))); - }); - }) - .catch((e) => reject(__e(e))); + else + { + const ret = await fhd.read(); + await aradd( + ret.result.map((v: API.FileInfoType) => v.path), zip, "/"); + } + const z_data = await zip.generateAsync({ type: "base64" }); + await dest.asFileHandle() + .setCache("data:application/zip;base64," + z_data) + .write("base64"); + resolve(); + } catch (error) { + reject(__e(error)); + } }); } @@ -2083,35 +1977,105 @@ namespace OS { * * @export * @param {string[]} list of directories to be created - * @return {*} {Promise} + * @param {boolen} sync sync/async of directory creation + * @return {*} {Promise} */ - export function mkdirAll(list: string[]): Promise { - return new Promise((resolve, reject) => { - if (list.length === 0) { - return resolve(); + export function mkdirAll(list: string[], sync?: boolean): Promise { + if (!sync) { + const promises = []; + for (const dir of list) { + const path = dir.asFileHandle() + promises.push(path.parent().mk(path.basename)); } - const path = list.splice(0, 1)[0].asFileHandle(); - return path - .parent() - .mk(path.basename) - .then((d: any) => { - return mkdirAll(list) - .then(() => resolve()) - .catch((e) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - }); + return Promise.all(promises); + } + else { + return new Promise(async (resolve, reject) => { + try { + if (list.length === 0) { + return resolve(true); + } + const dir = list.splice(0, 1)[0].asFileHandle(); + const path = dir.parent(); + const dname = dir.basename; + const r = await path.asFileHandle().mk(dname); + if (r.error) { + return reject( + this._api.throwe( + __( + "Cannot create {0}", + `${path}/${dir}` + ) + ) + ); + } + await mkdirAll(list, sync); + resolve(true); + } + catch (e) { + reject(__e(e)); + } + }); + } } + + /** - * * - * @export - * @param {Array} list of templates mapping files - * @param {string} path path stored create files - * @param {string} name + * + * @export Extract a zip fle + * @param {string} zfile zip file to extract + * @param {(zip:any) => Promise} [dest_callback] a callback to get extraction destination * @return {*} {Promise} */ + export function extractZip(zfile: string | API.VFS.BaseFileHandle, dest_callback: (zip: any) => Promise): Promise { + return new Promise(async (resolve, reject) => { + try { + await API.requires("os://scripts/jszip.min.js"); + const data = await zfile.asFileHandle().read("binary"); + const zip = await JSZip.loadAsync(data); + const to = await dest_callback(zip); + const dirs = []; + const files = []; + for (const name in zip.files) { + const file = zip.files[name]; + if (file.dir) { + dirs.push(to + "/" + name); + } else { + files.push(name); + } + } + await mkdirAll(dirs, true); + const promises = []; + for (const file of files) { + promises.push(new Promise(async (res, rej) => { + try { + const data = await zip.file(file).async("uint8array"); + const path = `${to}/${file}`; + const fp = path.asFileHandle(); + fp.cache = new Blob([data], { type: "octet/stream" }); + const r = await fp.write("text/plain"); + if (r.error) { + return rej( + API.throwe( + __("Cannot extract file to {0}", path) + ) + ); + } + return resolve(res(path)); + } catch (error) { + rej(__e(error)); + } + })); + } + await Promise.all(promises); + resolve(); + } catch (e) { + return reject(__e(e)); + } + }); + } /** * Make files from a set of template files @@ -2120,35 +2084,28 @@ namespace OS { * @param {Array} list mapping paths between templates files and created files * @param {string} path files destination * @param {(data: string) => string} callback: pre-processing files content before writing to destination files - * @return {*} {Promise} + * @return {*} {Promise} */ export function mktpl( list: Array, path: string, callback: (data: string) => string - ): Promise { - return new Promise((resolve, reject) => { - if (list.length === 0) { - return resolve(); - } - const item = list.splice(0, 1)[0]; - return `${path}/${item[0]}` - .asFileHandle() - .read() - .then((data) => { - const file = item[1].asFileHandle(); - return file - .setCache(callback(data)) - .write("text/plain") - .then(() => { - return mktpl(list, path, callback) - .then(() => resolve()) - .catch((e) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - }) - .catch((e) => reject(__e(e))); - }); + ): Promise { + const promises = []; + for (const tpl of list) { + promises.push(new Promise(async (resolve, reject) => { + try { + const data = await `${path}/${tpl[0]}`.asFileHandle().read(); + const file = tpl[1].asFileHandle(); + file.setCache(callback(data)); + await file.write("text/plain"); + resolve(undefined); + } catch (error) { + reject(__e(error)); + } + })); + } + return Promise.all(promises); } } } diff --git a/src/packages/CodePad/AntOSDK.ts b/src/packages/CodePad/AntOSDK.ts index 321e5f6..13c54e5 100644 --- a/src/packages/CodePad/AntOSDK.ts +++ b/src/packages/CodePad/AntOSDK.ts @@ -89,13 +89,9 @@ namespace OS { .then(async (meta) => { try { await this.build(meta, true); - try { - return this.run(meta); - } catch (e) { - return this.logger().error(__("Unable to run project: {0}", e.stack)); - } + await this.run(meta); } catch (e_1) { - return this.logger().error(__("Unable to build project: {0}", e_1.stack)); + return this.logger().error(__("Unable to build and run project: {0}", e_1.stack)); } }) .catch((e) => this.logger().error(__("Unable to read meta-data: {0}", e.stack))); @@ -112,19 +108,13 @@ namespace OS { .then(async (meta) => { try { await this.build(meta, false); - try { - return API.VFS.mkar( - `${meta.root}/build/debug`, - `${meta.root}/build/release/${meta.name}.zip` - ); - } catch (e) { - return this.logger().error( - __("Unable to create package archive: {0}", - e.stack) - ); - } + await API.VFS.mkar( + `${meta.root}/build/debug`, + `${meta.root}/build/release/${meta.name}.zip` + ); + this.logger().info(__("Archive generate at: {0}", `${meta.root}/build/release/${meta.name}.zip`)); } catch (e_1) { - return this.logger().error(__("Unable to build project: {0}", e_1.stack)); + return this.logger().error(__("Unable to release project: {0}", e_1.stack)); } }) .catch((e) => this.logger().error(__("Unable to read meta-data: {0}", e.stack))); @@ -253,54 +243,54 @@ namespace OS { const core_lib = "os://packages/CodePad/libs/corelib.d.ts"; try { await this.load_corelib(core_lib); - const arr = []; - API.VFS.read_files(files, arr).then((_result) => { - const libs: string[] = arr.map((e) => e.path) - libs.unshift(core_lib); - const src_files: GenericObject = {}; - src_files[core_lib] = AntOSDK.corelib["ts"]; - for (const el of arr) { - src_files[el.path] = ts.createSourceFile(el.path, el.content, ts.ScriptTarget.Latest); - } - let js_code = ""; - const host = { - fileExists: (path: string) => { - return src_files[path] != undefined; - }, - directoryExists: (path: string) => { - return true; - }, - getCurrentDirectory: () => "/", - getDirectories: () => [], - getCanonicalFileName: (path: string) => path, - getNewLine: () => "\n", - getDefaultLibFileName: () => "", - getSourceFile: (path: string) => src_files[path], - readFile: (path: string) => undefined, - useCaseSensitiveFileNames: () => true, - writeFile: (path: string, data: string) => js_code = `${js_code}\n${data}`, - }; - const program = ts.createProgram(libs, { - "target": "es6", - "skipLibCheck": true, - }, host); - const result = program.emit(); - const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program))); - if (diagnostics.length > 0) { - diagnostics.forEach(diagnostic => { - if (diagnostic.file) { - let { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); - let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); - this.logger().error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); - } else { - this.logger().error(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")); - } - }); - return reject(API.throwe(__("Typescript compile error"))); - } - resolve(js_code); - }) - .catch((e) => { reject(__e(e)) }); + const arr = await API.VFS.read_files(files); + const libs: string[] = files.map((e) => e) + libs.unshift(core_lib); + const src_files: GenericObject = {}; + src_files[core_lib] = AntOSDK.corelib["ts"]; + for (const i in arr) { + src_files[files[i]] = ts.createSourceFile(files[i], arr[i], ts.ScriptTarget.Latest); + } + let js_code = ""; + const host = { + fileExists: (path: string) => { + return src_files[path] != undefined; + }, + directoryExists: (path: string) => { + return true; + }, + getCurrentDirectory: () => "/", + getDirectories: () => [], + getCanonicalFileName: (path: string) => path, + getNewLine: () => "\n", + getDefaultLibFileName: () => "", + getSourceFile: (path: string) => src_files[path], + readFile: (path: string) => undefined, + useCaseSensitiveFileNames: () => true, + writeFile: (path: string, data: string) => js_code = `${js_code}\n${data}`, + }; + const program = ts.createProgram(libs, { + "target": "es6", + "skipLibCheck": true, + }, host); + const result = program.emit(); + const diagnostics = result.diagnostics.concat((ts.getPreEmitDiagnostics(program))); + if (diagnostics.length > 0) { + diagnostics.forEach(diagnostic => { + if (diagnostic.file) { + let { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); + let message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); + this.logger().error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); + } else { + this.logger().error(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")); + } + }); + return reject(API.throwe(__("Typescript compile error"))); + } + for (const file of files) { + this.logger().info(__("Compiled: {0}", file)); + } + resolve(js_code); } catch (e) { return reject(__e(e)); } @@ -331,12 +321,12 @@ namespace OS { const ts_list = meta.ts.map( (v: string) => `${meta.root.trimBy("/")}/${v}` ); - Promise.all([ + const results = await Promise.all([ this.compile_ts(ts_list), this.compile_coffee(coffee_list) - ]).then((js_codes: string[]) => { - resolve(js_codes.join("\n")); - }).catch((e_1) => reject(__e(e_1))); + ]); + + resolve(results.join("\n")); } catch (e_2) { return reject(__e(e_2)); } @@ -358,14 +348,12 @@ namespace OS { } try { await this.verify_coffee(list.map((x: string) => x)); - try { - const code = await API.VFS.cat(list, ""); - const jsrc = CoffeeScript.compile(code); - this.logger().info(__("Compiled successful")); - return resolve(jsrc); - } catch (e) { - return reject(__e(e)); + const code = await API.VFS.cat(list, ""); + const jsrc = CoffeeScript.compile(code); + for (const file of list) { + this.logger().info(__("Compiled: {0}", file)); } + return resolve(jsrc); } catch (e_1) { return reject(__e(e_1)); } @@ -382,109 +370,54 @@ namespace OS { * @memberof AntOSDK */ private build(meta: GenericObject, debug: boolean): Promise { - const dirs = [ - `${meta.root}/build`, - `${meta.root}/build/debug`, - `${meta.root}/build/release`, - ]; return new Promise(async (resolve, reject) => { try { - await API.VFS.mkdirAll(dirs); - try { - const src = await this.compile(meta); - let v: string; - try { - let jsrc = await API.VFS.cat( - (() => { - const result = []; - for (v of meta.javascripts) { - result.push(`${meta.root}/${v}`); - } - return result; - })(), - src + this.logger().info(__("Building the package", meta.name)); + await API.VFS.mkdirAll([`${meta.root}/build`,]); + await API.VFS.mkdirAll([`${meta.root}/build/debug`, `${meta.root}/build/release`]); + const src = await this.compile(meta); + let code = await API.VFS.cat(meta.javascripts.map(v => `${meta.root}/${v}`), src); + if (!debug) { + const options = { + toplevel: true, + compress: { + passes: 3, + }, + mangle: true, + output: { + //beautify: true, + }, + }; + const result = Terser.minify(code, options); + if (result.error) { + this.logger().error( + __( + "Unable to minify code: {0}", + result.error + ) ); - await new Promise(async function (r, e) { - let code = jsrc; - if (!debug) { - const options = { - toplevel: true, - compress: { - passes: 3, - }, - mangle: true, - output: { - //beautify: true, - }, - }; - const result_1 = Terser.minify( - jsrc, - options - ); - if (result_1.error) { - this.logger().error( - __( - "Unable to minify code: {0}", - result_1.error - ) - ); - } else { - ({ code } = result_1); - } - } - try { - const d = await `${meta.root}/build/debug/main.js` - .asFileHandle() - .setCache(code) - .write("text/plain"); - return r(); - } catch (ex) { - return e(__e(ex)); - } - }); - await new Promise(async (r, e) => { - const txt = await API.VFS.cat( - (() => { - const result1 = []; - for (v of meta.css) { - result1.push(`${meta.root}/${v}`); - } - return result1; - })(), - "" - ); - if (txt === "") { - return r(); - } - try { - const d_1 = await `${meta.root}/build/debug/main.css` - .asFileHandle() - .setCache(txt) - .write("text/plain"); - return r(); - } catch (ex_1) { - return e(__e(ex_1)); - } - }); - await API.VFS.copy( - (() => { - const result1_1 = []; - for (v of meta.copies) { - result1_1.push(`${meta.root}/${v}`); - } - return result1_1; - })(), - `${meta.root}/build/debug` - ); - return resolve(); - } catch (e) { - return reject(__e(e)); + } else { + code = result.code; } - } catch (e_1) { - return reject(__e(e_1)); } - } catch (e_2) { - return reject(__e(e_2)); + if (code != "") + await `${meta.root}/build/debug/main.js` + .asFileHandle() + .setCache(code) + .write("text/plain"); + const txt = await API.VFS.cat(meta.css.map(v => `${meta.root}/${v}`), ""); + if (txt != "") + await `${meta.root}/build/debug/main.css` + .asFileHandle() + .setCache(txt) + .write("text/plain"); + await API.VFS.copy( + meta.copies.map(v => `${meta.root}/${v}`), + `${meta.root}/build/debug` + ); + resolve(); + } catch (e) { + return reject(__e(e)); } }); } diff --git a/src/packages/CodePad/libs/corelib.d.ts.zip b/src/packages/CodePad/libs/corelib.d.ts.zip index 122ace6..7f2e313 100644 Binary files a/src/packages/CodePad/libs/corelib.d.ts.zip and b/src/packages/CodePad/libs/corelib.d.ts.zip differ diff --git a/src/packages/Files/main.ts b/src/packages/Files/main.ts index 950f3e8..c7b3c5f 100644 --- a/src/packages/Files/main.ts +++ b/src/packages/Files/main.ts @@ -87,8 +87,7 @@ namespace OS { iconclass: v.iconclass, }); } - - m.items = [ + let ctx_menu = [ { text: "__(Open with)", nodes: apps, @@ -103,6 +102,75 @@ namespace OS { this.mnFile(), this.mnEdit(), ]; + if(file.mime === "application/zip") + { + ctx_menu = ctx_menu.concat([ + { + text: "__(Extract Here)", + onmenuselect: (e: GUI.TagEventType) => { + if (!e) { + return; + } + API.VFS.extractZip(file.path, + (z) => new Promise((r,e) => r(file.path.asFileHandle().parent().path))) + .catch((err) => this.error(__("Unable to extract file"), err)); + }, + }, + { + text: "__(Extract to)", + onmenuselect: async (e: GUI.TagEventType) => { + if (!e) { + return; + } + try { + OS.GUI.dialogs.FileDialog.last_opened = this.currdir.path; + const d = await this.openDialog("FileDialog", { + title: __("Select extract destination"), + type: "dir", + file: file.path.replace(".zip","").asFileHandle() + }); + const path = `${d.file.path}/${d.name}`; + await API.VFS.mkdirAll([path]); + await API.VFS.extractZip(file.path, + (z) => new Promise((r,e) => r(path))); + } catch (error) { + this.error(__("Unable to extract file"), error); + } + }, + }, + ]); + } + else + { + ctx_menu.push( + { + text: "__(Compress)", + onmenuselect: async (e: GUI.TagEventType) => { + if (!e) { + return; + } + try { + OS.GUI.dialogs.FileDialog.last_opened = this.currdir.path; + const d = await this.openDialog("FileDialog", { + title: __("Save compressed file to"), + type: "dir", + file: `${this.currdir.path}/${file.name}.zip`.asFileHandle() + }); + if(d.name.trim() === "") + { + return this.error(__("Invalid file name")); + } + const path = `${d.file.path}/${d.name}`; + await API.VFS.mkar(file.path, path); + this.notify(__("Archive file created: {0}",path )); + } catch (error) { + this.error(__("Unable to compress file, folder"), error); + } + } + } + ); + } + m.items = ctx_menu; m.show(e); }; @@ -546,7 +614,7 @@ namespace OS { return this.notify(__("File {0} cut", file.filename)); case `${this.name}-copy`: - if (!file && file.type !== "dir") { + if (!file) { return; } this.clipboard = { @@ -579,30 +647,12 @@ namespace OS { ); }); } else { - this.clipboard.file - .read("binary") - .then(async (d) => { - const blob = new Blob([d], { - type: this.clipboard.file.info.mime, - }); - const fp = `${this.currdir.path}/${this.clipboard.file.basename}`.asFileHandle(); - fp.cache = blob; - try { - const r = await fp.write(this.clipboard.file.info.mime); - return (this.clipboard = undefined); - } - catch (e) { - return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e); - } + API.VFS.copy([this.clipboard.file.path],this.currdir.path) + .then(() => { + return (this.clipboard = undefined); }) .catch((e) => { - return this.error( - __( - "Fail to read: {0}", - this.clipboard.file.path - ), - e - ); + return this.error(__("Fail to paste: {0}", this.clipboard.file.path), e); }); } break; diff --git a/src/packages/Files/package.json b/src/packages/Files/package.json index 992146a..ab2f52b 100644 --- a/src/packages/Files/package.json +++ b/src/packages/Files/package.json @@ -6,7 +6,7 @@ "author": "Xuan Sang LE", "email": "xsang.le@gmail.com" }, - "version":"0.1.2-a", + "version":"0.1.3-a", "category":"System", "iconclass":"fa fa-hdd-o", "mimes":["dir"], diff --git a/src/packages/MarketPlace/main.ts b/src/packages/MarketPlace/main.ts index 96e25d0..1c974f4 100644 --- a/src/packages/MarketPlace/main.ts +++ b/src/packages/MarketPlace/main.ts @@ -68,19 +68,15 @@ namespace OS { }; this.btinstall.onbtclick = async () => { - if (this.btinstall.data.dirty) { - try { + try { + if (this.btinstall.data.dirty) { await this.updatePackage(); return this.notify(__("Package updated")); - } catch (e) { - return this.error(e.toString(), e); } - } - try { const n = await this.remoteInstall(); return this.notify(__("Package installed: {0}", n)); - } catch (e_1) { - return this.error(e_1.toString(), e_1); + } catch (error) { + return this.error(error.toString(), error); } }; @@ -466,40 +462,19 @@ namespace OS { return reject(this._api.throwe(__("Unable to find package: {0}", pkgname))); } try { - const data = await this._api.blob( - meta.download + "?_=" + new Date().getTime() - ); - try { - const n = await this.install(data, meta); - return resolve(meta); - } catch (e) { - return reject(__e(e)); - } + const n = await this.install(meta.download + "?_=" + new Date().getTime(), meta); + return resolve(meta); } catch (e_1) { return reject(__e(e_1)); } }); } private bulkInstall(list: string[]): Promise { - return new Promise((resolve, reject) => { - if (list.length == 0) { - return resolve(true); - } - const pkgname = list.splice(0, 1)[0]; - this.installPkg(pkgname) - .then((_meta) => { - this.bulkInstall(list) - .then((b) => { - resolve(b); - }) - .catch((e) => { - reject(e); - }) - }) - .catch((err) => { - reject(err); - }) - }); + const promises = []; + for (let pkgname of list) { + promises.push(this.installPkg(pkgname)); + } + return Promise.all(promises); } private remoteInstall(): Promise { const el = this.applist.selectedItem; @@ -512,175 +487,130 @@ namespace OS { } // get blob file return new Promise(async (resolve, reject) => { - let pkgname = `${el.data.pkgname}@${el.data.version}`; - const dep = this.checkDependencies(pkgname); - if (dep.notfound.size != 0) { - return this.openDialog("TextDialog", { - disable: true, - title: __("Unresolved dependencies"), - value: __( - "Unable to install: The package `{0}` depends on these packages, but they are not found:\n{1}", - pkgname, - [...dep.notfound].join("\n") - ) - }) - .then((_v) => { - reject(__("Unresolved dependencies on: {0}", pkgname)) + try { + let pkgname = `${el.data.pkgname}@${el.data.version}`; + const dep = this.checkDependencies(pkgname); + if (dep.notfound.size != 0) { + this.openDialog("TextDialog", { + disable: true, + title: __("Unresolved dependencies"), + value: __( + "Unable to install: The package `{0}` depends on these packages, but they are not found:\n{1}", + pkgname, + [...dep.notfound].join("\n") + ) }); + return reject(__("Unresolved dependencies on: {0}", pkgname)); + } + const t = await this.openDialog("TextDialog", { + title: __("Confirm install"), + disable: true, + value: __( + "Please confirm the following operation:\n\n{0} packages will be removed:\n\n{1}\n\n{2} packages will be installed:\n\n{3}", + dep.uninstall.size.toString(), + [...dep.uninstall].join("\n"), + dep.install.size.toString(), + [...dep.install].join("\n") + ) + }); + if (!t) return; + await this.bulkUninstall([...dep.uninstall]); + const metas = await this.bulkInstall([...dep.install]); + this.appDetail(metas.pop()); + resolve(pkgname); + } catch (error) { + reject(__e(error)); } - this.openDialog("TextDialog", { - title: __("Confirm install"), - disable: true, - value: __( - "Please confirm the following operation:\n\n{0} packages will be removed:\n\n{1}\n\n{2} packages will be installed:\n\n{3}", - dep.uninstall.size.toString(), - [...dep.uninstall].join("\n"), - dep.install.size.toString(), - [...dep.install].join("\n") - ) - }).then((_v) => { - this.bulkUninstall([...dep.uninstall]) - .then((_b) => { - this.bulkInstall([...dep.install]) - .then((_b1) => { - resolve(pkgname); - }) - .catch((e1) => { - reject(e1); - }) - }) - .catch((e2) => { - reject(e2); - }) - }) }); } private localInstall(): Promise { - return new Promise((resolve, reject) => { - return this.openDialog("FileDialog", { - title: "__(Select package archive)", - mimes: [".*/zip"], - }).then((d) => { - return d.file.path - .asFileHandle() - .read("binary") - .then((data: Uint8Array) => { - return this.install(data) - .then((n) => { - const apps = this.applist.data.map( - (v) => v.pkgname - ); - const idx = apps.indexOf(n); - if (idx >= 0) { - this.applist.selected = idx; - } - return resolve(n); - }) - .catch((e: Error) => reject(__e(e))) - .catch((e: Error) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - }); + return new Promise(async (resolve, reject) => { + try { + const d = await this.openDialog("FileDialog", { + title: "__(Select package archive)", + mimes: [".*/zip"], + }); + const n = await this.install(d.file.path); + const apps = this.applist.data.map( + (v) => v.pkgname + ); + const idx = apps.indexOf(n); + if (idx >= 0) { + this.applist.selected = idx; + } + return resolve(n.name); + } catch (error) { + reject(__e(error)); + } }); } private install( - data: ArrayBuffer, + zfile: string, meta?: GenericObject - ): Promise { - return new Promise((resolve, reject) => { - return JSZip.loadAsync(data) - .then((zip: any) => { - return zip - .file("package.json") - .async("string") - .then((d: string) => { - let name: string; - const v = JSON.parse(d); - const pth = `${this.installdir}/${v.pkgname ? v.pkgname : v.app}`; - const dir = [pth]; - const files = []; - for (name in zip.files) { - const file = zip.files[name]; - if (file.dir) { - dir.push(pth + "/" + name); - } else { - files.push(name); - } - } - // create all directory - return this.mkdirs(dir) - .then(() => { - return this.installFile( - v.pkgname ? v.pkgname : v.app, - zip, - files - ) - .then(() => { - const app_meta = { - pkgname: v.pkgname ? v.pkgname : v.app, - name: v.name, - text: v.name, - icon: v.icon, - iconclass: v.iconclass, - category: v.category, - author: v.info.author, - version: v.version, - description: meta - ? meta.description - : undefined, - download: meta - ? meta.download - : undefined, - }; - v.text = v.name; - v.filename = v.pkgname ? v.pkgname : v.app; - v.type = "app"; - v.mime = "antos/app"; - if ( - !v.iconclass && - !v.icon - ) { - v.iconclass = - "fa fa-adn"; - } - v.path = pth; - this.systemsetting.system.packages[ - v.pkgname ? v.pkgname : v.app - ] = v; - this.appDetail(app_meta); - return resolve(v.name); - }) - .catch((e) => reject(__e(e))); - }) - .catch((e) => reject(__e(e))); - }) - .catch((err: Error) => reject(__e(err))); - }) - .catch((e: Error) => reject(__e(e))); + ): Promise> { + return new Promise(async (resolve, reject) => { + try { + let v: API.PackageMetaType; + let pth: string = ""; + await API.VFS.extractZip(zfile, (zip) => { + return new Promise(async (res, rej) => { + try { + const d = await zip.file("package.json").async("string"); + v = JSON.parse(d); + pth = `${this.installdir}/${v.pkgname ? v.pkgname : v.app}`; + await API.VFS.mkdirAll([pth]); + res(pth); + } catch (error) { + rej(__e(error)) + } + }); + + }); + const app_meta = { + pkgname: v.pkgname ? v.pkgname : v.app, + name: v.name, + text: v.name, + icon: v.icon, + iconclass: v.iconclass, + category: v.category, + author: v.info.author, + version: v.version, + description: meta + ? meta.description + : undefined, + download: meta + ? meta.download + : undefined, + }; + v.text = v.name; + v.filename = v.pkgname ? v.pkgname : v.app; + v.type = "app"; + v.mime = "antos/app"; + if ( + !v.iconclass && + !v.icon + ) { + v.iconclass = + "fa fa-adn"; + } + v.path = pth; + this.systemsetting.system.packages[ + v.pkgname ? v.pkgname : v.app + ] = v; + return resolve(app_meta); + } catch (error) { + reject(__e(error)); + } }); } private bulkUninstall(list: string[]): Promise { - return new Promise(async (resolve, reject) => { - if (list.length == 0) { - return resolve(true); - } - const pkgname = list.splice(0, 1)[0]; - this.uninstallPkg(pkgname) - .then((_meta) => { - this.bulkUninstall(list) - .then((b) => { - resolve(b); - }) - .catch((e) => { - reject(e); - }) - }) - .catch((err) => { - reject(err); - }) - }); + const promises = []; + for (let pkgname of list) { + promises.push(this.uninstallPkg(pkgname)); + } + return Promise.all(promises); } private uninstallPkg(pkgname: string): Promise { return new Promise(async (resolve, reject) => { @@ -782,90 +712,20 @@ namespace OS { } const meta = this.apps_meta[`${sel.pkgname}@${app.version}`]; await this.remoteInstall(); - try { - if (meta) { - if (meta.domel) - this.applist.delete(meta.domel); - } - return resolve(true); + if (meta) { + if (meta.domel) + this.applist.delete(meta.domel); } - catch (e) { - return reject(__e(e)); - } - + return resolve(true); } catch (e_1) { return reject(__e(e_1)); } }); } - - private mkdirs(list: string[]): Promise { - return new Promise((resolve, reject) => { - if (list.length === 0) { - return resolve(true); - } - const dir = list.splice(0, 1)[0].asFileHandle(); - const path = dir.parent(); - const dname = dir.basename; - return path - .asFileHandle() - .mk(dname) - .then((r) => { - if (r.error) { - return reject( - this._api.throwe( - __( - "Cannot create {0}", - `${path}/${dir}` - ) - ) - ); - } - return this.mkdirs(list) - .then(() => resolve(true)) - .catch((e) => reject(__e(e))); - }) - .catch((e) => reject(__e(e))); - }); - } - - private installFile(n: string, zip: any, files: string[]): Promise { - return new Promise((resolve, reject) => { - if (files.length === 0) { - return resolve(true); - } - const file = files.splice(0, 1)[0]; - const path = `${this.installdir}/${n}/${file}`; - return zip - .file(file) - .async("uint8array") - .then((d: Uint8Array) => { - const fp = path.asFileHandle(); - fp.cache = new Blob([d], { type: "octet/stream" }); - return fp - .write("text/plain") - .then((r) => { - if (r.error) { - return reject( - this._api.throwe( - __("Cannot install {0}", path) - ) - ); - } - return this.installFile(n, zip, files) - .then(() => resolve(true)) - .catch((e) => reject(__e(e))); - }) - .catch((e) => reject(__e(e))); - }) - .catch((e: Error) => reject(__e(e))); - }); - } } MarketPlace.dependencies = [ - "os://scripts/jszip.min.js", "os://scripts/showdown.min.js", ]; MarketPlace.singleton = true; diff --git a/src/packages/MarketPlace/package.json b/src/packages/MarketPlace/package.json index 98da55c..5765e0e 100644 --- a/src/packages/MarketPlace/package.json +++ b/src/packages/MarketPlace/package.json @@ -1,12 +1,12 @@ { "app":"MarketPlace", - "name":"Application store", + "name":"AntOS Application store", "description":"Application store", "info":{ "author": "Xuan Sang LE", "email": "xsang.le@gmail.com" }, - "version":"0.2.2-a", + "version":"0.2.3-a", "category":"System", "iconclass":"fa fa-shopping-bag", "mimes":["none"],