Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewrite script/files loading to be be url based #1059

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
aa4b090
Rewrite script/files loading to be be url based
mstoykov Jun 7, 2019
4b91966
fixup! Rewrite script/files loading to be be url based
mstoykov Jun 27, 2019
a894e80
fixup! Rewrite script/files loading to be be url based
mstoykov Jul 4, 2019
3843bc9
fixup! Rewrite script/files loading to be be url based
mstoykov Jul 4, 2019
d27a5f0
Merge remote-tracking branch 'origin/master' into refactor/RewriteaAr…
mstoykov Jul 4, 2019
14e49b1
Rename FSes to Filesystems
mstoykov Jul 4, 2019
2222235
Fix lll error
mstoykov Jul 4, 2019
53f10f5
Add tests for old archive support
mstoykov Jul 4, 2019
ef49dfd
Fix saving and loading archive filename and pwd
mstoykov Jul 5, 2019
3047dec
Fix pwd sometimes missing it's slash at the end
mstoykov Jul 5, 2019
8add590
Fix not recognizing local files which are not starting with . or /
mstoykov Jul 5, 2019
a484a31
Fix lifting config files from the filesystems in the memmapfs and tha…
mstoykov Jul 5, 2019
3e65e7e
Add comment about UnprependPathFs
mstoykov Jul 5, 2019
0832273
Better names and abstration for UnprependPathFs
mstoykov Jul 5, 2019
56a4c37
Refactor normalizedFs to be a ChangePathFs
mstoykov Jul 5, 2019
2fe2d63
rename changepathfs file
mstoykov Jul 5, 2019
622409c
Implement caching and reading of cache for github/cdnjs urls
mstoykov Jul 8, 2019
ac764f3
Refactor the walk function in lib.archive a bit
mstoykov Jul 8, 2019
2e6bce1
Fix name of dumpMemMapFsToBuf
mstoykov Jul 9, 2019
edf5d79
Add test for ChangePathFs and some fixes
mstoykov Jul 9, 2019
c2e4417
Merge remote-tracking branch 'origin/master' into refactor/RewriteaAr…
mstoykov Jul 9, 2019
4bdd575
Check usage of CacheOnReadFs in archive
mstoykov Jul 10, 2019
5d40270
Add test for LstatIfPossible to ChangePathFs
mstoykov Jul 10, 2019
518e58f
Fix wronly calling Mkdir instead of MkdirAll in test
mstoykov Jul 10, 2019
34809f1
test a little bit more of the ChangePathFs.OpenFile code
mstoykov Jul 10, 2019
701df42
Add TrimPathSeparatorFs test
mstoykov Jul 10, 2019
fbda1ae
Fix trimpathseparator on windows
mstoykov Jul 10, 2019
d7be446
Add to TestTrimAferoPathSeparatorFs
mstoykov Jul 10, 2019
8f34ca7
Fix file and directory permissions and times
mstoykov Jul 11, 2019
df56303
Hardlink the to the 'data' file in the archive
mstoykov Jul 11, 2019
4f23674
Merge remote-tracking branch 'origin/master' into refactor/RewriteaAr…
mstoykov Jul 11, 2019
6b08d61
Don't print the warning for schemeless URLs multiple times
mstoykov Jul 11, 2019
b2b681c
Fixes for golangci and not correctly reading scheme urls from the cache
mstoykov Jul 15, 2019
dee4693
Add test testing error on main script not in fs
mstoykov Jul 15, 2019
e6b6ee2
Add tests for bad filename/pwd in archives
mstoykov Jul 15, 2019
1ee2b16
Add test for malformed metadata in archive
mstoykov Jul 15, 2019
ab0bc8a
s/travers/traverse
mstoykov Jul 15, 2019
55b90d0
Fix relative and absolute paths on windows
mstoykov Jul 15, 2019
97a658e
loader.Resolve: Don't change pwd when it's missing slash on the end
mstoykov Jul 15, 2019
723c49e
If a command gets an absolute path don't try it as relative
mstoykov Jul 15, 2019
3b3b905
Add test with funky paths to the archive
mstoykov Jul 16, 2019
67c6b13
100% test coverage for cmd#readSource
mstoykov Jul 16, 2019
fd5d380
Support running and archiving when giving scripts with stdin
mstoykov Jul 16, 2019
60f2295
Move cmd#readSource to loader#ReadSource
mstoykov Jul 16, 2019
305bf81
Move cmd#createFilesystems to loader#CreateFilesystems
mstoykov Jul 16, 2019
f57c992
typo
mstoykov Jul 17, 2019
a9498eb
case insensitive anonymizaiton for windows paths
mstoykov Jul 18, 2019
9249ba4
Add the os under which the archive was made in the archive
mstoykov Jul 23, 2019
20152f1
Merge remote-tracking branch 'origin/master' into refactor/RewriteaAr…
mstoykov Jul 23, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/v1/setup_teardown_routes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"encoding/json"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"

