Skip to content

Commit a5b645d

Browse files
Merge pull request #84 from pyscript/unzip
Pyodide unzip/untar abilities + MicroPython unzip
2 parents 71abc15 + 967b264 commit a5b645d

17 files changed

+174
-12
lines changed

docs/index.js

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/zip-CVv62MiA.js

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/zip-CVv62MiA.js.map

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

esm/interpreter/_python.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ export const registerJSModule = (interpreter, name, value) => {
77
interpreter.registerJsModule(name, value);
88
};
99

10+
export const getFormat = (path, url) => {
11+
if (path.endsWith('/*')) {
12+
if (/\.(zip|tar(?:\.gz)?)$/.test(url))
13+
return RegExp.$1;
14+
throw new Error(`Unsupported archive ${url}`);
15+
}
16+
return '';
17+
};
18+
1019
export const run = (interpreter, code, ...args) => {
1120
try {
1221
return interpreter.runPython(dedent(code), ...args);

esm/interpreter/_utils.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ export const RUNNING_IN_WORKER = !globalThis.window;
1111
// This should be the only helper needed for all Emscripten based FS exports
1212
export const writeFile = ({ FS, PATH, PATH_FS }, path, buffer) => {
1313
const absPath = PATH_FS.resolve(path);
14-
FS.mkdirTree(PATH.dirname(absPath));
14+
const dirPath = PATH.dirname(absPath);
15+
if (FS.mkdirTree) FS.mkdirTree(dirPath);
16+
else mkdirTree(FS, dirPath);
1517
return FS.writeFile(absPath, new Uint8Array(buffer), {
1618
canOwn: true,
1719
});
@@ -141,7 +143,12 @@ export const fetchFiles = (module, interpreter, config_files) =>
141143
all(
142144
calculateFilesPaths(config_files).map(({ url, path }) =>
143145
fetchBuffer(config_files, url)
144-
.then((buffer) => module.writeFile(interpreter, path, buffer)),
146+
.then((buffer) => module.writeFile(
147+
interpreter,
148+
path,
149+
buffer,
150+
url,
151+
)),
145152
),
146153
);
147154

esm/interpreter/micropython.js

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
1+
// import fetch from '@webreflection/fetch';
12
import { fetchFiles, fetchJSModules, fetchPaths, writeFile } from './_utils.js';
2-
import { registerJSModule, run, runAsync, runEvent } from './_python.js';
3+
import { getFormat, registerJSModule, run, runAsync, runEvent } from './_python.js';
34
import { stdio } from './_io.js';
45
import mip from '../python/mip.js';
6+
import zip from '../zip.js';
57

68
const type = 'micropython';
79

@@ -33,7 +35,58 @@ export default {
3335
runAsync,
3436
runEvent,
3537
transform: (interpreter, value) => interpreter.PyProxy.toJs(value),
36-
writeFile: ({ FS, _module: { PATH, PATH_FS } }, path, buffer) =>
37-
writeFile({ FS, PATH, PATH_FS }, path, buffer),
38+
writeFile: (interpreter, path, buffer, url) => {
39+
const { FS, _module: { PATH, PATH_FS } } = interpreter;
40+
const fs = { FS, PATH, PATH_FS };
41+
const format = getFormat(path, url);
42+
if (format) {
43+
const extractDir = path.slice(0, -1);
44+
if (extractDir !== './') FS.mkdir(extractDir);
45+
switch (format) {
46+
case 'zip': {
47+
const blob = new Blob([buffer], { type: 'application/zip' });
48+
return zip().then(async ({ BlobReader, Uint8ArrayWriter, ZipReader }) => {
49+
const zipFileReader = new BlobReader(blob);
50+
const zipReader = new ZipReader(zipFileReader);
51+
for (const entry of await zipReader.getEntries()) {
52+
const { directory, filename } = entry;
53+
if (directory) {
54+
FS.mkdir(extractDir + filename);
55+
}
56+
else {
57+
const buffer = await entry.getData(new Uint8ArrayWriter);
58+
FS.writeFile(extractDir + filename, buffer, {
59+
canOwn: true,
60+
});
61+
}
62+
}
63+
zipReader.close();
64+
});
65+
}
66+
case 'tar.gz': {
67+
const TMP = './_.tar.gz';
68+
writeFile(fs, TMP, buffer);
69+
interpreter.runPython(`
70+
import os, gzip, tarfile
71+
tar = tarfile.TarFile(fileobj=gzip.GzipFile(fileobj=open("${TMP}", "rb")))
72+
for f in tar:
73+
name = f"${extractDir}{f.name[2:]}"
74+
if f.type == tarfile.DIRTYPE:
75+
if f.name != "./":
76+
os.mkdir(name.strip("/"))
77+
else:
78+
source = tar.extractfile(f)
79+
with open(name, "wb") as dest:
80+
dest.write(source.read())
81+
dest.close()
82+
tar.close()
83+
os.remove("${TMP}")
84+
`);
85+
return;
86+
}
87+
}
88+
}
89+
return writeFile(fs, path, buffer);
90+
},
3891
};
3992
/* c8 ignore stop */

esm/interpreter/pyodide.js

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { create } from 'gc-hook';
22

33
import { RUNNING_IN_WORKER, fetchFiles, fetchJSModules, fetchPaths, writeFile } from './_utils.js';
4-
import { registerJSModule, run, runAsync, runEvent } from './_python.js';
4+
import { getFormat, registerJSModule, run, runAsync, runEvent } from './_python.js';
55
import { stdio } from './_io.js';
66

77
const type = 'pyodide';
@@ -109,7 +109,15 @@ export default {
109109
value.toJs(toJsOptions) :
110110
value
111111
),
112-
writeFile: ({ FS, PATH, _module: { PATH_FS } }, path, buffer) =>
113-
writeFile({ FS, PATH, PATH_FS }, path, buffer),
112+
writeFile: (interpreter, path, buffer, url) => {
113+
const format = getFormat(path, url);
114+
if (format) {
115+
return interpreter.unpackArchive(buffer, format, {
116+
extractDir: path.slice(0, -1)
117+
});
118+
}
119+
const { FS, PATH, _module: { PATH_FS } } = interpreter;
120+
return writeFile({ FS, PATH, PATH_FS }, path, buffer);
121+
},
114122
};
115123
/* c8 ignore stop */

esm/zip.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/* c8 ignore start */
2+
export default () => import(/* webpackIgnore: true */'./3rd-party/zip.js');
3+
/* c8 ignore stop */

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,6 @@
8888
"to-json-callback": "^0.1.1"
8989
},
9090
"worker": {
91-
"blob": "sha256-tV7jypF54M8P2vuzREc5ZRk1nPGj9AL1VmnxnE2az/s="
91+
"blob": "sha256-jf8fAU4aXz2BNme/XOUMyIliOinwW2o+moYgdacP8qs="
9292
}
9393
}

0 commit comments

Comments
 (0)