This commit is contained in:
1
vendor/github.com/ddliu/motto/.gitignore
generated
vendored
Normal file
1
vendor/github.com/ddliu/motto/.gitignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/tests/npm/node_modules
|
||||
11
vendor/github.com/ddliu/motto/.travis.yml
generated
vendored
Normal file
11
vendor/github.com/ddliu/motto/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.6.x
|
||||
- tip
|
||||
|
||||
before_install:
|
||||
- "sudo apt-get update -qq"
|
||||
- "sudo apt-get install -qq nodejs"
|
||||
before_script:
|
||||
- "cd ./tests/npm && npm install && cd ../../"
|
||||
23
vendor/github.com/ddliu/motto/LICENSE
generated
vendored
Normal file
23
vendor/github.com/ddliu/motto/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
MIT License
|
||||
===========
|
||||
|
||||
Copyright (c) 2014 Dong <ddliuhb@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
186
vendor/github.com/ddliu/motto/README.md
generated
vendored
Normal file
186
vendor/github.com/ddliu/motto/README.md
generated
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
# motto
|
||||
|
||||
[](https://travis-ci.org/ddliu/motto)
|
||||
|
||||
Modular [otto](https://github.com/robertkrimen/otto)
|
||||
|
||||
Motto provide a Nodejs like module environment to run javascript files in golang.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
go get github.com/ddliu/motto
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var _ = require('underscore');
|
||||
var data = require('./data.json'); // [3, 2, 1, 4, 6]
|
||||
module.exports = _.min(data);
|
||||
```
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/ddliu/motto"
|
||||
_ "github.com/ddliu/motto/underscore"
|
||||
)
|
||||
|
||||
func main() {
|
||||
motto.Run("path/to/index.js")
|
||||
}
|
||||
```
|
||||
|
||||
You can also install the motto command line tool to run it directly:
|
||||
|
||||
```bash
|
||||
go install github.com/ddliu/motto/motto
|
||||
motto path/to/index.js
|
||||
```
|
||||
|
||||
## Modules
|
||||
|
||||
The module environment is almost capable with Nodejs [spec](http://nodejs.org/api/modules.html).
|
||||
|
||||
Some Nodejs modules(without core module dependencies) can be used directly in Motto.
|
||||
|
||||
## Addons
|
||||
|
||||
Motto can be extended with addons, below is an example addon which implement part of the "fs" module of Nodejs:
|
||||
|
||||
```go
|
||||
package fs
|
||||
|
||||
import (
|
||||
"github.com/ddliu/motto"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
func fsModuleLoader(vm *motto.Motto) (otto.Value, error) {
|
||||
fs, _ := vm.Object(`({})`)
|
||||
fs.Set("readFileSync", func(call otto.FunctionCall) otto.Value {
|
||||
filename, _ := call.Argument(0).ToString()
|
||||
bytes, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
|
||||
v, _ := call.Otto.ToValue(string(bytes))
|
||||
return v
|
||||
})
|
||||
|
||||
return vm.ToValue(fs)
|
||||
}
|
||||
|
||||
func init() {
|
||||
motto.AddModule("fs", fsModuleLoader)
|
||||
}
|
||||
```
|
||||
|
||||
After import this package, you can `require` it directly in your js file:
|
||||
|
||||
```js
|
||||
var fs = require('fs');
|
||||
var content = fs.readFileSync('/path/to/data');
|
||||
```
|
||||
|
||||
## Nodejs in Golang?
|
||||
|
||||
[nodego](https://github.com/ddliu/nodego) implements some features and core modules
|
||||
of Nodejs.
|
||||
|
||||
## Performance
|
||||
|
||||
Simple benchmark shows below for furthur performance optimize:
|
||||
|
||||
```bash
|
||||
strace -c -Ttt motto tests/index.js
|
||||
strace -c -Ttt node tests/index.js
|
||||
```
|
||||
|
||||
Motto:
|
||||
|
||||
```
|
||||
% time seconds usecs/call calls errors syscall
|
||||
------ ----------- ----------- --------- --------- ----------------
|
||||
20.20 0.000144 2 59 rt_sigaction
|
||||
15.71 0.000112 7 15 mmap
|
||||
11.92 0.000085 11 8 futex
|
||||
10.10 0.000072 6 13 4 stat
|
||||
7.43 0.000053 7 8 read
|
||||
5.89 0.000042 21 2 clone
|
||||
5.75 0.000041 10 4 open
|
||||
4.77 0.000034 7 5 rt_sigprocmask
|
||||
4.63 0.000033 33 1 execve
|
||||
3.23 0.000023 12 2 write
|
||||
2.24 0.000016 4 4 fstat
|
||||
1.82 0.000013 3 4 close
|
||||
1.82 0.000013 13 1 sched_getaffinity
|
||||
1.68 0.000012 12 1 sched_yield
|
||||
0.98 0.000007 7 1 munmap
|
||||
0.98 0.000007 7 1 arch_prctl
|
||||
0.42 0.000003 3 1 getcwd
|
||||
0.42 0.000003 3 1 sigaltstack
|
||||
------ ----------- ----------- --------- --------- ----------------
|
||||
100.00 0.000713 131 4 total
|
||||
```
|
||||
|
||||
Nodejs:
|
||||
|
||||
```
|
||||
% time seconds usecs/call calls errors syscall
|
||||
------ ----------- ----------- --------- --------- ----------------
|
||||
20.15 0.000636 7 92 mmap
|
||||
17.78 0.000561 16 36 munmap
|
||||
13.97 0.000441 18 24 read
|
||||
7.73 0.000244 7 35 mprotect
|
||||
7.70 0.000243 15 16 brk
|
||||
7.32 0.000231 7 34 1 futex
|
||||
4.56 0.000144 7 22 open
|
||||
3.61 0.000114 5 22 15 ioctl
|
||||
2.15 0.000068 3 21 close
|
||||
2.03 0.000064 3 21 fstat
|
||||
2.00 0.000063 5 14 14 access
|
||||
1.58 0.000050 4 12 lstat
|
||||
1.24 0.000039 8 5 write
|
||||
1.24 0.000039 6 7 rt_sigaction
|
||||
1.05 0.000033 6 6 2 stat
|
||||
0.89 0.000028 28 1 readlink
|
||||
0.76 0.000024 5 5 rt_sigprocmask
|
||||
0.70 0.000022 6 4 getcwd
|
||||
0.67 0.000021 11 2 pipe2
|
||||
0.63 0.000020 20 1 clone
|
||||
0.38 0.000012 6 2 getrlimit
|
||||
0.29 0.000009 9 1 epoll_create1
|
||||
0.25 0.000008 8 1 eventfd2
|
||||
0.22 0.000007 7 1 clock_gettime
|
||||
0.22 0.000007 4 2 epoll_ctl
|
||||
0.19 0.000006 6 1 gettid
|
||||
0.19 0.000006 6 1 set_tid_address
|
||||
0.19 0.000006 6 1 set_robust_list
|
||||
0.13 0.000004 4 1 execve
|
||||
0.10 0.000003 3 1 arch_prctl
|
||||
0.10 0.000003 3 1 epoll_wait
|
||||
------ ----------- ----------- --------- --------- ----------------
|
||||
100.00 0.003156 393 32 total
|
||||
```
|
||||
|
||||
## Changelog
|
||||
|
||||
### v0.1.0 (2014-06-22)
|
||||
|
||||
Initial release
|
||||
|
||||
### v0.2.0 (2014-06-24)
|
||||
|
||||
Make module capable with Nodejs
|
||||
|
||||
### v0.3.0 (2014-06-26)
|
||||
|
||||
Rewrite module.
|
||||
|
||||
Make it easier to write addons.
|
||||
|
||||
Add underscore addon as an example.
|
||||
191
vendor/github.com/ddliu/motto/module.go
generated
vendored
Normal file
191
vendor/github.com/ddliu/motto/module.go
generated
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
// Copyright 2014 dong<ddliuhb@gmail.com>.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Motto - Modular Javascript environment.
|
||||
package motto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
// ModuleLoader is declared to load a module.
|
||||
type ModuleLoader func(*Motto) (otto.Value, error)
|
||||
|
||||
// Create module loader from javascript source code.
|
||||
//
|
||||
// When the loader is called, the javascript source is executed in Motto.
|
||||
//
|
||||
// "pwd" indicates current working directory, which might be used to search for
|
||||
// modules.
|
||||
func CreateLoaderFromSource(source, filename string) ModuleLoader {
|
||||
pwd := filepath.Dir(filename)
|
||||
return func(vm *Motto) (otto.Value, error) {
|
||||
// Wraps the source to create a module environment
|
||||
source = "(function(module) {var require = module.require;var exports = module.exports;var __dirname = module.__dirname;" + source + "\n})"
|
||||
|
||||
// Provide the "require" method in the module scope.
|
||||
jsRequire := func(call otto.FunctionCall) otto.Value {
|
||||
jsModuleName := call.Argument(0).String()
|
||||
|
||||
moduleValue, err := vm.Require(jsModuleName, pwd)
|
||||
if err != nil {
|
||||
jsException(vm, "Error", "motto: "+err.Error())
|
||||
}
|
||||
|
||||
return moduleValue
|
||||
}
|
||||
|
||||
jsModule, _ := vm.Object(`({exports: {}})`)
|
||||
jsModule.Set("require", jsRequire)
|
||||
jsModule.Set("__dirname", pwd)
|
||||
jsExports, _ := jsModule.Get("exports")
|
||||
|
||||
// Run the module source, with "jsModule" as the "module" variable, "jsExports" as "this"(Nodejs capable).
|
||||
var src *otto.Script
|
||||
var err error
|
||||
var sourceMap string
|
||||
if vm.SourceMapEnabled {
|
||||
sourceMapFilename := filename + ".map"
|
||||
if ok, _ := isFile(sourceMapFilename); ok {
|
||||
if content, err := ioutil.ReadFile(sourceMapFilename); err == nil {
|
||||
sourceMap = string(content)
|
||||
}
|
||||
}
|
||||
}
|
||||
if sourceMap != "" {
|
||||
src, err = vm.CompileWithSourceMap(filename, source, sourceMap)
|
||||
} else {
|
||||
src, err = vm.Compile(filename, source)
|
||||
}
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
srcValue, err := vm.Otto.Run(src)
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
moduleReturn, err := srcValue.Call(jsExports, jsModule)
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
|
||||
var moduleValue otto.Value
|
||||
if !moduleReturn.IsUndefined() {
|
||||
moduleValue = moduleReturn
|
||||
jsModule.Set("exports", moduleValue)
|
||||
} else {
|
||||
moduleValue, _ = jsModule.Get("exports")
|
||||
}
|
||||
|
||||
return moduleValue, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Create module loader from javascript file.
|
||||
//
|
||||
// Filename can be a javascript file or a json file.
|
||||
func CreateLoaderFromFile(filename string) ModuleLoader {
|
||||
return func(vm *Motto) (otto.Value, error) {
|
||||
source, err := ioutil.ReadFile(filename)
|
||||
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
|
||||
// load json
|
||||
if filepath.Ext(filename) == ".json" {
|
||||
return vm.Call("JSON.parse", nil, string(source))
|
||||
}
|
||||
|
||||
return CreateLoaderFromSource(string(source), filename)(vm)
|
||||
}
|
||||
}
|
||||
|
||||
// Find a file module by name.
|
||||
//
|
||||
// If name starts with "." or "/", we search the module in the according locations
|
||||
// (name and name.js and name.json).
|
||||
//
|
||||
// Otherwise we search the module in the "node_modules" sub-directory of "pwd" and
|
||||
// "paths"
|
||||
//
|
||||
// It basicly follows the rules of Node.js module api: http://nodejs.org/api/modules.html
|
||||
func FindFileModule(name, pwd string, paths []string) (string, error) {
|
||||
if len(name) == 0 {
|
||||
return "", errors.New("Empty module name")
|
||||
}
|
||||
|
||||
add := func(choices []string, name string) []string {
|
||||
ext := filepath.Ext(name)
|
||||
if ext != ".js" && ext != ".json" {
|
||||
choices = append(choices, name+".js", name+".json")
|
||||
}
|
||||
choices = append(choices, name)
|
||||
return choices
|
||||
}
|
||||
|
||||
var choices []string
|
||||
if name[0] == '.' || filepath.IsAbs(name) {
|
||||
if name[0] == '.' {
|
||||
name = filepath.Join(pwd, name)
|
||||
}
|
||||
|
||||
choices = add(choices, name)
|
||||
} else {
|
||||
if pwd != "" {
|
||||
choices = add(choices, filepath.Join(pwd, "node_modules", name))
|
||||
}
|
||||
|
||||
for _, v := range paths {
|
||||
choices = add(choices, filepath.Join(v, name))
|
||||
}
|
||||
}
|
||||
|
||||
for _, v := range choices {
|
||||
ok, err := isDir(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if ok {
|
||||
packageJsonFilename := filepath.Join(v, "package.json")
|
||||
ok, err := isFile(packageJsonFilename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var entryPoint string
|
||||
if ok {
|
||||
entryPoint, err = parsePackageEntryPoint(packageJsonFilename)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if entryPoint == "" {
|
||||
entryPoint = "./index.js"
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(entryPoint, ".") {
|
||||
entryPoint = "./" + entryPoint
|
||||
}
|
||||
return FindFileModule(entryPoint, v, paths)
|
||||
}
|
||||
|
||||
ok, err = isFile(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if ok {
|
||||
return filepath.Abs(v)
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("Module not found: " + name)
|
||||
}
|
||||
174
vendor/github.com/ddliu/motto/motto.go
generated
vendored
Normal file
174
vendor/github.com/ddliu/motto/motto.go
generated
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright 2014 dong<ddliuhb@gmail.com>.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Motto - Modular Javascript environment.
|
||||
package motto
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"sync"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
// Globally registered modules
|
||||
var globalModules map[string]ModuleLoader = make(map[string]ModuleLoader)
|
||||
|
||||
// Globally registered paths (paths to search for modules)
|
||||
var globalPaths []string
|
||||
|
||||
// Globally protects global state
|
||||
var globalMu sync.RWMutex
|
||||
|
||||
// Motto is modular vm environment
|
||||
type Motto struct {
|
||||
// Motto is based on otto
|
||||
*otto.Otto
|
||||
|
||||
// try to read source map
|
||||
SourceMapEnabled bool
|
||||
|
||||
// Modules that registered for current vm
|
||||
modules map[string]ModuleLoader
|
||||
modulesMu sync.RWMutex
|
||||
|
||||
// Location to search for modules
|
||||
paths []string
|
||||
pathsMu sync.RWMutex
|
||||
|
||||
// Onece a module is required by vm, the exported value is cached for further
|
||||
// use.
|
||||
moduleCache map[string]otto.Value
|
||||
moduleCacheMu sync.RWMutex
|
||||
}
|
||||
|
||||
// Run a module or file
|
||||
func (m *Motto) Run(name string) (otto.Value, error) {
|
||||
if ok, _ := isFile(name); ok {
|
||||
name, _ = filepath.Abs(name)
|
||||
}
|
||||
|
||||
return m.Require(name, ".")
|
||||
}
|
||||
|
||||
// Require a module with cache
|
||||
func (m *Motto) Require(id, pwd string) (otto.Value, error) {
|
||||
if cache, ok := m.cachedModule(id); ok {
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
loader := m.module(id)
|
||||
if loader == nil {
|
||||
loader = Module(id)
|
||||
}
|
||||
|
||||
if loader != nil {
|
||||
v, err := loader(m)
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
|
||||
m.addCachedModule(id, v)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
filename, err := FindFileModule(id, pwd, append(m.paths, globalPaths...))
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
|
||||
// resove id
|
||||
id = filename
|
||||
|
||||
if cache, ok := m.cachedModule(id); ok {
|
||||
return cache, nil
|
||||
}
|
||||
|
||||
v, err := CreateLoaderFromFile(id)(m)
|
||||
|
||||
if err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
|
||||
m.addCachedModule(id, v)
|
||||
return v, nil
|
||||
}
|
||||
|
||||
func (m *Motto) addCachedModule(id string, v otto.Value) {
|
||||
m.moduleCacheMu.Lock()
|
||||
m.moduleCache[id] = v
|
||||
m.moduleCacheMu.Unlock()
|
||||
}
|
||||
|
||||
func (m *Motto) cachedModule(id string) (otto.Value, bool) {
|
||||
m.moduleCacheMu.RLock()
|
||||
defer m.moduleCacheMu.RUnlock()
|
||||
v, ok := m.moduleCache[id]
|
||||
return v, ok
|
||||
}
|
||||
|
||||
// ClearModule clear all registered module from current vm
|
||||
func (m *Motto) ClearModule() {
|
||||
m.moduleCacheMu.Lock()
|
||||
m.moduleCache = make(map[string]otto.Value)
|
||||
m.moduleCacheMu.Unlock()
|
||||
}
|
||||
|
||||
// AddModule registers a new module to current vm.
|
||||
func (m *Motto) AddModule(id string, l ModuleLoader) {
|
||||
m.modulesMu.Lock()
|
||||
m.modules[id] = l
|
||||
m.modulesMu.Unlock()
|
||||
}
|
||||
|
||||
func (m *Motto) module(id string) ModuleLoader {
|
||||
m.modulesMu.RLock()
|
||||
defer m.modulesMu.RUnlock()
|
||||
return m.modules[id]
|
||||
}
|
||||
|
||||
// AddPath adds paths to search for modules.
|
||||
func (m *Motto) AddPath(paths ...string) {
|
||||
m.pathsMu.Lock()
|
||||
m.paths = append(m.paths, paths...)
|
||||
m.pathsMu.Unlock()
|
||||
}
|
||||
|
||||
// AddModule registers global module
|
||||
func AddModule(id string, m ModuleLoader) {
|
||||
globalMu.Lock()
|
||||
globalModules[id] = m
|
||||
globalMu.Unlock()
|
||||
}
|
||||
|
||||
// Module returns ModuleLoader for a given ID.
|
||||
func Module(id string) ModuleLoader {
|
||||
globalMu.RLock()
|
||||
defer globalMu.RUnlock()
|
||||
|
||||
return globalModules[id]
|
||||
}
|
||||
|
||||
// AddPath registers global path.
|
||||
func AddPath(paths ...string) {
|
||||
globalMu.Lock()
|
||||
globalPaths = append(globalPaths, paths...)
|
||||
globalMu.Unlock()
|
||||
}
|
||||
|
||||
// Run module by name in the motto module environment.
|
||||
func Run(name string) (*Motto, otto.Value, error) {
|
||||
vm := New()
|
||||
v, err := vm.Run(name)
|
||||
|
||||
return vm, v, err
|
||||
}
|
||||
|
||||
// New creates a new motto vm instance.
|
||||
func New() *Motto {
|
||||
return &Motto{
|
||||
Otto: otto.New(),
|
||||
modules: make(map[string]ModuleLoader),
|
||||
moduleCache: make(map[string]otto.Value),
|
||||
}
|
||||
}
|
||||
60
vendor/github.com/ddliu/motto/utils.go
generated
vendored
Normal file
60
vendor/github.com/ddliu/motto/utils.go
generated
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2014 dong<ddliuhb@gmail.com>.
|
||||
// Licensed under the MIT license.
|
||||
//
|
||||
// Motto - Modular Javascript environment.
|
||||
package motto
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
)
|
||||
|
||||
func isDir(path string) (bool, error) {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return fi.IsDir(), nil
|
||||
}
|
||||
|
||||
func isFile(path string) (bool, error) {
|
||||
fi, err := os.Stat(path)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return false, err
|
||||
}
|
||||
|
||||
return !fi.IsDir(), nil
|
||||
}
|
||||
|
||||
type packageInfo struct {
|
||||
Main string `json:"main"`
|
||||
}
|
||||
|
||||
func parsePackageEntryPoint(path string) (string, error) {
|
||||
bytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var info packageInfo
|
||||
err = json.Unmarshal(bytes, &info)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return info.Main, nil
|
||||
}
|
||||
|
||||
// Throw a javascript error, see https://github.com/robertkrimen/otto/issues/17
|
||||
func jsException(vm *Motto, errorType, msg string) {
|
||||
value, _ := vm.Call("new "+errorType, nil, msg)
|
||||
panic(value)
|
||||
}
|
||||
Reference in New Issue
Block a user