Expand Down Expand Up @@ -130,9 +131,10 @@ func TestSetupData(t *testing.T) {
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
runner, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: testCase.script},
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: testCase.script},
afero.NewMemMapFs(),
lib.RuntimeOptions{},
)
Expand Down
12 changes: 7 additions & 5 deletions cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"io"
"io/ioutil"
"net/http"
"net/url"
"os"
"os/signal"
"path/filepath"
Expand Down Expand Up @@ -508,13 +509,14 @@ func readSource(src, pwd string, fs afero.Fs, stdin io.Reader) (*lib.SourceData,
if err != nil {
return nil, err
}
return &lib.SourceData{Filename: "-", Data: data}, nil
return &lib.SourceData{URL: &url.URL{Path: "-", Scheme: "file"}, Data: data}, nil
}
abspath := filepath.Join(pwd, src)
if ok, _ := afero.Exists(fs, abspath); ok {
src = abspath
pwdURL := &url.URL{Scheme: "file", Path: filepath.ToSlash(filepath.Clean(pwd))}
mstoykov marked this conversation as resolved.
Show resolved Hide resolved
srcURL, err := loader.Resolve(pwdURL, src)
if err != nil {
return nil, err
}
return loader.Load(fs, pwd, src)
return loader.Load(map[string]afero.Fs{"file": fs, "https": afero.NewMemMapFs()}, srcURL, src)
}

