diff --git a/docs/modules.md b/docs/modules.md index d7e95f9781..38c608e7b4 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -29,6 +29,7 @@ individual modules, please refer to the Starlib documentation. | Module | Description | | --- | --- | | [`compress/gzip.star`](https://github.com/qri-io/starlib/blob/master/compress/gzip) | gzip decompressing | +| [`compress/zipfile.star`](https://github.com/qri-io/starlib/blob/master/zipfile) | zip decompressing | | [`encoding/base64.star`](https://github.com/qri-io/starlib/tree/master/encoding/base64) | Base 64 encoding and decoding | | [`encoding/csv.star`](https://github.com/qri-io/starlib/tree/master/encoding/csv) | CSV decoding | | [`encoding/json.star`](https://github.com/qri-io/starlib/tree/master/encoding/json) | JSON encoding and decoding | diff --git a/runtime/applet.go b/runtime/applet.go index 6a78aa8566..9b750dbc41 100644 --- a/runtime/applet.go +++ b/runtime/applet.go @@ -13,6 +13,7 @@ import ( starlibhash "github.com/qri-io/starlib/hash" starlibhtml "github.com/qri-io/starlib/html" starlibre "github.com/qri-io/starlib/re" + starlibzip "github.com/qri-io/starlib/zipfile" starlibjson "go.starlark.net/lib/json" starlibmath "go.starlark.net/lib/math" starlibtime "go.starlark.net/lib/time" @@ -320,6 +321,19 @@ func (a *Applet) loadModule(thread *starlark.Thread, module string) (starlark.St starlibgzip.Module.Name: starlibgzip.Module, }, nil + case "compress/zipfile.star": + // Starlib expects you to load the ZipFile function directly, rather than having it be part of a namespace. + // Wraps this to be more consistent with other pixlet modules, as follows: + // load("compress/zipfile.star", "zipfile") + // archive = zipfile.ZipFile("/tmp/foo.zip") + m, _ := starlibzip.LoadModule() + return starlark.StringDict{ + "zipfile": &starlarkstruct.Module{ + Name: "zipfile", + Members: m, + }, + }, nil + case "encoding/base64.star": return starlibbase64.LoadModule() diff --git a/runtime/applet_test.go b/runtime/applet_test.go index 1ae0040a51..e48f97e3ab 100644 --- a/runtime/applet_test.go +++ b/runtime/applet_test.go @@ -1,6 +1,8 @@ package runtime import ( + "archive/zip" + "bytes" "fmt" "testing" @@ -263,7 +265,7 @@ def main(): } func TestTimezoneDatabase(t *testing.T) { - src:= ` + src := ` load("render.star", "render") load("time.star", "time") def main(): @@ -279,4 +281,56 @@ def main(): assert.NoError(t, err) } +func TestZipModule(t *testing.T) { + // Create a new zip file to read from starlark + // https://go.dev/src/archive/zip/example_test.go + buf := new(bytes.Buffer) + w := zip.NewWriter(buf) + var files = []struct { + Name, Body string + }{ + {"readme.txt", "This archive contains some text files."}, + {"gopher.txt", "Gopher names:\nGeorge\nGeoffrey\nGonzo"}, + {"todo.txt", "Get animal handling licence.\nWrite more examples."}, + } + for _, file := range files { + f, err := w.Create(file.Name) + assert.NoError(t, err) + _, err = f.Write([]byte(file.Body)) + assert.NoError(t, err) + } + err := w.Close() + assert.NoError(t, err) + + // override the print function of the thread so we can check we got correct + // values from the zip module. + var printedText []string + initializer := func(thread *starlark.Thread) *starlark.Thread { + thread.Print = func(thread *starlark.Thread, msg string) { + printedText = append(printedText, msg) + } + return thread + } + + src := ` +load("compress/zipfile.star", "zipfile") +def main(config): + z = zipfile.ZipFile(config.get("ZIP_BYTES")) + print(z.namelist()) + zf = z.open("readme.txt") + print(zf.read()) + return [] +` + + app := &Applet{} + err = app.Load("test.star", []byte(src), nil) + _, err = app.Run(map[string]string{"ZIP_BYTES": buf.String()}, initializer) + assert.NoError(t, err) + + assert.Equal(t, []string{ + "[\"readme.txt\", \"gopher.txt\", \"todo.txt\"]", + "This archive contains some text files.", + }, printedText) +} + // TODO: test Screens, especially Screens.Render()