// Creates a new runner.
Expand Down
12 changes: 6 additions & 6 deletions cmd/runtime_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package cmd
import (
"bytes"
"fmt"
"net/url"
"os"
"runtime"
"strings"
Expand Down Expand Up @@ -220,8 +221,8 @@ func TestEnvVars(t *testing.T) {

runner, err := newRunner(
&lib.SourceData{
Data: []byte(jsCode),
Filename: "/script.js",
Data: []byte(jsCode),
URL: &url.URL{Path: "/script.js"},
},
typeJS,
afero.NewOsFs(),
Expand All @@ -234,16 +235,15 @@ func TestEnvVars(t *testing.T) {
assert.NoError(t, archive.Write(archiveBuf))

getRunnerErr := func(rtOpts lib.RuntimeOptions) (lib.Runner, error) {
r, err := newRunner(
return newRunner(
&lib.SourceData{
Data: []byte(archiveBuf.Bytes()),
Filename: "/script.tar",
Data: archiveBuf.Bytes(),
URL: &url.URL{Path: "/script.js"},
},
typeArchive,
afero.NewOsFs(),
rtOpts,
)
return r, err
}

_, err = getRunnerErr(lib.RuntimeOptions{})
Expand Down
4 changes: 2 additions & 2 deletions converter/har/converter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ func TestBuildK6RequestObject(t *testing.T) {
v, err := buildK6RequestObject(req)
assert.NoError(t, err)
_, err = js.New(&lib.SourceData{
Filename: "/script.js",
Data: []byte(fmt.Sprintf("export default function() { res = http.batch([%v]); }", v)),
URL: &url.URL{Path: "/script.js"},
Data: []byte(fmt.Sprintf("export default function() { res = http.batch([%v]); }", v)),
}, afero.NewMemMapFs(), lib.RuntimeOptions{})
assert.NoError(t, err)
}
Expand Down
11 changes: 6 additions & 5 deletions core/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package core
import (
"context"
"fmt"
"net/url"
"testing"
"time"

Expand Down Expand Up @@ -556,7 +557,7 @@ func TestSentReceivedMetrics(t *testing.T) {

runTest := func(t *testing.T, ts testScript, tc testCase, noConnReuse bool) (float64, float64) {
r, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: []byte(ts.Code)},
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: []byte(ts.Code)},
afero.NewMemMapFs(),
lib.RuntimeOptions{},
)
Expand Down Expand Up @@ -697,7 +698,7 @@ func TestRunTags(t *testing.T) {
`))

r, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: script},
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: script},
afero.NewMemMapFs(),
lib.RuntimeOptions{},
)
Expand Down Expand Up @@ -797,7 +798,7 @@ func TestSetupTeardownThresholds(t *testing.T) {
`))

runner, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: script},
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: script},
afero.NewMemMapFs(),
lib.RuntimeOptions{},
)
Expand Down Expand Up @@ -860,7 +861,7 @@ func TestEmittedMetricsWhenScalingDown(t *testing.T) {
`))

runner, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: script},
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: script},
afero.NewMemMapFs(),
lib.RuntimeOptions{},
)
Expand Down Expand Up @@ -920,7 +921,7 @@ func TestMinIterationDuration(t *testing.T) {
t.Parallel()

runner, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: []byte(`
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: []byte(`
import { Counter } from "k6/metrics";

let testCounter = new Counter("testcounter");
Expand Down
3 changes: 2 additions & 1 deletion core/local/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ package local
import (
"context"
"net"
"net/url"
"runtime"
"sync/atomic"
"testing"
Expand Down Expand Up @@ -481,7 +482,7 @@ func TestRealTimeAndSetupTeardownMetrics(t *testing.T) {
}`)

runner, err := js.New(
&lib.SourceData{Filename: "/script.js", Data: script},
&lib.SourceData{URL: &url.URL{Path: "/script.js"}, Data: script},
afero.NewMemMapFs(),
lib.RuntimeOptions{},
)
Expand Down
66 changes: 43 additions & 23 deletions js/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ package js
import (
"context"
"encoding/json"
"os"
"net/url"
"time"

"github.com/dop251/goja"
"github.com/loadimpact/k6/js/common"
Expand All @@ -38,7 +39,7 @@ import (
// A Bundle is a self-contained bundle of scripts and resources.
// You can use this to produce identical BundleInstance objects.
type Bundle struct {
Filename string
Filename *url.URL
Source string
Program *goja.Program
Options lib.Options
Expand All @@ -55,16 +56,32 @@ type BundleInstance struct {
Default goja.Callable
}

type cacheOnReadFs struct {
afero.Fs
cache afero.Fs
}

func newCacheOnReadFs(base, layer afero.Fs, cacheTime time.Duration) afero.Fs {
return cacheOnReadFs{
Fs: afero.NewCacheOnReadFs(base, layer, cacheTime),
cache: layer,
}
}

func (c cacheOnReadFs) GetCachedFs() afero.Fs {
return c.cache
}

// NewBundle creates a new bundle from a source file and a filesystem.
func NewBundle(src *lib.SourceData, fs afero.Fs, rtOpts lib.RuntimeOptions) (*Bundle, error) {
func NewBundle(src *lib.SourceData, fileFS afero.Fs, rtOpts lib.RuntimeOptions) (*Bundle, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this rename? Are we sure that this file system will always be a fileFS, not something else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my current reworking due to windows ... I now provide the whole map[string]afero.Fs, for reasons that will become apparent :)
But yeah the idea here was that this would be the fileFs that was used to load the original script from ... Obviously this doesn't work very well as

  1. We won't cache that one when we first load it in the cmd/run.go or elsewhere
  2. Won't work if we load (and again not cache it) if it was from a remote script ... aka https Fs :)

compiler, err := compiler.New()
if err != nil {
return nil, err
}

// Compile sources, both ES5 and ES6 are supported.
code := string(src.Data)
pgm, _, err := compiler.Compile(code, src.Filename, "", "", true)
pgm, _, err := compiler.Compile(code, src.URL.String(), "", "", true)
if err != nil {
return nil, err
}
Expand All @@ -73,15 +90,19 @@ func NewBundle(src *lib.SourceData, fs afero.Fs, rtOpts lib.RuntimeOptions) (*Bu
// written every time something is read from the real filesystem. This cache is then used for
// successive spawns to read from (they have no access to the real disk).
mirrorFS := afero.NewMemMapFs()
cachedFS := afero.NewCacheOnReadFs(fs, mirrorFS, 0)
cachedFS := newCacheOnReadFs(fileFS, mirrorFS, 0)
fses := map[string]afero.Fs{
"file": cachedFS,
"https": afero.NewMemMapFs(),
}

// Make a bundle, instantiate it into a throwaway VM to populate caches.
rt := goja.New()
bundle := Bundle{
Filename: src.Filename,
Filename: src.URL,
Source: code,
Program: pgm,
BaseInitContext: NewInitContext(rt, compiler, new(context.Context), cachedFS, loader.Dir(src.Filename)),
BaseInitContext: NewInitContext(rt, compiler, new(context.Context), fses, loader.Dir(src.URL)),
Env: rtOpts.Env,
}
if err := bundle.instantiate(rt, bundle.BaseInitContext); err != nil {
Expand Down Expand Up @@ -146,8 +167,17 @@ func NewBundleFromArchive(arc *lib.Archive, rtOpts lib.RuntimeOptions) (*Bundle,
if err != nil {
return nil, err
}
initctx := NewInitContext(goja.New(), compiler, new(context.Context), arc.FS, arc.Pwd)
initctx.files = arc.Files
pwdURL, err := loader.Resolve(&url.URL{Scheme: "file", Path: "/"}, arc.Pwd)
if err != nil {
return nil, err
}

filenameURL, err := loader.Resolve(pwdURL, arc.Filename)
if err != nil {
return nil, err
}

initctx := NewInitContext(goja.New(), compiler, new(context.Context), arc.FSes, pwdURL)

env := arc.Env
if env == nil {
Expand All @@ -159,7 +189,7 @@ func NewBundleFromArchive(arc *lib.Archive, rtOpts lib.RuntimeOptions) (*Bundle,
}

bundle := &Bundle{
Filename: arc.Filename,
Filename: filenameURL,
Source: string(arc.Data),
Program: pgm,
Options: arc.Options,
Expand All @@ -175,28 +205,18 @@ func NewBundleFromArchive(arc *lib.Archive, rtOpts lib.RuntimeOptions) (*Bundle,
func (b *Bundle) makeArchive() *lib.Archive {
arc := &lib.Archive{
Type: "js",
FS: afero.NewMemMapFs(),
FSes: b.BaseInitContext.fses,
Options: b.Options,
Filename: b.Filename,
Filename: b.Filename.String(),
Data: []byte(b.Source),
Pwd: b.BaseInitContext.pwd,
Pwd: b.BaseInitContext.pwd.String(),
Env: make(map[string]string, len(b.Env)),
}
// Copy env so changes in the archive are not reflected in the source Bundle
for k, v := range b.Env {
arc.Env[k] = v
}

arc.Scripts = make(map[string][]byte, len(b.BaseInitContext.programs))
for name, pgm := range b.BaseInitContext.programs {
arc.Scripts[name] = []byte(pgm.src)
err := afero.WriteFile(arc.FS, name, []byte(pgm.src), os.ModePerm)
if err != nil {
return nil
}
}
arc.Files = b.BaseInitContext.files

return arc
}

Expand Down
Loading