mirror of
https://github.com/status-im/status-go.git
synced 2025-02-22 11:48:31 +00:00
Add SetTimeout/SetInterval to JailCell otto.Otto, closes #189
* Commit initial change for settimeout/setinterval * Add initial tests for jail setTimeout/setInterval * Add ottoext dependency * Add fetch jail test with function * Add dependencies of fetch from ottoext * Refactor with regards to PR review * Refactor with regards to PR review * Fix syntax errors * Fix missing return statement
This commit is contained in:
parent
fb7738b1bb
commit
b50c46caa8
@ -16,6 +16,8 @@ import (
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
"github.com/status-im/status-go/static"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
)
|
||||
|
||||
// errors
|
||||
@ -171,9 +173,28 @@ type TxQueueManager interface {
|
||||
DiscardTransactions(ids string) map[string]RawDiscardTransactionResult
|
||||
}
|
||||
|
||||
// JailExecutor defines an interface which exposes method to be executed
|
||||
// against a Jail vm.
|
||||
type JailExecutor interface {
|
||||
// Run exist so we are able to execute js code on pure otto.VM without runing
|
||||
// it on the event loop.
|
||||
Run(string) (otto.Value, error)
|
||||
|
||||
// Exec exists for the purpose to execute has normal on the event loop provided by
|
||||
// ottoext.
|
||||
Exec(string) (otto.Value, error)
|
||||
|
||||
// Fetch calls the underlying FetchAPI which makes http request
|
||||
// to desired path. (See https://developer.mozilla.org/en/docs/Web/API/Fetch_API).
|
||||
Fetch(string, func(otto.Value)) (otto.Value, error)
|
||||
}
|
||||
|
||||
// JailCell represents single jail cell, which is basically a JavaScript VM.
|
||||
type JailCell interface {
|
||||
CellVM() *otto.Otto
|
||||
CellLoop() *loop.Loop
|
||||
Executor() JailExecutor
|
||||
Copy() (JailCell, error)
|
||||
}
|
||||
|
||||
// JailManager defines methods for managing jailed environments
|
||||
|
@ -13,6 +13,10 @@ import (
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/common"
|
||||
"github.com/status-im/status-go/static"
|
||||
|
||||
"fknsrs.biz/p/ottoext/fetch"
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
"fknsrs.biz/p/ottoext/timers"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -31,9 +35,32 @@ var (
|
||||
type JailCell struct {
|
||||
id string
|
||||
vm *otto.Otto
|
||||
lo *loop.Loop
|
||||
sem *semaphore.Semaphore
|
||||
}
|
||||
|
||||
// newJailCell encapsulates what we need to create a new jailCell from the
|
||||
// provided vm and eventloop instance.
|
||||
func newJailCell(id string, vm *otto.Otto, lo *loop.Loop) (*JailCell, error) {
|
||||
|
||||
// Register fetch provider from ottoext.
|
||||
if err := fetch.Define(vm, lo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Register event loop for timers.
|
||||
if err := timers.Define(vm, lo); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &JailCell{
|
||||
id: id,
|
||||
vm: vm,
|
||||
lo: lo,
|
||||
sem: semaphore.New(1, JailCellRequestTimeout*time.Second),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Jail represents jailed environment inside of which we hold multiple cells.
|
||||
// Each cell is a separate JavaScript VM.
|
||||
type Jail struct {
|
||||
@ -43,6 +70,60 @@ type Jail struct {
|
||||
baseJSCode string // JavaScript used to initialize all new cells with
|
||||
}
|
||||
|
||||
// Copy returns a new JailCell instance with a new eventloop runtime associated with
|
||||
// the given cell.
|
||||
func (cell *JailCell) Copy() (common.JailCell, error) {
|
||||
vmCopy := cell.vm.Copy()
|
||||
return newJailCell(cell.id, vmCopy, loop.New(vmCopy))
|
||||
}
|
||||
|
||||
// Fetch attempts to call the underline Fetch API added through the
|
||||
// ottoext package.
|
||||
func (cell *JailCell) Fetch(url string, callback func(otto.Value)) (otto.Value, error) {
|
||||
if err := cell.vm.Set("__captureFetch", callback); err != nil {
|
||||
return otto.UndefinedValue(), err
|
||||
}
|
||||
|
||||
return cell.Exec(`fetch("` + url + `").then(function(response){
|
||||
__captureFetch({
|
||||
"url": response.url,
|
||||
"type": response.type,
|
||||
"body": response.text(),
|
||||
"status": response.status,
|
||||
"headers": response.headers,
|
||||
});
|
||||
});
|
||||
`)
|
||||
}
|
||||
|
||||
// Exec evaluates the giving js string on the associated vm loop returning
|
||||
// an error.
|
||||
func (cell *JailCell) Exec(val string) (otto.Value, error) {
|
||||
res, err := cell.vm.Run(val)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
|
||||
return res, cell.lo.Run()
|
||||
}
|
||||
|
||||
// Run evaluates the giving js string on the associated vm llop.
|
||||
func (cell *JailCell) Run(val string) (otto.Value, error) {
|
||||
return cell.vm.Run(val)
|
||||
}
|
||||
|
||||
// CellLoop returns the ottoext.Loop instance which provides underline timeout/setInternval
|
||||
// event runtime for the Jail vm.
|
||||
func (cell *JailCell) CellLoop() *loop.Loop {
|
||||
return cell.lo
|
||||
}
|
||||
|
||||
// Executor returns a structure which implements the common.JailExecutor.
|
||||
func (cell *JailCell) Executor() common.JailExecutor {
|
||||
return cell
|
||||
}
|
||||
|
||||
// CellVM returns the associated otto.Vm connect to the giving cell.
|
||||
func (cell *JailCell) CellVM() *otto.Otto {
|
||||
return cell.vm
|
||||
}
|
||||
@ -62,11 +143,16 @@ func (jail *Jail) BaseJS(js string) {
|
||||
|
||||
// NewJailCell initializes and returns jail cell
|
||||
func (jail *Jail) NewJailCell(id string) common.JailCell {
|
||||
return &JailCell{
|
||||
id: id,
|
||||
vm: otto.New(),
|
||||
sem: semaphore.New(1, JailCellRequestTimeout*time.Second),
|
||||
vm := otto.New()
|
||||
|
||||
newJail, err := newJailCell(id, vm, loop.New(vm))
|
||||
if err != nil {
|
||||
//TODO(alex): Should we really panic here, his there
|
||||
// a better way. Think on it.
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return newJail
|
||||
}
|
||||
|
||||
// Parse creates a new jail cell context, with the given chatID as identifier.
|
||||
@ -127,7 +213,15 @@ func (jail *Jail) Call(chatID string, path string, args string) string {
|
||||
}
|
||||
jail.RUnlock()
|
||||
|
||||
vm := cell.CellVM().Copy() // isolate VM to allow concurrent access
|
||||
// Due to the new timer assigned we need to clone existing cell to allow
|
||||
// unique cell runtime and eventloop context.
|
||||
cellCopy, err := cell.Copy()
|
||||
if err != nil {
|
||||
return makeError(err.Error())
|
||||
}
|
||||
|
||||
// isolate VM to allow concurrent access
|
||||
vm := cellCopy.CellVM()
|
||||
res, err := vm.Call("call", nil, path, args)
|
||||
|
||||
return makeResult(res.String(), err)
|
||||
|
@ -3,9 +3,12 @@ package jail_test
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/status-im/status-go/geth/jail"
|
||||
"github.com/status-im/status-go/geth/node"
|
||||
"github.com/status-im/status-go/geth/params"
|
||||
@ -115,6 +118,83 @@ func (s *JailTestSuite) TestFunctionCall() {
|
||||
require.Equal(expectedResponse, response)
|
||||
}
|
||||
|
||||
func (s *JailTestSuite) TestJailTimeoutFailure() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.jail)
|
||||
|
||||
newCell := s.jail.NewJailCell(testChatID)
|
||||
require.NotNil(newCell)
|
||||
|
||||
execr := newCell.Executor()
|
||||
|
||||
// Attempt to run a timeout string against a JailCell.
|
||||
_, err := execr.Exec(`
|
||||
setTimeout(function(n){
|
||||
if(Date.now() - n < 50){
|
||||
throw new Error("Timedout early");
|
||||
}
|
||||
|
||||
return n;
|
||||
}, 30, Date.now());
|
||||
`)
|
||||
|
||||
require.NotNil(err)
|
||||
}
|
||||
|
||||
func (s *JailTestSuite) TestJailTimeout() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.jail)
|
||||
|
||||
newCell := s.jail.NewJailCell(testChatID)
|
||||
require.NotNil(newCell)
|
||||
|
||||
execr := newCell.Executor()
|
||||
|
||||
// Attempt to run a timeout string against a JailCell.
|
||||
res, err := execr.Exec(`
|
||||
setTimeout(function(n){
|
||||
if(Date.now() - n < 50){
|
||||
throw new Error("Timedout early");
|
||||
}
|
||||
|
||||
return n;
|
||||
}, 50, Date.now());
|
||||
`)
|
||||
|
||||
require.NoError(err)
|
||||
require.NotNil(res)
|
||||
}
|
||||
|
||||
func (s *JailTestSuite) TestJailFetch() {
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(http.StatusOK)
|
||||
w.Write([]byte("Hello World"))
|
||||
})
|
||||
|
||||
server := httptest.NewServer(mux)
|
||||
defer server.Close()
|
||||
|
||||
require := s.Require()
|
||||
require.NotNil(s.jail)
|
||||
|
||||
newCell := s.jail.NewJailCell(testChatID)
|
||||
require.NotNil(newCell)
|
||||
|
||||
execr := newCell.Executor()
|
||||
|
||||
wait := make(chan struct{})
|
||||
|
||||
// Attempt to run a fetch resource.
|
||||
_, err := execr.Fetch(server.URL, func(res otto.Value) {
|
||||
go func() { wait <- struct{}{} }()
|
||||
})
|
||||
|
||||
require.NoError(err)
|
||||
|
||||
<-wait
|
||||
}
|
||||
|
||||
func (s *JailTestSuite) TestJailRPCSend() {
|
||||
require := s.Require()
|
||||
require.NotNil(s.jail)
|
||||
|
26
vendor/fknsrs.biz/p/ottoext/LICENSE.md
vendored
Normal file
26
vendor/fknsrs.biz/p/ottoext/LICENSE.md
vendored
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2015, Deoxxa Development
|
||||
======================================
|
||||
All rights reserved.
|
||||
--------------------
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of Deoxxa Development nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY DEOXXA DEVELOPMENT ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL DEOXXA DEVELOPMENT BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
22
vendor/fknsrs.biz/p/ottoext/README.md
vendored
Normal file
22
vendor/fknsrs.biz/p/ottoext/README.md
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
ottoext
|
||||
=======
|
||||
|
||||
[](https://godoc.org/fknsrs.biz/p/ottoext)
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
This package contains some extensions for the otto JavaScript interpreter. The
|
||||
most important extension is a generic event loop based on code from natto. The
|
||||
other extensions are `setTimeout` and `setInterval` support, `Promise` support
|
||||
(via `native-promise-only`, MIT license), and `fetch` support.
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Take a look at the test files to see how the extensions work.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
3-clause BSD. A copy is included with the source.
|
1
vendor/fknsrs.biz/p/ottoext/cmd/ottoext/.gitignore
vendored
Normal file
1
vendor/fknsrs.biz/p/ottoext/cmd/ottoext/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/ottoext
|
12
vendor/fknsrs.biz/p/ottoext/cmd/ottoext/example.js
vendored
Normal file
12
vendor/fknsrs.biz/p/ottoext/cmd/ottoext/example.js
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
var x = fetch('http://www.example.com/').then(function(r) {
|
||||
r.text().then(function(d) {
|
||||
console.log(r.statusText);
|
||||
|
||||
for (var k in r.headers._headers) {
|
||||
console.log(k + ':', r.headers.get(k));
|
||||
}
|
||||
console.log('');
|
||||
|
||||
console.log(d);
|
||||
});
|
||||
});
|
90
vendor/fknsrs.biz/p/ottoext/cmd/ottoext/main.go
vendored
Normal file
90
vendor/fknsrs.biz/p/ottoext/cmd/ottoext/main.go
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
// command otto runs JavaScript from a file, opens a repl, or does both.
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
"fknsrs.biz/p/ottoext/loop/looptask"
|
||||
erepl "fknsrs.biz/p/ottoext/repl"
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/robertkrimen/otto/repl"
|
||||
|
||||
"fknsrs.biz/p/ottoext/fetch"
|
||||
"fknsrs.biz/p/ottoext/process"
|
||||
"fknsrs.biz/p/ottoext/promise"
|
||||
"fknsrs.biz/p/ottoext/timers"
|
||||
)
|
||||
|
||||
var (
|
||||
openRepl = flag.Bool("repl", false, "Always open a REPL, even if a file is provided.")
|
||||
debugger = flag.Bool("debugger", false, "Attach REPL-based debugger.")
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
vm := otto.New()
|
||||
|
||||
if *debugger {
|
||||
vm.SetDebuggerHandler(repl.DebuggerHandler)
|
||||
}
|
||||
|
||||
l := loop.New(vm)
|
||||
|
||||
if err := timers.Define(vm, l); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := promise.Define(vm, l); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := fetch.Define(vm, l); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := process.Define(vm, flag.Args()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
blockingTask := looptask.NewEvalTask("")
|
||||
|
||||
if len(flag.Args()) == 0 || *openRepl {
|
||||
l.Add(blockingTask)
|
||||
}
|
||||
|
||||
if len(flag.Args()) > 0 {
|
||||
d, err := ioutil.ReadFile(flag.Arg(0))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// this is a very cheap way of "supporting" shebang lines
|
||||
if d[0] == '#' {
|
||||
d = []byte("// " + string(d))
|
||||
}
|
||||
|
||||
s, err := vm.Compile(flag.Arg(0), string(d))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if err := l.Eval(s); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
if len(flag.Args()) == 0 || *openRepl {
|
||||
go func() {
|
||||
if err := erepl.Run(l); err != nil && err != io.EOF {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
l.Ready(blockingTask)
|
||||
}()
|
||||
}
|
||||
|
||||
if err := l.Run(); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
13
vendor/fknsrs.biz/p/ottoext/fetch/Makefile
vendored
Normal file
13
vendor/fknsrs.biz/p/ottoext/fetch/Makefile
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
dist-fetch.rice-box.go: dist-fetch/bundle.js
|
||||
rice embed-go
|
||||
|
||||
dist-fetch/bundle.js: js/bundle.js
|
||||
mkdir -p dist-fetch
|
||||
cp -a js/bundle.js dist-fetch/bundle.js
|
||||
cp -a js/bundle.js.map dist-fetch/bundle.js.map
|
||||
|
||||
js/bundle.js: js/fetch.js js/headers.js js/index.js js/request.js js/response.js
|
||||
cd js && npm install && npm run bundle${BUNDLE_SUFFIX}
|
||||
|
||||
clean:
|
||||
rm -rf dist-fetch.rice-box.go dist-fetch js/bundle.js
|
48
vendor/fknsrs.biz/p/ottoext/fetch/dist-fetch.rice-box.go
vendored
Normal file
48
vendor/fknsrs.biz/p/ottoext/fetch/dist-fetch.rice-box.go
vendored
Normal file
File diff suppressed because one or more lines are too long
359
vendor/fknsrs.biz/p/ottoext/fetch/dist-fetch/bundle.js
vendored
Normal file
359
vendor/fknsrs.biz/p/ottoext/fetch/dist-fetch/bundle.js
vendored
Normal file
@ -0,0 +1,359 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId])
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ exports: {},
|
||||
/******/ id: moduleId,
|
||||
/******/ loaded: false
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.loaded = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/*!******************!*\
|
||||
!*** ./index.js ***!
|
||||
\******************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
__webpack_require__(/*! expose?fetch!./fetch */ 1);
|
||||
__webpack_require__(/*! expose?Headers!./headers */ 6);
|
||||
__webpack_require__(/*! expose?Request!./request */ 7);
|
||||
__webpack_require__(/*! expose?Response!./response */ 8);
|
||||
|
||||
/***/ },
|
||||
/* 1 */
|
||||
/*!******************************************!*\
|
||||
!*** ./~/expose-loader?fetch!./fetch.js ***!
|
||||
\******************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["fetch"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./fetch.js */ 2);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ },
|
||||
/* 2 */
|
||||
/*!*******************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./fetch.js ***!
|
||||
\*******************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
exports['default'] = fetch;
|
||||
var Request = __webpack_require__(/*! ./request */ 3);
|
||||
var Response = __webpack_require__(/*! ./response */ 5);
|
||||
|
||||
function fetch(input, init) {
|
||||
var req = new Request(input, init);
|
||||
var res = new Response();
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
return __private__fetch_execute(req, res, function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 3 */
|
||||
/*!*********************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./request.js ***!
|
||||
\*********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
var Headers = __webpack_require__(/*! ./headers */ 4);
|
||||
|
||||
var Request = function Request(input) {
|
||||
var _ref = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
|
||||
|
||||
var method = _ref.method;
|
||||
var headers = _ref.headers;
|
||||
var redirect = _ref.redirect;
|
||||
var body = _ref.body;
|
||||
|
||||
_classCallCheck(this, Request);
|
||||
|
||||
this.method = 'GET';
|
||||
this.headers = new Headers({});
|
||||
this.redirect = 'manual';
|
||||
this.body = null;
|
||||
|
||||
if (input instanceof Request) {
|
||||
this.url = input.url;
|
||||
this.method = input.method;
|
||||
this.headers = new Headers(input.headers);
|
||||
this.redirect = input.redirect;
|
||||
} else {
|
||||
this.url = input;
|
||||
}
|
||||
|
||||
if (method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
this.headers = new Headers(headers);
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
this.redirect = redirect;
|
||||
}
|
||||
|
||||
if (body) {
|
||||
this.body = body;
|
||||
}
|
||||
};
|
||||
|
||||
exports['default'] = Request;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 4 */
|
||||
/*!*********************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./headers.js ***!
|
||||
\*********************************************/
|
||||
/***/ function(module, exports) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
var Headers = (function () {
|
||||
function Headers(init) {
|
||||
var _this = this;
|
||||
|
||||
_classCallCheck(this, Headers);
|
||||
|
||||
this._headers = {};
|
||||
|
||||
if (init instanceof Headers) {
|
||||
init = init._headers;
|
||||
}
|
||||
|
||||
if (typeof init === 'object' && init !== null) {
|
||||
for (var k in init) {
|
||||
var v = init[k];
|
||||
if (!Array.isArray(v)) {
|
||||
v = [v];
|
||||
}
|
||||
|
||||
v.forEach(function (e) {
|
||||
return _this.append(k, e);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_createClass(Headers, [{
|
||||
key: 'append',
|
||||
value: function append(name, value) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
if (!Object.hasOwnProperty.call(this._headers, normalisedName)) {
|
||||
this._headers[normalisedName] = [];
|
||||
}
|
||||
|
||||
this._headers[normalisedName].push(value);
|
||||
}
|
||||
}, {
|
||||
key: 'delete',
|
||||
value: function _delete(name) {
|
||||
delete this._headers[Headers.normaliseName(name)];
|
||||
}
|
||||
}, {
|
||||
key: 'get',
|
||||
value: function get(name) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
if (this._headers[normalisedName]) {
|
||||
return this._headers[normalisedName][0];
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'getAll',
|
||||
value: function getAll(name) {
|
||||
return this._headers[Headers.normaliseName(name)] || [];
|
||||
}
|
||||
}, {
|
||||
key: 'has',
|
||||
value: function has(name) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
return Array.isArray(this._headers[normalisedName]);
|
||||
}
|
||||
}, {
|
||||
key: 'set',
|
||||
value: function set(name, value) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
this._headers[normalisedName] = [value];
|
||||
}
|
||||
}], [{
|
||||
key: 'normaliseName',
|
||||
value: function normaliseName(name) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
}]);
|
||||
|
||||
return Headers;
|
||||
})();
|
||||
|
||||
exports['default'] = Headers;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 5 */
|
||||
/*!**********************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./response.js ***!
|
||||
\**********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
var Headers = __webpack_require__(/*! ./headers */ 4);
|
||||
|
||||
var Response = (function () {
|
||||
function Response(body) {
|
||||
var _ref = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
|
||||
|
||||
var _ref$status = _ref.status;
|
||||
var status = _ref$status === undefined ? 200 : _ref$status;
|
||||
var _ref$statusText = _ref.statusText;
|
||||
var statusText = _ref$statusText === undefined ? 'OK' : _ref$statusText;
|
||||
var _ref$headers = _ref.headers;
|
||||
var headers = _ref$headers === undefined ? {} : _ref$headers;
|
||||
|
||||
_classCallCheck(this, Response);
|
||||
|
||||
this.bodyUsed = true;
|
||||
this._body = null;
|
||||
|
||||
this.headers = new Headers(headers);
|
||||
this.ok = status >= 200 && status < 300;
|
||||
this.status = status;
|
||||
this.statusText = statusText;
|
||||
this.type = this.headers.get('content-type');
|
||||
}
|
||||
|
||||
_createClass(Response, [{
|
||||
key: 'text',
|
||||
value: function text() {
|
||||
var _this = this;
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
return resolve(_this._body);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'json',
|
||||
value: function json() {
|
||||
return this.text().then(function (d) {
|
||||
return JSON.parse(d);
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
return Response;
|
||||
})();
|
||||
|
||||
exports['default'] = Response;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 6 */
|
||||
/*!**********************************************!*\
|
||||
!*** ./~/expose-loader?Headers!./headers.js ***!
|
||||
\**********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["Headers"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./headers.js */ 4);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ },
|
||||
/* 7 */
|
||||
/*!**********************************************!*\
|
||||
!*** ./~/expose-loader?Request!./request.js ***!
|
||||
\**********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["Request"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./request.js */ 3);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ },
|
||||
/* 8 */
|
||||
/*!************************************************!*\
|
||||
!*** ./~/expose-loader?Response!./response.js ***!
|
||||
\************************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["Response"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./response.js */ 5);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ }
|
||||
/******/ ]);
|
||||
//# sourceMappingURL=bundle.js.map
|
1
vendor/fknsrs.biz/p/ottoext/fetch/dist-fetch/bundle.js.map
vendored
Normal file
1
vendor/fknsrs.biz/p/ottoext/fetch/dist-fetch/bundle.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
157
vendor/fknsrs.biz/p/ottoext/fetch/fetch.go
vendored
Normal file
157
vendor/fknsrs.biz/p/ottoext/fetch/fetch.go
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
package fetch // import "fknsrs.biz/p/ottoext/fetch"
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/robertkrimen/otto"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
"fknsrs.biz/p/ottoext/promise"
|
||||
)
|
||||
|
||||
func mustValue(v otto.Value, err error) otto.Value {
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return v
|
||||
}
|
||||
|
||||
type fetchTask struct {
|
||||
id int64
|
||||
jsReq, jsRes *otto.Object
|
||||
cb otto.Value
|
||||
err error
|
||||
status int
|
||||
statusText string
|
||||
headers map[string][]string
|
||||
body []byte
|
||||
}
|
||||
|
||||
func (t *fetchTask) SetID(id int64) { t.id = id }
|
||||
func (t *fetchTask) GetID() int64 { return t.id }
|
||||
|
||||
func (t *fetchTask) Execute(vm *otto.Otto, l *loop.Loop) error {
|
||||
var arguments []interface{}
|
||||
|
||||
if t.err != nil {
|
||||
e, err := vm.Call(`new Error`, nil, t.err.Error())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
arguments = append(arguments, e)
|
||||
}
|
||||
|
||||
t.jsRes.Set("status", t.status)
|
||||
t.jsRes.Set("statusText", t.statusText)
|
||||
h := mustValue(t.jsRes.Get("headers")).Object()
|
||||
for k, vs := range t.headers {
|
||||
for _, v := range vs {
|
||||
if _, err := h.Call("append", k, v); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
t.jsRes.Set("_body", string(t.body))
|
||||
|
||||
if _, err := t.cb.Call(otto.NullValue(), arguments...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *fetchTask) Cancel() {
|
||||
}
|
||||
|
||||
func Define(vm *otto.Otto, l *loop.Loop) error {
|
||||
return DefineWithHandler(vm, l, nil)
|
||||
}
|
||||
|
||||
func DefineWithHandler(vm *otto.Otto, l *loop.Loop, h http.Handler) error {
|
||||
if err := promise.Define(vm, l); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
jsData := rice.MustFindBox("dist-fetch").MustString("bundle.js")
|
||||
smData := rice.MustFindBox("dist-fetch").MustString("bundle.js.map")
|
||||
|
||||
s, err := vm.CompileWithSourceMap("fetch-bundle.js", jsData, smData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := vm.Run(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm.Set("__private__fetch_execute", func(c otto.FunctionCall) otto.Value {
|
||||
jsReq := c.Argument(0).Object()
|
||||
jsRes := c.Argument(1).Object()
|
||||
cb := c.Argument(2)
|
||||
|
||||
method := mustValue(jsReq.Get("method")).String()
|
||||
urlStr := mustValue(jsReq.Get("url")).String()
|
||||
jsBody := mustValue(jsReq.Get("body"))
|
||||
var body io.Reader
|
||||
if jsBody.IsString() {
|
||||
body = strings.NewReader(jsBody.String())
|
||||
}
|
||||
|
||||
t := &fetchTask{
|
||||
jsReq: jsReq,
|
||||
jsRes: jsRes,
|
||||
cb: cb,
|
||||
}
|
||||
|
||||
l.Add(t)
|
||||
|
||||
go func() {
|
||||
defer l.Ready(t)
|
||||
|
||||
req, err := http.NewRequest(method, urlStr, body)
|
||||
if err != nil {
|
||||
t.err = err
|
||||
return
|
||||
}
|
||||
|
||||
if h != nil && urlStr[0] == '/' {
|
||||
res := httptest.NewRecorder()
|
||||
|
||||
h.ServeHTTP(res, req)
|
||||
|
||||
t.status = res.Code
|
||||
t.statusText = http.StatusText(res.Code)
|
||||
t.headers = res.Header()
|
||||
t.body = res.Body.Bytes()
|
||||
} else {
|
||||
res, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
t.err = err
|
||||
return
|
||||
}
|
||||
|
||||
d, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
t.err = err
|
||||
return
|
||||
}
|
||||
|
||||
t.status = res.StatusCode
|
||||
t.statusText = res.Status
|
||||
t.headers = res.Header
|
||||
t.body = d
|
||||
}
|
||||
}()
|
||||
|
||||
return otto.UndefinedValue()
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
1
vendor/fknsrs.biz/p/ottoext/fetch/js/.gitignore
vendored
Normal file
1
vendor/fknsrs.biz/p/ottoext/fetch/js/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/node_modules
|
359
vendor/fknsrs.biz/p/ottoext/fetch/js/bundle.js
vendored
Normal file
359
vendor/fknsrs.biz/p/ottoext/fetch/js/bundle.js
vendored
Normal file
@ -0,0 +1,359 @@
|
||||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId])
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ exports: {},
|
||||
/******/ id: moduleId,
|
||||
/******/ loaded: false
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.loaded = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/*!******************!*\
|
||||
!*** ./index.js ***!
|
||||
\******************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
__webpack_require__(/*! expose?fetch!./fetch */ 1);
|
||||
__webpack_require__(/*! expose?Headers!./headers */ 6);
|
||||
__webpack_require__(/*! expose?Request!./request */ 7);
|
||||
__webpack_require__(/*! expose?Response!./response */ 8);
|
||||
|
||||
/***/ },
|
||||
/* 1 */
|
||||
/*!******************************************!*\
|
||||
!*** ./~/expose-loader?fetch!./fetch.js ***!
|
||||
\******************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["fetch"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./fetch.js */ 2);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ },
|
||||
/* 2 */
|
||||
/*!*******************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./fetch.js ***!
|
||||
\*******************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
exports['default'] = fetch;
|
||||
var Request = __webpack_require__(/*! ./request */ 3);
|
||||
var Response = __webpack_require__(/*! ./response */ 5);
|
||||
|
||||
function fetch(input, init) {
|
||||
var req = new Request(input, init);
|
||||
var res = new Response();
|
||||
|
||||
return new Promise(function (resolve, reject) {
|
||||
return __private__fetch_execute(req, res, function (err) {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 3 */
|
||||
/*!*********************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./request.js ***!
|
||||
\*********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
var Headers = __webpack_require__(/*! ./headers */ 4);
|
||||
|
||||
var Request = function Request(input) {
|
||||
var _ref = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
|
||||
|
||||
var method = _ref.method;
|
||||
var headers = _ref.headers;
|
||||
var redirect = _ref.redirect;
|
||||
var body = _ref.body;
|
||||
|
||||
_classCallCheck(this, Request);
|
||||
|
||||
this.method = 'GET';
|
||||
this.headers = new Headers({});
|
||||
this.redirect = 'manual';
|
||||
this.body = null;
|
||||
|
||||
if (input instanceof Request) {
|
||||
this.url = input.url;
|
||||
this.method = input.method;
|
||||
this.headers = new Headers(input.headers);
|
||||
this.redirect = input.redirect;
|
||||
} else {
|
||||
this.url = input;
|
||||
}
|
||||
|
||||
if (method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
this.headers = new Headers(headers);
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
this.redirect = redirect;
|
||||
}
|
||||
|
||||
if (body) {
|
||||
this.body = body;
|
||||
}
|
||||
};
|
||||
|
||||
exports['default'] = Request;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 4 */
|
||||
/*!*********************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./headers.js ***!
|
||||
\*********************************************/
|
||||
/***/ function(module, exports) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
var Headers = (function () {
|
||||
function Headers(init) {
|
||||
var _this = this;
|
||||
|
||||
_classCallCheck(this, Headers);
|
||||
|
||||
this._headers = {};
|
||||
|
||||
if (init instanceof Headers) {
|
||||
init = init._headers;
|
||||
}
|
||||
|
||||
if (typeof init === 'object' && init !== null) {
|
||||
for (var k in init) {
|
||||
var v = init[k];
|
||||
if (!Array.isArray(v)) {
|
||||
v = [v];
|
||||
}
|
||||
|
||||
v.forEach(function (e) {
|
||||
return _this.append(k, e);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_createClass(Headers, [{
|
||||
key: 'append',
|
||||
value: function append(name, value) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
if (!Object.hasOwnProperty.call(this._headers, normalisedName)) {
|
||||
this._headers[normalisedName] = [];
|
||||
}
|
||||
|
||||
this._headers[normalisedName].push(value);
|
||||
}
|
||||
}, {
|
||||
key: 'delete',
|
||||
value: function _delete(name) {
|
||||
delete this._headers[Headers.normaliseName(name)];
|
||||
}
|
||||
}, {
|
||||
key: 'get',
|
||||
value: function get(name) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
if (this._headers[normalisedName]) {
|
||||
return this._headers[normalisedName][0];
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: 'getAll',
|
||||
value: function getAll(name) {
|
||||
return this._headers[Headers.normaliseName(name)] || [];
|
||||
}
|
||||
}, {
|
||||
key: 'has',
|
||||
value: function has(name) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
return Array.isArray(this._headers[normalisedName]);
|
||||
}
|
||||
}, {
|
||||
key: 'set',
|
||||
value: function set(name, value) {
|
||||
var normalisedName = Headers.normaliseName(name);
|
||||
|
||||
this._headers[normalisedName] = [value];
|
||||
}
|
||||
}], [{
|
||||
key: 'normaliseName',
|
||||
value: function normaliseName(name) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
}]);
|
||||
|
||||
return Headers;
|
||||
})();
|
||||
|
||||
exports['default'] = Headers;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 5 */
|
||||
/*!**********************************************!*\
|
||||
!*** ./~/babel-loader?stage=0!./response.js ***!
|
||||
\**********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
'use strict';
|
||||
|
||||
Object.defineProperty(exports, '__esModule', {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
|
||||
|
||||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
|
||||
|
||||
var Headers = __webpack_require__(/*! ./headers */ 4);
|
||||
|
||||
var Response = (function () {
|
||||
function Response(body) {
|
||||
var _ref = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1];
|
||||
|
||||
var _ref$status = _ref.status;
|
||||
var status = _ref$status === undefined ? 200 : _ref$status;
|
||||
var _ref$statusText = _ref.statusText;
|
||||
var statusText = _ref$statusText === undefined ? 'OK' : _ref$statusText;
|
||||
var _ref$headers = _ref.headers;
|
||||
var headers = _ref$headers === undefined ? {} : _ref$headers;
|
||||
|
||||
_classCallCheck(this, Response);
|
||||
|
||||
this.bodyUsed = true;
|
||||
this._body = null;
|
||||
|
||||
this.headers = new Headers(headers);
|
||||
this.ok = status >= 200 && status < 300;
|
||||
this.status = status;
|
||||
this.statusText = statusText;
|
||||
this.type = this.headers.get('content-type');
|
||||
}
|
||||
|
||||
_createClass(Response, [{
|
||||
key: 'text',
|
||||
value: function text() {
|
||||
var _this = this;
|
||||
|
||||
return new Promise(function (resolve) {
|
||||
return resolve(_this._body);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: 'json',
|
||||
value: function json() {
|
||||
return this.text().then(function (d) {
|
||||
return JSON.parse(d);
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
return Response;
|
||||
})();
|
||||
|
||||
exports['default'] = Response;
|
||||
module.exports = exports['default'];
|
||||
|
||||
/***/ },
|
||||
/* 6 */
|
||||
/*!**********************************************!*\
|
||||
!*** ./~/expose-loader?Headers!./headers.js ***!
|
||||
\**********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["Headers"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./headers.js */ 4);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ },
|
||||
/* 7 */
|
||||
/*!**********************************************!*\
|
||||
!*** ./~/expose-loader?Request!./request.js ***!
|
||||
\**********************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["Request"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./request.js */ 3);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ },
|
||||
/* 8 */
|
||||
/*!************************************************!*\
|
||||
!*** ./~/expose-loader?Response!./response.js ***!
|
||||
\************************************************/
|
||||
/***/ function(module, exports, __webpack_require__) {
|
||||
|
||||
/* WEBPACK VAR INJECTION */(function(global) {module.exports = global["Response"] = __webpack_require__(/*! -!./~/babel-loader?stage=0!./response.js */ 5);
|
||||
/* WEBPACK VAR INJECTION */}.call(exports, (function() { return this; }())))
|
||||
|
||||
/***/ }
|
||||
/******/ ]);
|
||||
//# sourceMappingURL=bundle.js.map
|
1
vendor/fknsrs.biz/p/ottoext/fetch/js/bundle.js.map
vendored
Normal file
1
vendor/fknsrs.biz/p/ottoext/fetch/js/bundle.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
17
vendor/fknsrs.biz/p/ottoext/fetch/js/fetch.js
vendored
Normal file
17
vendor/fknsrs.biz/p/ottoext/fetch/js/fetch.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
const Request = require('./request');
|
||||
const Response = require('./response');
|
||||
|
||||
export default function fetch(input, init) {
|
||||
const req = new Request(input, init);
|
||||
const res = new Response();
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
return __private__fetch_execute(req, res, err => {
|
||||
if (err) {
|
||||
return reject(err);
|
||||
}
|
||||
|
||||
return resolve(res);
|
||||
});
|
||||
});
|
||||
}
|
62
vendor/fknsrs.biz/p/ottoext/fetch/js/headers.js
vendored
Normal file
62
vendor/fknsrs.biz/p/ottoext/fetch/js/headers.js
vendored
Normal file
@ -0,0 +1,62 @@
|
||||
export default class Headers {
|
||||
_headers = {};
|
||||
|
||||
constructor(init) {
|
||||
if (init instanceof Headers) {
|
||||
init = init._headers;
|
||||
}
|
||||
|
||||
if (typeof init === 'object' && init !== null) {
|
||||
for (var k in init) {
|
||||
var v = init[k];
|
||||
if (!Array.isArray(v)) {
|
||||
v = [v];
|
||||
}
|
||||
|
||||
v.forEach(e => this.append(k, e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
append(name, value) {
|
||||
const normalisedName = Headers.normaliseName(name);
|
||||
|
||||
if (!Object.hasOwnProperty.call(this._headers, normalisedName)) {
|
||||
this._headers[normalisedName] = [];
|
||||
}
|
||||
|
||||
this._headers[normalisedName].push(value);
|
||||
}
|
||||
|
||||
delete(name) {
|
||||
delete this._headers[Headers.normaliseName(name)];
|
||||
}
|
||||
|
||||
get(name) {
|
||||
const normalisedName = Headers.normaliseName(name);
|
||||
|
||||
if (this._headers[normalisedName]) {
|
||||
return this._headers[normalisedName][0];
|
||||
}
|
||||
}
|
||||
|
||||
getAll(name) {
|
||||
return this._headers[Headers.normaliseName(name)] || [];
|
||||
}
|
||||
|
||||
has(name) {
|
||||
const normalisedName = Headers.normaliseName(name);
|
||||
|
||||
return Array.isArray(this._headers[normalisedName]);
|
||||
}
|
||||
|
||||
set(name, value) {
|
||||
const normalisedName = Headers.normaliseName(name);
|
||||
|
||||
this._headers[normalisedName] = [value];
|
||||
}
|
||||
|
||||
static normaliseName(name) {
|
||||
return name.toLowerCase();
|
||||
}
|
||||
}
|
4
vendor/fknsrs.biz/p/ottoext/fetch/js/index.js
vendored
Normal file
4
vendor/fknsrs.biz/p/ottoext/fetch/js/index.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
require('expose?fetch!./fetch');
|
||||
require('expose?Headers!./headers');
|
||||
require('expose?Request!./request');
|
||||
require('expose?Response!./response');
|
13
vendor/fknsrs.biz/p/ottoext/fetch/js/package.json
vendored
Normal file
13
vendor/fknsrs.biz/p/ottoext/fetch/js/package.json
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"scripts": {
|
||||
"bundle": "webpack -v -d",
|
||||
"watch": "webpack -v -w"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^5.8.25",
|
||||
"babel-loader": "^5.3.2",
|
||||
"babel-runtime": "^5.8.25",
|
||||
"expose-loader": "^0.7.0",
|
||||
"webpack": "^1.12.2"
|
||||
}
|
||||
}
|
35
vendor/fknsrs.biz/p/ottoext/fetch/js/request.js
vendored
Normal file
35
vendor/fknsrs.biz/p/ottoext/fetch/js/request.js
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
const Headers = require('./headers');
|
||||
|
||||
export default class Request {
|
||||
constructor(input, {method, headers, redirect, body}={}) {
|
||||
this.method = 'GET';
|
||||
this.headers = new Headers({});
|
||||
this.redirect = 'manual';
|
||||
this.body = null;
|
||||
|
||||
if (input instanceof Request) {
|
||||
this.url = input.url;
|
||||
this.method = input.method;
|
||||
this.headers = new Headers(input.headers);
|
||||
this.redirect = input.redirect;
|
||||
} else {
|
||||
this.url = input;
|
||||
}
|
||||
|
||||
if (method) {
|
||||
this.method = method;
|
||||
}
|
||||
|
||||
if (headers) {
|
||||
this.headers = new Headers(headers);
|
||||
}
|
||||
|
||||
if (redirect) {
|
||||
this.redirect = redirect;
|
||||
}
|
||||
|
||||
if (body) {
|
||||
this.body = body;
|
||||
}
|
||||
}
|
||||
}
|
23
vendor/fknsrs.biz/p/ottoext/fetch/js/response.js
vendored
Normal file
23
vendor/fknsrs.biz/p/ottoext/fetch/js/response.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
const Headers = require('./headers');
|
||||
|
||||
export default class Response {
|
||||
bodyUsed = true;
|
||||
|
||||
_body = null;
|
||||
|
||||
constructor(body, {status=200, statusText='OK', headers={}}={}) {
|
||||
this.headers = new Headers(headers);
|
||||
this.ok = status >= 200 && status < 300;
|
||||
this.status = status;
|
||||
this.statusText = statusText;
|
||||
this.type = this.headers.get('content-type');
|
||||
}
|
||||
|
||||
text() {
|
||||
return new Promise(resolve => resolve(this._body));
|
||||
}
|
||||
|
||||
json() {
|
||||
return this.text().then(d => JSON.parse(d));
|
||||
}
|
||||
}
|
23
vendor/fknsrs.biz/p/ottoext/fetch/js/webpack.config.js
vendored
Normal file
23
vendor/fknsrs.biz/p/ottoext/fetch/js/webpack.config.js
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
module.exports = {
|
||||
devtool: 'source-map',
|
||||
entry: './index',
|
||||
output: {
|
||||
filename: 'bundle.js',
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['', '.js'],
|
||||
},
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: 'babel?stage=0',
|
||||
},
|
||||
],
|
||||
},
|
||||
node: {
|
||||
console: false,
|
||||
process: false,
|
||||
setImmediate: false,
|
||||
},
|
||||
};
|
189
vendor/fknsrs.biz/p/ottoext/loop/loop.go
vendored
Normal file
189
vendor/fknsrs.biz/p/ottoext/loop/loop.go
vendored
Normal file
@ -0,0 +1,189 @@
|
||||
package loop // import "fknsrs.biz/p/ottoext/loop"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
func formatTask(t Task) string {
|
||||
if t == nil {
|
||||
return "<nil>"
|
||||
}
|
||||
|
||||
return fmt.Sprintf("<%T> %d", t, t.GetID())
|
||||
}
|
||||
|
||||
// Task represents something that the event loop can schedule and run.
|
||||
//
|
||||
// Task describes two operations that will almost always be boilerplate,
|
||||
// SetID and GetID. They exist so that the event loop can identify tasks
|
||||
// after they're added.
|
||||
//
|
||||
// Execute is called when a task has been pulled from the "ready" queue.
|
||||
//
|
||||
// Cancel is called when a task is removed from the loop without being
|
||||
// finalised.
|
||||
type Task interface {
|
||||
SetID(id int64)
|
||||
GetID() int64
|
||||
Execute(vm *otto.Otto, l *Loop) error
|
||||
Cancel()
|
||||
}
|
||||
|
||||
// Loop encapsulates the event loop's state. This includes the vm on which the
|
||||
// loop operates, a monotonically incrementing event id, a map of tasks that
|
||||
// aren't ready yet, keyed by their ID, and a channel of tasks that are ready
|
||||
// to finalise on the VM. The channel holding the tasks pending finalising can
|
||||
// be buffered or unbuffered.
|
||||
type Loop struct {
|
||||
vm *otto.Otto
|
||||
id int64
|
||||
lock sync.RWMutex
|
||||
tasks map[int64]Task
|
||||
ready chan Task
|
||||
closed bool
|
||||
}
|
||||
|
||||
// New creates a new Loop with an unbuffered ready queue on a specific VM.
|
||||
func New(vm *otto.Otto) *Loop {
|
||||
return NewWithBacklog(vm, 0)
|
||||
}
|
||||
|
||||
// NewWithBacklog creates a new Loop on a specific VM, giving it a buffered
|
||||
// queue, the capacity of which being specified by the backlog argument.
|
||||
func NewWithBacklog(vm *otto.Otto, backlog int) *Loop {
|
||||
return &Loop{
|
||||
vm: vm,
|
||||
tasks: make(map[int64]Task),
|
||||
ready: make(chan Task, backlog),
|
||||
}
|
||||
}
|
||||
|
||||
// VM gets the JavaScript interpreter associated with the loop. This will be
|
||||
// some kind of Otto object, but it's wrapped in an interface so the
|
||||
// `ottoext` library can work with forks/extensions of otto.
|
||||
func (l *Loop) VM() *otto.Otto {
|
||||
return l.vm
|
||||
}
|
||||
|
||||
// Add puts a task into the loop. This signals to the loop that this task is
|
||||
// doing something outside of the JavaScript environment, and that at some
|
||||
// point, it will become ready for finalising.
|
||||
func (l *Loop) Add(t Task) {
|
||||
l.lock.Lock()
|
||||
t.SetID(atomic.AddInt64(&l.id, 1))
|
||||
l.tasks[t.GetID()] = t
|
||||
l.lock.Unlock()
|
||||
}
|
||||
|
||||
// Remove takes a task out of the loop. This should not be called if a task
|
||||
// has already become ready for finalising. Warranty void if constraint is
|
||||
// broken.
|
||||
func (l *Loop) Remove(t Task) {
|
||||
l.remove(t)
|
||||
go l.Ready(nil)
|
||||
}
|
||||
|
||||
func (l *Loop) remove(t Task) {
|
||||
l.removeByID(t.GetID())
|
||||
}
|
||||
|
||||
func (l *Loop) removeByID(id int64) {
|
||||
l.lock.Lock()
|
||||
delete(l.tasks, id)
|
||||
l.lock.Unlock()
|
||||
}
|
||||
|
||||
// Ready signals to the loop that a task is ready to be finalised. This might
|
||||
// block if the "ready channel" in the loop is at capacity.
|
||||
func (l *Loop) Ready(t Task) {
|
||||
if l.closed {
|
||||
return
|
||||
}
|
||||
|
||||
l.ready <- t
|
||||
}
|
||||
|
||||
// EvalAndRun is a combination of Eval and Run. Creatively named.
|
||||
func (l *Loop) EvalAndRun(s interface{}) error {
|
||||
if err := l.Eval(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return l.Run()
|
||||
}
|
||||
|
||||
// Eval executes some code in the VM associated with the loop and returns an
|
||||
// error if that execution fails.
|
||||
func (l *Loop) Eval(s interface{}) error {
|
||||
if _, err := l.vm.Run(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (l *Loop) processTask(t Task) error {
|
||||
id := t.GetID()
|
||||
|
||||
if err := t.Execute(l.vm, l); err != nil {
|
||||
l.lock.RLock()
|
||||
for _, t := range l.tasks {
|
||||
t.Cancel()
|
||||
}
|
||||
l.lock.RUnlock()
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
l.removeByID(id)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Run handles the task scheduling and finalisation. It will block until
|
||||
// there's no work left to do, or an error occurs.
|
||||
func (l *Loop) Run() error {
|
||||
for {
|
||||
l.lock.Lock()
|
||||
if len(l.tasks) == 0 {
|
||||
// prevent any more tasks entering the ready channel
|
||||
l.closed = true
|
||||
|
||||
l.lock.Unlock()
|
||||
|
||||
break
|
||||
}
|
||||
l.lock.Unlock()
|
||||
|
||||
t := <-l.ready
|
||||
|
||||
if t != nil {
|
||||
if err := l.processTask(t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// drain ready channel of any existing tasks
|
||||
outer:
|
||||
for {
|
||||
select {
|
||||
case t := <-l.ready:
|
||||
if t != nil {
|
||||
if err := l.processTask(t); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
break outer
|
||||
}
|
||||
}
|
||||
|
||||
close(l.ready)
|
||||
|
||||
return nil
|
||||
}
|
126
vendor/fknsrs.biz/p/ottoext/loop/looptask/tasks.go
vendored
Normal file
126
vendor/fknsrs.biz/p/ottoext/loop/looptask/tasks.go
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
package looptask
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
// IdleTask is designed to sit in a loop and keep it active, without doing any
|
||||
// work.
|
||||
type IdleTask struct {
|
||||
ID int64
|
||||
}
|
||||
|
||||
// NewIdleTask creates a new IdleTask object.
|
||||
func NewIdleTask() *IdleTask {
|
||||
return &IdleTask{}
|
||||
}
|
||||
|
||||
// SetID sets the ID of an IdleTask.
|
||||
func (i *IdleTask) SetID(ID int64) { i.ID = ID }
|
||||
|
||||
// GetID gets the ID of an IdleTask.
|
||||
func (i IdleTask) GetID() int64 { return i.ID }
|
||||
|
||||
// Cancel does nothing on an IdleTask, as there's nothing to clean up.
|
||||
func (i IdleTask) Cancel() {}
|
||||
|
||||
// Execute always returns an error for an IdleTask, as it should never
|
||||
// actually be run.
|
||||
func (i IdleTask) Execute(vm *otto.Otto, l *loop.Loop) error {
|
||||
return errors.New("Idle task should never execute")
|
||||
}
|
||||
|
||||
// EvalTask schedules running an otto.Script. It has two channels for
|
||||
// communicating the result of the execution.
|
||||
type EvalTask struct {
|
||||
ID int64
|
||||
Script interface{}
|
||||
Value chan otto.Value
|
||||
Error chan error
|
||||
SoftError bool
|
||||
}
|
||||
|
||||
// NewEvalTask creates a new EvalTask for a given otto.Script, creating two
|
||||
// buffered channels for the response.
|
||||
func NewEvalTask(s interface{}) *EvalTask {
|
||||
return &EvalTask{
|
||||
Script: s,
|
||||
Value: make(chan otto.Value, 1),
|
||||
Error: make(chan error, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// SetID sets the ID of an EvalTask.
|
||||
func (e *EvalTask) SetID(ID int64) { e.ID = ID }
|
||||
|
||||
// GetID gets the ID of an EvalTask.
|
||||
func (e EvalTask) GetID() int64 { return e.ID }
|
||||
|
||||
// Cancel does nothing for an EvalTask, as there's nothing to clean up.
|
||||
func (e EvalTask) Cancel() {}
|
||||
|
||||
// Execute runs the EvalTask's otto.Script in the vm provided, pushing the
|
||||
// resultant return value and error (or nil) into the associated channels.
|
||||
// If the execution results in an error, it will return that error.
|
||||
func (e EvalTask) Execute(vm *otto.Otto, l *loop.Loop) error {
|
||||
v, err := vm.Run(e.Script)
|
||||
e.Value <- v
|
||||
e.Error <- err
|
||||
|
||||
if e.SoftError {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// CallTask schedules an otto.Value (which should be a function) to be called
|
||||
// with a specific set of arguments. It has two channels for communicating the
|
||||
// result of the call.
|
||||
type CallTask struct {
|
||||
ID int64
|
||||
Function otto.Value
|
||||
Args []interface{}
|
||||
Value chan otto.Value
|
||||
Error chan error
|
||||
SoftError bool
|
||||
}
|
||||
|
||||
// NewCallTask creates a new CallTask object for a given otto.Value (which
|
||||
// should be a function) and set of arguments, creating two buffered channels
|
||||
// for the response.
|
||||
func NewCallTask(fn otto.Value, args ...interface{}) *CallTask {
|
||||
return &CallTask{
|
||||
Function: fn,
|
||||
Args: args,
|
||||
Value: make(chan otto.Value, 1),
|
||||
Error: make(chan error, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// SetID sets the ID of a CallTask.
|
||||
func (c *CallTask) SetID(ID int64) { c.ID = ID }
|
||||
|
||||
// GetID gets the ID of a CallTask.
|
||||
func (c CallTask) GetID() int64 { return c.ID }
|
||||
|
||||
// Cancel does nothing for a CallTask, as there's nothing to clean up.
|
||||
func (c CallTask) Cancel() {}
|
||||
|
||||
// Execute calls the associated function (not necessarily in the given vm),
|
||||
// pushing the resultant return value and error (or nil) into the associated
|
||||
// channels. If the call results in an error, it will return that error.
|
||||
func (c CallTask) Execute(vm *otto.Otto, l *loop.Loop) error {
|
||||
v, err := c.Function.Call(otto.NullValue(), c.Args...)
|
||||
c.Value <- v
|
||||
c.Error <- err
|
||||
|
||||
if c.SoftError {
|
||||
return nil
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
2
vendor/fknsrs.biz/p/ottoext/main.go
vendored
Normal file
2
vendor/fknsrs.biz/p/ottoext/main.go
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Package ottoext contains some extensions for the otto JavaScript interpreter.
|
||||
package ottoext // import "fknsrs.biz/p/ottoext"
|
27
vendor/fknsrs.biz/p/ottoext/process/process.go
vendored
Normal file
27
vendor/fknsrs.biz/p/ottoext/process/process.go
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
package process // import "fknsrs.biz/p/ottoext/process"
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
func Define(vm *otto.Otto, argv []string) error {
|
||||
if v, err := vm.Get("process"); err != nil {
|
||||
return err
|
||||
} else if !v.IsUndefined() {
|
||||
return nil
|
||||
}
|
||||
|
||||
env := make(map[string]string)
|
||||
for _, e := range os.Environ() {
|
||||
a := strings.SplitN(e, "=", 2)
|
||||
env[a[0]] = a[1]
|
||||
}
|
||||
|
||||
return vm.Set("process", map[string]interface{}{
|
||||
"env": env,
|
||||
"argv": argv,
|
||||
})
|
||||
}
|
5
vendor/fknsrs.biz/p/ottoext/promise/Makefile
vendored
Normal file
5
vendor/fknsrs.biz/p/ottoext/promise/Makefile
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
dist-promise.rice-box.go: dist-promise/bundle.js
|
||||
rice embed-go
|
||||
|
||||
clean:
|
||||
rm -rf dist-promise.rice-box.go
|
315
vendor/fknsrs.biz/p/ottoext/promise/dist-promise/bundle.js
vendored
Normal file
315
vendor/fknsrs.biz/p/ottoext/promise/dist-promise/bundle.js
vendored
Normal file
@ -0,0 +1,315 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function Promise(resolver) {
|
||||
if (typeof resolver !== 'function' && typeof resolver !== 'undefined') {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
if (typeof this !== 'object' || (this && this.then)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
// states
|
||||
// 0: pending
|
||||
// 1: resolving
|
||||
// 2: rejecting
|
||||
// 3: resolved
|
||||
// 4: rejected
|
||||
var state = 0;
|
||||
var val = 0;
|
||||
var next = [];
|
||||
var fn = null;
|
||||
var er = null;
|
||||
|
||||
this.promise = this;
|
||||
|
||||
this.resolve = function resolve(v) {
|
||||
fn = self.fn;
|
||||
er = self.er;
|
||||
|
||||
if (!state) {
|
||||
val = v;
|
||||
state = 1;
|
||||
|
||||
setImmediate(fire);
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
this.reject = function reject(v) {
|
||||
fn = self.fn;
|
||||
er = self.er;
|
||||
|
||||
if (!state) {
|
||||
val = v;
|
||||
state = 2;
|
||||
|
||||
setImmediate(fire);
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
this._p = 1;
|
||||
|
||||
this.then = function then(_fn, _er) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
var p = new Promise();
|
||||
|
||||
p.fn = _fn;
|
||||
p.er = _er;
|
||||
|
||||
switch (state) {
|
||||
case 3:
|
||||
p.resolve(val);
|
||||
break;
|
||||
case 4:
|
||||
p.reject(val);
|
||||
break;
|
||||
default:
|
||||
next.push(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
this.catch = function _catch(_er) {
|
||||
return self.then(null, _er);
|
||||
};
|
||||
|
||||
var finish = function finish(type) {
|
||||
state = type || 4;
|
||||
|
||||
next.map(function(p) {
|
||||
state === 3 && p.resolve(val) || p.reject(val);
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
if (typeof resolver === 'function') {
|
||||
resolver(this.resolve, this.reject);
|
||||
}
|
||||
} catch (e) {
|
||||
this.reject(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
// ref: reference to 'then' function
|
||||
// cb, ec, cn: successCallback, failureCallback, notThennableCallback
|
||||
function thennable (ref, cb, ec, cn) {
|
||||
if ((typeof val === 'object' || typeof val === 'function') && typeof ref === 'function') {
|
||||
try {
|
||||
// cnt protects against abuse calls from spec checker
|
||||
var cnt = 0;
|
||||
ref.call(val, function(v) {
|
||||
if (cnt++) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = v;
|
||||
|
||||
cb();
|
||||
}, function(v) {
|
||||
if (cnt++) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = v;
|
||||
|
||||
ec();
|
||||
})
|
||||
} catch (e) {
|
||||
val = e;
|
||||
|
||||
ec();
|
||||
}
|
||||
} else {
|
||||
cn();
|
||||
}
|
||||
}
|
||||
|
||||
function fire() {
|
||||
// check if it's a thenable
|
||||
var ref;
|
||||
|
||||
try {
|
||||
ref = val && val.then;
|
||||
} catch (e) {
|
||||
val = e;
|
||||
state = 2;
|
||||
|
||||
return fire();
|
||||
}
|
||||
|
||||
thennable(ref, function() {
|
||||
state = 1;
|
||||
|
||||
fire();
|
||||
}, function() {
|
||||
state = 2;
|
||||
|
||||
fire();
|
||||
}, function() {
|
||||
try {
|
||||
if (state === 1 && typeof fn === 'function') {
|
||||
val = fn(val);
|
||||
} else if (state === 2 && typeof er === 'function') {
|
||||
val = er(val);
|
||||
|
||||
state = 1;
|
||||
}
|
||||
} catch (e) {
|
||||
val = e;
|
||||
|
||||
return finish();
|
||||
}
|
||||
|
||||
if (val === self) {
|
||||
val = TypeError();
|
||||
|
||||
finish();
|
||||
} else {
|
||||
thennable(ref, function() {
|
||||
finish(3);
|
||||
}, finish, function() {
|
||||
finish(state === 1 && 3);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Promise.resolve = function resolve(value) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
if (value instanceof Promise) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
resolve(value);
|
||||
});
|
||||
};
|
||||
|
||||
Promise.reject = function reject(value) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
reject(value);
|
||||
});
|
||||
};
|
||||
|
||||
Promise.all = function all(arr) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
if (!(arr instanceof Array)) {
|
||||
return Promise.reject(TypeError());
|
||||
}
|
||||
|
||||
var p = new Promise();
|
||||
|
||||
function done(e, v) {
|
||||
if (v) {
|
||||
return p.resolve(v);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
return p.reject(e);
|
||||
}
|
||||
|
||||
var unresolved = arr.reduce(function(cnt, v) {
|
||||
if (v && v.then) {
|
||||
return cnt + 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}, 0);
|
||||
|
||||
if (unresolved === 0) {
|
||||
p.resolve(arr);
|
||||
}
|
||||
|
||||
arr.map(function(v, i) {
|
||||
if (v && v.then) {
|
||||
v.then(function(r) {
|
||||
arr[i] = r;
|
||||
done();
|
||||
return r;
|
||||
}, done);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
Promise.race = function race(arr) {
|
||||
if (!(this._p === 1)) {
|
||||
throw TypeError();
|
||||
}
|
||||
|
||||
if (!(arr instanceof Array)) {
|
||||
return Promise.reject(TypeError());
|
||||
}
|
||||
|
||||
if (arr.length === 0) {
|
||||
return new Promise();
|
||||
}
|
||||
|
||||
var p = new Promise();
|
||||
|
||||
function done(e, v) {
|
||||
if (v) {
|
||||
return p.resolve(v);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
return p.reject(e);
|
||||
}
|
||||
|
||||
var unresolved = arr.reduce(function(cnt, v) {
|
||||
if (v && v.then) {
|
||||
return cnt + 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}, 0);
|
||||
|
||||
if (unresolved === 0) {
|
||||
p.resolve(arr);
|
||||
}
|
||||
|
||||
arr.map(function(v, i) {
|
||||
if (v && v.then) {
|
||||
v.then(function(r) {
|
||||
done(null, r);
|
||||
}, done);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Promise._p = 1;
|
318
vendor/fknsrs.biz/p/ottoext/promise/js.go
vendored
Normal file
318
vendor/fknsrs.biz/p/ottoext/promise/js.go
vendored
Normal file
@ -0,0 +1,318 @@
|
||||
package promise
|
||||
|
||||
const src = `'use strict';
|
||||
|
||||
/**
|
||||
* @constructor
|
||||
*/
|
||||
function Promise(resolver) {
|
||||
if (typeof resolver !== 'function' && typeof resolver !== 'undefined') {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
if (typeof this !== 'object' || (this && this.then)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
// states
|
||||
// 0: pending
|
||||
// 1: resolving
|
||||
// 2: rejecting
|
||||
// 3: resolved
|
||||
// 4: rejected
|
||||
var state = 0;
|
||||
var val = 0;
|
||||
var next = [];
|
||||
var fn = null;
|
||||
var er = null;
|
||||
|
||||
this.promise = this;
|
||||
|
||||
this.resolve = function resolve(v) {
|
||||
fn = self.fn;
|
||||
er = self.er;
|
||||
|
||||
if (!state) {
|
||||
val = v;
|
||||
state = 1;
|
||||
|
||||
setImmediate(fire);
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
this.reject = function reject(v) {
|
||||
fn = self.fn;
|
||||
er = self.er;
|
||||
|
||||
if (!state) {
|
||||
val = v;
|
||||
state = 2;
|
||||
|
||||
setImmediate(fire);
|
||||
}
|
||||
|
||||
return self;
|
||||
};
|
||||
|
||||
this._p = 1;
|
||||
|
||||
this.then = function then(_fn, _er) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
var p = new Promise();
|
||||
|
||||
p.fn = _fn;
|
||||
p.er = _er;
|
||||
|
||||
switch (state) {
|
||||
case 3:
|
||||
p.resolve(val);
|
||||
break;
|
||||
case 4:
|
||||
p.reject(val);
|
||||
break;
|
||||
default:
|
||||
next.push(p);
|
||||
break;
|
||||
}
|
||||
|
||||
return p;
|
||||
};
|
||||
|
||||
this.catch = function _catch(_er) {
|
||||
return self.then(null, _er);
|
||||
};
|
||||
|
||||
var finish = function finish(type) {
|
||||
state = type || 4;
|
||||
|
||||
next.map(function(p) {
|
||||
state === 3 && p.resolve(val) || p.reject(val);
|
||||
});
|
||||
};
|
||||
|
||||
try {
|
||||
if (typeof resolver === 'function') {
|
||||
resolver(this.resolve, this.reject);
|
||||
}
|
||||
} catch (e) {
|
||||
this.reject(e);
|
||||
}
|
||||
|
||||
return this;
|
||||
|
||||
// ref: reference to 'then' function
|
||||
// cb, ec, cn: successCallback, failureCallback, notThennableCallback
|
||||
function thennable (ref, cb, ec, cn) {
|
||||
if ((typeof val === 'object' || typeof val === 'function') && typeof ref === 'function') {
|
||||
try {
|
||||
// cnt protects against abuse calls from spec checker
|
||||
var cnt = 0;
|
||||
ref.call(val, function(v) {
|
||||
if (cnt++) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = v;
|
||||
|
||||
cb();
|
||||
}, function(v) {
|
||||
if (cnt++) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = v;
|
||||
|
||||
ec();
|
||||
})
|
||||
} catch (e) {
|
||||
val = e;
|
||||
|
||||
ec();
|
||||
}
|
||||
} else {
|
||||
cn();
|
||||
}
|
||||
}
|
||||
|
||||
function fire() {
|
||||
// check if it's a thenable
|
||||
var ref;
|
||||
|
||||
try {
|
||||
ref = val && val.then;
|
||||
} catch (e) {
|
||||
val = e;
|
||||
state = 2;
|
||||
|
||||
return fire();
|
||||
}
|
||||
|
||||
thennable(ref, function() {
|
||||
state = 1;
|
||||
|
||||
fire();
|
||||
}, function() {
|
||||
state = 2;
|
||||
|
||||
fire();
|
||||
}, function() {
|
||||
try {
|
||||
if (state === 1 && typeof fn === 'function') {
|
||||
val = fn(val);
|
||||
} else if (state === 2 && typeof er === 'function') {
|
||||
val = er(val);
|
||||
|
||||
state = 1;
|
||||
}
|
||||
} catch (e) {
|
||||
val = e;
|
||||
|
||||
return finish();
|
||||
}
|
||||
|
||||
if (val === self) {
|
||||
val = TypeError();
|
||||
|
||||
finish();
|
||||
} else {
|
||||
thennable(ref, function() {
|
||||
finish(3);
|
||||
}, finish, function() {
|
||||
finish(state === 1 && 3);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Promise.resolve = function resolve(value) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
if (value instanceof Promise) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return new Promise(function(resolve) {
|
||||
resolve(value);
|
||||
});
|
||||
};
|
||||
|
||||
Promise.reject = function reject(value) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
return new Promise(function(resolve, reject) {
|
||||
reject(value);
|
||||
});
|
||||
};
|
||||
|
||||
Promise.all = function all(arr) {
|
||||
if (!(this._p === 1)) {
|
||||
throw new TypeError();
|
||||
}
|
||||
|
||||
if (!(arr instanceof Array)) {
|
||||
return Promise.reject(TypeError());
|
||||
}
|
||||
|
||||
var p = new Promise();
|
||||
|
||||
function done(e, v) {
|
||||
if (v) {
|
||||
return p.resolve(v);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
return p.reject(e);
|
||||
}
|
||||
|
||||
var unresolved = arr.reduce(function(cnt, v) {
|
||||
if (v && v.then) {
|
||||
return cnt + 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}, 0);
|
||||
|
||||
if (unresolved === 0) {
|
||||
p.resolve(arr);
|
||||
}
|
||||
|
||||
arr.map(function(v, i) {
|
||||
if (v && v.then) {
|
||||
v.then(function(r) {
|
||||
arr[i] = r;
|
||||
done();
|
||||
return r;
|
||||
}, done);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Promise.race = function race(arr) {
|
||||
if (!(this._p === 1)) {
|
||||
throw TypeError();
|
||||
}
|
||||
|
||||
if (!(arr instanceof Array)) {
|
||||
return Promise.reject(TypeError());
|
||||
}
|
||||
|
||||
if (arr.length === 0) {
|
||||
return new Promise();
|
||||
}
|
||||
|
||||
var p = new Promise();
|
||||
|
||||
function done(e, v) {
|
||||
if (v) {
|
||||
return p.resolve(v);
|
||||
}
|
||||
|
||||
if (e) {
|
||||
return p.reject(e);
|
||||
}
|
||||
|
||||
var unresolved = arr.reduce(function(cnt, v) {
|
||||
if (v && v.then) {
|
||||
return cnt + 1;
|
||||
}
|
||||
|
||||
return cnt;
|
||||
}, 0);
|
||||
|
||||
if (unresolved === 0) {
|
||||
p.resolve(arr);
|
||||
}
|
||||
|
||||
arr.map(function(v, i) {
|
||||
if (v && v.then) {
|
||||
v.then(function(r) {
|
||||
done(null, r);
|
||||
}, done);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
done();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
Promise._p = 1;
|
||||
`
|
31
vendor/fknsrs.biz/p/ottoext/promise/promise.go
vendored
Normal file
31
vendor/fknsrs.biz/p/ottoext/promise/promise.go
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
package promise // import "fknsrs.biz/p/ottoext/promise"
|
||||
|
||||
import (
|
||||
"github.com/robertkrimen/otto"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
"fknsrs.biz/p/ottoext/timers"
|
||||
)
|
||||
|
||||
func Define(vm *otto.Otto, l *loop.Loop) error {
|
||||
if v, err := vm.Get("Promise"); err != nil {
|
||||
return err
|
||||
} else if !v.IsUndefined() {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := timers.Define(vm, l); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s, err := vm.Compile("promise-bundle.js", src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := vm.Run(s); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
236
vendor/fknsrs.biz/p/ottoext/repl/print.go
vendored
Normal file
236
vendor/fknsrs.biz/p/ottoext/repl/print.go
vendored
Normal file
@ -0,0 +1,236 @@
|
||||
package repl
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
)
|
||||
|
||||
func seenWith(seen map[otto.Value]bool, v otto.Value) map[otto.Value]bool {
|
||||
r := make(map[otto.Value]bool)
|
||||
for k, v := range seen {
|
||||
r[k] = v
|
||||
}
|
||||
|
||||
r[v] = true
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func format(v otto.Value, width, indent, limit int) (string, error) {
|
||||
return formatIndent(v, width, indent, limit, 0, 0, make(map[otto.Value]bool))
|
||||
}
|
||||
|
||||
func formatIndent(v otto.Value, width, indent, limit, level, additional int, seen map[otto.Value]bool) (string, error) {
|
||||
if limit == 0 {
|
||||
return "...", nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.IsBoolean(), v.IsNull(), v.IsNumber(), v.IsUndefined():
|
||||
return v.String(), nil
|
||||
case v.IsString():
|
||||
return fmt.Sprintf("%q", v.String()), nil
|
||||
case v.IsFunction():
|
||||
n, err := v.Object().Get("name")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n.IsUndefined() {
|
||||
return "function", nil
|
||||
}
|
||||
return fmt.Sprintf("function %s", n.String()), nil
|
||||
case v.IsObject():
|
||||
if d, err := formatOneLine(v, limit, seen); err != nil {
|
||||
return "", err
|
||||
} else if level*indent+additional+len(d) <= width {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
switch v.Class() {
|
||||
case "Array":
|
||||
return formatArray(v, width, indent, limit, level, seen)
|
||||
default:
|
||||
return formatObject(v, width, indent, limit, level, seen)
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("couldn't format type %s", v.Class())
|
||||
}
|
||||
}
|
||||
|
||||
func formatArray(v otto.Value, width, indent, limit, level int, seen map[otto.Value]bool) (string, error) {
|
||||
if seen[v] {
|
||||
return strings.Repeat(" ", level*indent) + "[circular]", nil
|
||||
}
|
||||
|
||||
o := v.Object()
|
||||
|
||||
lv, err := o.Get("length")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
li, err := lv.Export()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
l, ok := li.(uint32)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("length property must be a number; was %T", li)
|
||||
}
|
||||
|
||||
bits := []string{"["}
|
||||
|
||||
for i := 0; i < int(l); i++ {
|
||||
e, err := o.Get(fmt.Sprintf("%d", i))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
d, err := formatIndent(e, width, indent, limit-1, level+1, 0, seenWith(seen, v))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bits = append(bits, strings.Repeat(" ", (level+1)*indent)+d+",")
|
||||
}
|
||||
|
||||
bits = append(bits, strings.Repeat(" ", level*indent)+"]")
|
||||
|
||||
return strings.Join(bits, "\n"), nil
|
||||
}
|
||||
|
||||
func formatObject(v otto.Value, width, indent, limit, level int, seen map[otto.Value]bool) (string, error) {
|
||||
if seen[v] {
|
||||
return strings.Repeat(" ", level*indent) + "[circular]", nil
|
||||
}
|
||||
|
||||
o := v.Object()
|
||||
|
||||
bits := []string{"{"}
|
||||
|
||||
keys := o.Keys()
|
||||
|
||||
for i, k := range keys {
|
||||
e, err := o.Get(k)
|
||||
|
||||
d, err := formatIndent(e, width, indent, limit-1, level+1, len(k)+2, seenWith(seen, v))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bits = append(bits, strings.Repeat(" ", (level+1)*indent)+k+": "+d+",")
|
||||
|
||||
i++
|
||||
}
|
||||
|
||||
bits = append(bits, strings.Repeat(" ", level*indent)+"}")
|
||||
|
||||
return strings.Join(bits, "\n"), nil
|
||||
}
|
||||
|
||||
func formatOneLine(v otto.Value, limit int, seen map[otto.Value]bool) (string, error) {
|
||||
if limit == 0 {
|
||||
return "...", nil
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.IsBoolean(), v.IsNull(), v.IsNumber(), v.IsUndefined():
|
||||
return v.String(), nil
|
||||
case v.IsString():
|
||||
return fmt.Sprintf("%q", v.String()), nil
|
||||
case v.IsFunction():
|
||||
n, err := v.Object().Get("name")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if n.IsUndefined() {
|
||||
return "function", nil
|
||||
}
|
||||
return fmt.Sprintf("function %s", n.String()), nil
|
||||
case v.IsObject():
|
||||
switch v.Class() {
|
||||
case "Array":
|
||||
return formatArrayOneLine(v, limit, seen)
|
||||
default:
|
||||
return formatObjectOneLine(v, limit, seen)
|
||||
}
|
||||
default:
|
||||
return "", fmt.Errorf("couldn't format type %s", v.Class())
|
||||
}
|
||||
}
|
||||
|
||||
func formatArrayOneLine(v otto.Value, limit int, seen map[otto.Value]bool) (string, error) {
|
||||
if limit == 0 {
|
||||
return "...", nil
|
||||
}
|
||||
|
||||
if seen[v] {
|
||||
return "[circular]", nil
|
||||
}
|
||||
|
||||
o := v.Object()
|
||||
|
||||
lv, err := o.Get("length")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
li, err := lv.Export()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
l, ok := li.(uint32)
|
||||
if !ok {
|
||||
return "", fmt.Errorf("length property must be a number; was %T", li)
|
||||
}
|
||||
|
||||
var bits []string
|
||||
|
||||
for i := 0; i < int(l); i++ {
|
||||
e, err := o.Get(fmt.Sprintf("%d", i))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
d, err := formatOneLine(e, limit-1, seenWith(seen, v))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bits = append(bits, d)
|
||||
}
|
||||
|
||||
return "[" + strings.Join(bits, ", ") + "]", nil
|
||||
}
|
||||
|
||||
func formatObjectOneLine(v otto.Value, limit int, seen map[otto.Value]bool) (string, error) {
|
||||
if limit == 0 {
|
||||
return "...", nil
|
||||
}
|
||||
|
||||
if seen[v] {
|
||||
return "[circular]", nil
|
||||
}
|
||||
|
||||
o := v.Object()
|
||||
|
||||
bits := []string{}
|
||||
|
||||
keys := o.Keys()
|
||||
|
||||
for _, k := range keys {
|
||||
e, err := o.Get(k)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
d, err := formatOneLine(e, limit-1, seenWith(seen, v))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
bits = append(bits, k+": "+d)
|
||||
}
|
||||
|
||||
return "{" + strings.Join(bits, ", ") + "}", nil
|
||||
}
|
151
vendor/fknsrs.biz/p/ottoext/repl/repl.go
vendored
Normal file
151
vendor/fknsrs.biz/p/ottoext/repl/repl.go
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
// Package repl implements an event loop aware REPL (read-eval-print loop)
|
||||
// for otto.
|
||||
package repl // import "fknsrs.biz/p/ottoext/repl"
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
"fknsrs.biz/p/ottoext/loop/looptask"
|
||||
"github.com/robertkrimen/otto"
|
||||
"github.com/robertkrimen/otto/parser"
|
||||
"gopkg.in/readline.v1"
|
||||
)
|
||||
|
||||
// Run creates a REPL with the default prompt and no prelude.
|
||||
func Run(l *loop.Loop) error {
|
||||
return RunWithPromptAndPrelude(l, "", "")
|
||||
}
|
||||
|
||||
// RunWithPrompt runs a REPL with the given prompt and no prelude.
|
||||
func RunWithPrompt(l *loop.Loop, prompt string) error {
|
||||
return RunWithPromptAndPrelude(l, prompt, "")
|
||||
}
|
||||
|
||||
// RunWithPrelude runs a REPL with the default prompt and the given prelude.
|
||||
func RunWithPrelude(l *loop.Loop, prelude string) error {
|
||||
return RunWithPromptAndPrelude(l, "", prelude)
|
||||
}
|
||||
|
||||
// RunWithPromptAndPrelude runs a REPL with the given prompt and prelude.
|
||||
func RunWithPromptAndPrelude(l *loop.Loop, prompt, prelude string) error {
|
||||
if prompt == "" {
|
||||
prompt = ">"
|
||||
}
|
||||
|
||||
prompt = strings.Trim(prompt, " ")
|
||||
prompt += " "
|
||||
|
||||
rl, err := readline.New(prompt)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.VM().Set("console", map[string]interface{}{
|
||||
"log": func(c otto.FunctionCall) otto.Value {
|
||||
s := make([]string, len(c.ArgumentList))
|
||||
for i := 0; i < len(c.ArgumentList); i++ {
|
||||
s[i] = c.Argument(i).String()
|
||||
}
|
||||
|
||||
rl.Stdout().Write([]byte(strings.Join(s, " ") + "\n"))
|
||||
rl.Refresh()
|
||||
|
||||
return otto.UndefinedValue()
|
||||
},
|
||||
"warn": func(c otto.FunctionCall) otto.Value {
|
||||
s := make([]string, len(c.ArgumentList))
|
||||
for i := 0; i < len(c.ArgumentList); i++ {
|
||||
s[i] = c.Argument(i).String()
|
||||
}
|
||||
|
||||
rl.Stderr().Write([]byte(strings.Join(s, " ") + "\n"))
|
||||
rl.Refresh()
|
||||
|
||||
return otto.UndefinedValue()
|
||||
},
|
||||
})
|
||||
|
||||
if prelude != "" {
|
||||
if _, err := io.Copy(rl.Stderr(), strings.NewReader(prelude+"\n")); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rl.Refresh()
|
||||
}
|
||||
|
||||
var d []string
|
||||
|
||||
for {
|
||||
ll, err := rl.Readline()
|
||||
if err != nil {
|
||||
if err == readline.ErrInterrupt {
|
||||
if d != nil {
|
||||
d = nil
|
||||
|
||||
rl.SetPrompt(prompt)
|
||||
rl.Refresh()
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
if len(d) == 0 && ll == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
d = append(d, ll)
|
||||
s := strings.Join(d, "\n")
|
||||
|
||||
if _, err := parser.ParseFile(nil, "repl", s, 0); err != nil {
|
||||
rl.SetPrompt(strings.Repeat(" ", len(prompt)))
|
||||
} else {
|
||||
rl.SetPrompt(prompt)
|
||||
|
||||
d = nil
|
||||
|
||||
t := looptask.NewEvalTask(s)
|
||||
// don't report errors to the loop - this lets us handle them and
|
||||
// resume normal operation
|
||||
t.SoftError = true
|
||||
l.Add(t)
|
||||
l.Ready(t)
|
||||
|
||||
v, err := <-t.Value, <-t.Error
|
||||
if err != nil {
|
||||
if oerr, ok := err.(*otto.Error); ok {
|
||||
io.Copy(rl.Stdout(), strings.NewReader(oerr.String()))
|
||||
} else {
|
||||
io.Copy(rl.Stdout(), strings.NewReader(err.Error()))
|
||||
}
|
||||
} else {
|
||||
f, err := format(v, 80, 2, 5)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
rl.Stdout().Write([]byte("\r" + f + "\n"))
|
||||
}
|
||||
}
|
||||
|
||||
rl.Refresh()
|
||||
}
|
||||
|
||||
return rl.Close()
|
||||
}
|
||||
|
||||
func inspect(v otto.Value, width, indent int) string {
|
||||
switch {
|
||||
case v.IsBoolean(), v.IsNull(), v.IsNumber(), v.IsString(), v.IsUndefined(), v.IsNaN():
|
||||
return fmt.Sprintf("%s%q", strings.Repeat(" ", indent), v.String())
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
130
vendor/fknsrs.biz/p/ottoext/timers/timers.go
vendored
Normal file
130
vendor/fknsrs.biz/p/ottoext/timers/timers.go
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
package timers // import "fknsrs.biz/p/ottoext/timers"
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/robertkrimen/otto"
|
||||
|
||||
"fknsrs.biz/p/ottoext/loop"
|
||||
)
|
||||
|
||||
var minDelay = map[bool]int64{
|
||||
true: 10,
|
||||
false: 4,
|
||||
}
|
||||
|
||||
func Define(vm *otto.Otto, l *loop.Loop) error {
|
||||
if v, err := vm.Get("setTimeout"); err != nil {
|
||||
return err
|
||||
} else if !v.IsUndefined() {
|
||||
return nil
|
||||
}
|
||||
|
||||
newTimer := func(interval bool) func(call otto.FunctionCall) otto.Value {
|
||||
return func(call otto.FunctionCall) otto.Value {
|
||||
delay, _ := call.Argument(1).ToInteger()
|
||||
if delay < minDelay[interval] {
|
||||
delay = minDelay[interval]
|
||||
}
|
||||
|
||||
t := &timerTask{
|
||||
duration: time.Duration(delay) * time.Millisecond,
|
||||
call: call,
|
||||
interval: interval,
|
||||
}
|
||||
l.Add(t)
|
||||
|
||||
t.timer = time.AfterFunc(t.duration, func() {
|
||||
l.Ready(t)
|
||||
})
|
||||
|
||||
value, err := call.Otto.ToValue(t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
}
|
||||
vm.Set("setTimeout", newTimer(false))
|
||||
vm.Set("setInterval", newTimer(true))
|
||||
|
||||
vm.Set("setImmediate", func(call otto.FunctionCall) otto.Value {
|
||||
t := &timerTask{
|
||||
duration: time.Millisecond,
|
||||
call: call,
|
||||
}
|
||||
l.Add(t)
|
||||
|
||||
t.timer = time.AfterFunc(t.duration, func() {
|
||||
l.Ready(t)
|
||||
})
|
||||
|
||||
value, err := call.Otto.ToValue(t)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return value
|
||||
})
|
||||
|
||||
clearTimeout := func(call otto.FunctionCall) otto.Value {
|
||||
v, _ := call.Argument(0).Export()
|
||||
if t, ok := v.(*timerTask); ok {
|
||||
t.stopped = true
|
||||
t.timer.Stop()
|
||||
l.Remove(t)
|
||||
}
|
||||
|
||||
return otto.UndefinedValue()
|
||||
}
|
||||
vm.Set("clearTimeout", clearTimeout)
|
||||
vm.Set("clearInterval", clearTimeout)
|
||||
vm.Set("clearImmediate", clearTimeout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type timerTask struct {
|
||||
id int64
|
||||
timer *time.Timer
|
||||
duration time.Duration
|
||||
interval bool
|
||||
call otto.FunctionCall
|
||||
stopped bool
|
||||
}
|
||||
|
||||
func (t *timerTask) SetID(id int64) { t.id = id }
|
||||
func (t *timerTask) GetID() int64 { return t.id }
|
||||
|
||||
func (t *timerTask) Execute(vm *otto.Otto, l *loop.Loop) error {
|
||||
var arguments []interface{}
|
||||
|
||||
if len(t.call.ArgumentList) > 2 {
|
||||
tmp := t.call.ArgumentList[2:]
|
||||
arguments = make([]interface{}, 2+len(tmp))
|
||||
|
||||
for i, value := range tmp {
|
||||
arguments[i+2] = value
|
||||
}
|
||||
} else {
|
||||
arguments = make([]interface{}, 1)
|
||||
}
|
||||
|
||||
arguments[0] = t.call.ArgumentList[0]
|
||||
|
||||
if _, err := vm.Call(`Function.call.call`, nil, arguments...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if t.interval && !t.stopped {
|
||||
t.timer.Reset(t.duration)
|
||||
l.Add(t)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *timerTask) Cancel() {
|
||||
t.timer.Stop()
|
||||
}
|
8
vendor/github.com/GeertJohan/go.rice/.gitignore
generated
vendored
Normal file
8
vendor/github.com/GeertJohan/go.rice/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
/example/example
|
||||
/example/example.exe
|
||||
/rice/rice
|
||||
/rice/rice.exe
|
||||
|
||||
*.rice-box.go
|
||||
*.rice-box.syso
|
||||
.wercker
|
19
vendor/github.com/GeertJohan/go.rice/.travis.yml
generated
vendored
Normal file
19
vendor/github.com/GeertJohan/go.rice/.travis.yml
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- master
|
||||
- 1.x.x
|
||||
- 1.8.x
|
||||
- 1.7.x
|
||||
- 1.6.x
|
||||
- 1.5.x
|
||||
|
||||
install:
|
||||
- go get -t ./...
|
||||
- env
|
||||
- if [ "${TRAVIS_GO_VERSION%.*}" != "1.5" ]; then go get github.com/golang/lint/golint; fi
|
||||
script:
|
||||
- go build -x ./...
|
||||
- go test -cover ./...
|
||||
- go vet ./...
|
||||
- if [ "${TRAVIS_GO_VERSION%.*}" != "1.5" ]; then golint .; fi
|
4
vendor/github.com/GeertJohan/go.rice/AUTHORS
generated
vendored
Normal file
4
vendor/github.com/GeertJohan/go.rice/AUTHORS
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
Geert-Johan Riemer <geertjohan@geertjohan.net>
|
||||
Paul Maddox <paul.maddox@gmail.com>
|
||||
Vincent Petithory <vincent.petithory@gmail.com>
|
||||
|
22
vendor/github.com/GeertJohan/go.rice/LICENSE
generated
vendored
Normal file
22
vendor/github.com/GeertJohan/go.rice/LICENSE
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
Copyright (c) 2013, Geert-Johan Riemer
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
151
vendor/github.com/GeertJohan/go.rice/README.md
generated
vendored
Normal file
151
vendor/github.com/GeertJohan/go.rice/README.md
generated
vendored
Normal file
@ -0,0 +1,151 @@
|
||||
## go.rice
|
||||
|
||||
[](https://travis-ci.org/GeertJohan/go.rice)
|
||||
[](https://godoc.org/github.com/GeertJohan/go.rice)
|
||||
|
||||
go.rice is a [Go](http://golang.org) package that makes working with resources such as html,js,css,images and templates very easy. During development `go.rice` will load required files directly from disk. Upon deployment it is easy to add all resource files to a executable using the `rice` tool, without changing the source code for your package. go.rice provides several methods to add resources to a binary.
|
||||
|
||||
### What does it do?
|
||||
The first thing go.rice does is finding the correct absolute path for your resource files. Say you are executing go binary in your home directory, but your `html-files` are located in `$GOPATH/src/yourApplication/html-files`. `go.rice` will lookup the correct path for that directory (relative to the location of yourApplication). The only thing you have to do is include the resources using `rice.FindBox("html-files")`.
|
||||
|
||||
This only works when the source is available to the machine executing the binary. Which is always the case when the binary was installed with `go get` or `go install`. It might occur that you wish to simply provide a binary, without source. The `rice` tool analyses source code and finds call's to `rice.FindBox(..)` and adds the required directories to the executable binary. There are several methods to add these resources. You can 'embed' by generating go source code, or append the resource to the executable as zip file. In both cases `go.rice` will detect the embedded or appended resources and load those, instead of looking up files from disk.
|
||||
|
||||
### Installation
|
||||
|
||||
Use `go get` to install the package the `rice` tool.
|
||||
```
|
||||
go get github.com/GeertJohan/go.rice
|
||||
go get github.com/GeertJohan/go.rice/rice
|
||||
```
|
||||
|
||||
### Package usage
|
||||
|
||||
Import the package: `import "github.com/GeertJohan/go.rice"`
|
||||
|
||||
**Serving a static content folder over HTTP with a rice Box**
|
||||
```go
|
||||
http.Handle("/", http.FileServer(rice.MustFindBox("http-files").HTTPBox()))
|
||||
http.ListenAndServe(":8080", nil)
|
||||
```
|
||||
|
||||
**Service a static content folder over HTTP at a non-root location**
|
||||
```go
|
||||
box := rice.MustFindBox("cssfiles")
|
||||
cssFileServer := http.StripPrefix("/css/", http.FileServer(box.HTTPBox()))
|
||||
http.Handle("/css/", cssFileServer)
|
||||
http.ListenAndServe(":8080", nil)
|
||||
```
|
||||
|
||||
Note the *trailing slash* in `/css/` in both the call to
|
||||
`http.StripPrefix` and `http.Handle`.
|
||||
|
||||
**Loading a template**
|
||||
```go
|
||||
// find a rice.Box
|
||||
templateBox, err := rice.FindBox("example-templates")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// get file contents as string
|
||||
templateString, err := templateBox.String("message.tmpl")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// parse and execute the template
|
||||
tmplMessage, err := template.New("message").Parse(templateString)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"})
|
||||
|
||||
```
|
||||
|
||||
Never call `FindBox()` or `MustFindBox()` from an `init()` function, as the boxes might have not been loaded at that time.
|
||||
|
||||
### Tool usage
|
||||
The `rice` tool lets you add the resources to a binary executable so the files are not loaded from the filesystem anymore. This creates a 'standalone' executable. There are several ways to add the resources to a binary, each has pro's and con's but all will work without requiring changes to the way you load the resources.
|
||||
|
||||
#### embed-go
|
||||
**Embed resources by generating Go source code**
|
||||
|
||||
This method must be executed before building. It generates a single Go source file called *rice-box.go* for each package, that is compiled by the go compiler into the binary.
|
||||
|
||||
The downside with this option is that the generated go source files can become very large, which will slow down compilation and require lots of memory to compile.
|
||||
|
||||
Execute the following commands:
|
||||
```
|
||||
rice embed-go
|
||||
go build
|
||||
```
|
||||
|
||||
*A Note on Symbolic Links*: `embed-go` uses the `os.Walk` function
|
||||
from the standard library. The `os.Walk` function does **not** follow
|
||||
symbolic links. So, when creating a box, be aware that any symbolic
|
||||
links inside your box's directory will not be followed. **However**,
|
||||
if the box itself is a symbolic link, its actual location will be
|
||||
resolved first and then walked. In summary, if your box location is a
|
||||
symbolic link, it will be followed but none of the symbolic links in
|
||||
the box will be followed.
|
||||
|
||||
#### embed-syso
|
||||
**Embed resources by generating a coff .syso file and some .go source code**
|
||||
|
||||
** This method is experimental and should not be used for production systems just yet **
|
||||
|
||||
This method must be executed before building. It generates a COFF .syso file and Go source file that are compiled by the go compiler into the binary.
|
||||
|
||||
Execute the following commands:
|
||||
```
|
||||
rice embed-syso
|
||||
go build
|
||||
```
|
||||
|
||||
#### append
|
||||
**Append resources to executable as zip file**
|
||||
|
||||
This method changes an already built executable. It appends the resources as zip file to the binary. It makes compilation a lot faster and can be used with large resource files.
|
||||
|
||||
Downsides for appending are that it requires `zip` to be installed and does not provide a working Seek method.
|
||||
|
||||
Run the following commands to create a standalone executable.
|
||||
```
|
||||
go build -o example
|
||||
rice append --exec example
|
||||
```
|
||||
|
||||
**Note: requires zip command to be installed**
|
||||
|
||||
On windows, install zip from http://gnuwin32.sourceforge.net/packages/zip.htm or cygwin/msys toolsets.
|
||||
|
||||
#### Help information
|
||||
Run `rice -h` for information about all options.
|
||||
|
||||
You can run the -h option for each sub-command, e.g. `rice append -h`.
|
||||
|
||||
### Order of precedence
|
||||
When opening a new box, the rice package tries to locate the resources in the following order:
|
||||
|
||||
- embedded in generated go source
|
||||
- appended as zip
|
||||
- 'live' from filesystem
|
||||
|
||||
|
||||
### License
|
||||
This project is licensed under a Simplified BSD license. Please read the [LICENSE file][license].
|
||||
|
||||
### TODO & Development
|
||||
This package is not completed yet. Though it already provides working embedding, some important featuers are still missing.
|
||||
- implement Readdir() correctly on virtualDir
|
||||
- in-code TODO's
|
||||
- find boxes in imported packages
|
||||
|
||||
Less important stuff:
|
||||
- idea, os/arch dependent embeds. rice checks if embedding file has _os_arch or build flags. If box is not requested by file without buildflags, then the buildflags are applied to the embed file.
|
||||
|
||||
### Package documentation
|
||||
|
||||
You will find package documentation at [godoc.org/github.com/GeertJohan/go.rice][godoc].
|
||||
|
||||
|
||||
[license]: https://github.com/GeertJohan/go.rice/blob/master/LICENSE
|
||||
[godoc]: http://godoc.org/github.com/GeertJohan/go.rice
|
138
vendor/github.com/GeertJohan/go.rice/appended.go
generated
vendored
Normal file
138
vendor/github.com/GeertJohan/go.rice/appended.go
generated
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/daaku/go.zipexe"
|
||||
"github.com/kardianos/osext"
|
||||
)
|
||||
|
||||
// appendedBox defines an appended box
|
||||
type appendedBox struct {
|
||||
Name string // box name
|
||||
Files map[string]*appendedFile // appended files (*zip.File) by full path
|
||||
}
|
||||
|
||||
type appendedFile struct {
|
||||
zipFile *zip.File
|
||||
dir bool
|
||||
dirInfo *appendedDirInfo
|
||||
children []*appendedFile
|
||||
content []byte
|
||||
}
|
||||
|
||||
// appendedBoxes is a public register of appendes boxes
|
||||
var appendedBoxes = make(map[string]*appendedBox)
|
||||
|
||||
func init() {
|
||||
// find if exec is appended
|
||||
thisFile, err := osext.Executable()
|
||||
if err != nil {
|
||||
return // not appended or cant find self executable
|
||||
}
|
||||
closer, rd, err := zipexe.OpenCloser(thisFile)
|
||||
if err != nil {
|
||||
return // not appended
|
||||
}
|
||||
defer closer.Close()
|
||||
|
||||
for _, f := range rd.File {
|
||||
// get box and file name from f.Name
|
||||
fileParts := strings.SplitN(strings.TrimLeft(filepath.ToSlash(f.Name), "/"), "/", 2)
|
||||
boxName := fileParts[0]
|
||||
var fileName string
|
||||
if len(fileParts) > 1 {
|
||||
fileName = fileParts[1]
|
||||
}
|
||||
|
||||
// find box or create new one if doesn't exist
|
||||
box := appendedBoxes[boxName]
|
||||
if box == nil {
|
||||
box = &appendedBox{
|
||||
Name: boxName,
|
||||
Files: make(map[string]*appendedFile),
|
||||
}
|
||||
appendedBoxes[boxName] = box
|
||||
}
|
||||
|
||||
// create and add file to box
|
||||
af := &appendedFile{
|
||||
zipFile: f,
|
||||
}
|
||||
if f.Comment == "dir" {
|
||||
af.dir = true
|
||||
af.dirInfo = &appendedDirInfo{
|
||||
name: filepath.Base(af.zipFile.Name),
|
||||
//++ TODO: use zip modtime when that is set correctly: af.zipFile.ModTime()
|
||||
time: time.Now(),
|
||||
}
|
||||
} else {
|
||||
// this is a file, we need it's contents so we can create a bytes.Reader when the file is opened
|
||||
// make a new byteslice
|
||||
af.content = make([]byte, af.zipFile.FileInfo().Size())
|
||||
// ignore reading empty files from zip (empty file still is a valid file to be read though!)
|
||||
if len(af.content) > 0 {
|
||||
// open io.ReadCloser
|
||||
rc, err := af.zipFile.Open()
|
||||
if err != nil {
|
||||
af.content = nil // this will cause an error when the file is being opened or seeked (which is good)
|
||||
// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet..
|
||||
log.Printf("error opening appended file %s: %v", af.zipFile.Name, err)
|
||||
} else {
|
||||
_, err = rc.Read(af.content)
|
||||
rc.Close()
|
||||
if err != nil {
|
||||
af.content = nil // this will cause an error when the file is being opened or seeked (which is good)
|
||||
// TODO: it's quite blunt to just log this stuff. but this is in init, so rice.Debug can't be changed yet..
|
||||
log.Printf("error reading data for appended file %s: %v", af.zipFile.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add appendedFile to box file list
|
||||
box.Files[fileName] = af
|
||||
|
||||
// add to parent dir (if any)
|
||||
dirName := filepath.Dir(fileName)
|
||||
if dirName == "." {
|
||||
dirName = ""
|
||||
}
|
||||
if fileName != "" { // don't make box root dir a child of itself
|
||||
if dir := box.Files[dirName]; dir != nil {
|
||||
dir.children = append(dir.children, af)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// implements os.FileInfo.
|
||||
// used for Readdir()
|
||||
type appendedDirInfo struct {
|
||||
name string
|
||||
time time.Time
|
||||
}
|
||||
|
||||
func (adi *appendedDirInfo) Name() string {
|
||||
return adi.name
|
||||
}
|
||||
func (adi *appendedDirInfo) Size() int64 {
|
||||
return 0
|
||||
}
|
||||
func (adi *appendedDirInfo) Mode() os.FileMode {
|
||||
return os.ModeDir
|
||||
}
|
||||
func (adi *appendedDirInfo) ModTime() time.Time {
|
||||
return adi.time
|
||||
}
|
||||
func (adi *appendedDirInfo) IsDir() bool {
|
||||
return true
|
||||
}
|
||||
func (adi *appendedDirInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
337
vendor/github.com/GeertJohan/go.rice/box.go
generated
vendored
Normal file
337
vendor/github.com/GeertJohan/go.rice/box.go
generated
vendored
Normal file
@ -0,0 +1,337 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/GeertJohan/go.rice/embedded"
|
||||
)
|
||||
|
||||
// Box abstracts a directory for resources/files.
|
||||
// It can either load files from disk, or from embedded code (when `rice --embed` was ran).
|
||||
type Box struct {
|
||||
name string
|
||||
absolutePath string
|
||||
embed *embedded.EmbeddedBox
|
||||
appendd *appendedBox
|
||||
}
|
||||
|
||||
var defaultLocateOrder = []LocateMethod{LocateEmbedded, LocateAppended, LocateFS}
|
||||
|
||||
func findBox(name string, order []LocateMethod) (*Box, error) {
|
||||
b := &Box{name: name}
|
||||
|
||||
// no support for absolute paths since gopath can be different on different machines.
|
||||
// therefore, required box must be located relative to package requiring it.
|
||||
if filepath.IsAbs(name) {
|
||||
return nil, errors.New("given name/path is absolute")
|
||||
}
|
||||
|
||||
var err error
|
||||
for _, method := range order {
|
||||
switch method {
|
||||
case LocateEmbedded:
|
||||
if embed := embedded.EmbeddedBoxes[name]; embed != nil {
|
||||
b.embed = embed
|
||||
return b, nil
|
||||
}
|
||||
|
||||
case LocateAppended:
|
||||
appendedBoxName := strings.Replace(name, `/`, `-`, -1)
|
||||
if appendd := appendedBoxes[appendedBoxName]; appendd != nil {
|
||||
b.appendd = appendd
|
||||
return b, nil
|
||||
}
|
||||
|
||||
case LocateFS:
|
||||
// resolve absolute directory path
|
||||
err := b.resolveAbsolutePathFromCaller()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// check if absolutePath exists on filesystem
|
||||
info, err := os.Stat(b.absolutePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// check if absolutePath is actually a directory
|
||||
if !info.IsDir() {
|
||||
err = errors.New("given name/path is not a directory")
|
||||
continue
|
||||
}
|
||||
return b, nil
|
||||
case LocateWorkingDirectory:
|
||||
// resolve absolute directory path
|
||||
err := b.resolveAbsolutePathFromWorkingDirectory()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// check if absolutePath exists on filesystem
|
||||
info, err := os.Stat(b.absolutePath)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
// check if absolutePath is actually a directory
|
||||
if !info.IsDir() {
|
||||
err = errors.New("given name/path is not a directory")
|
||||
continue
|
||||
}
|
||||
return b, nil
|
||||
}
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
err = fmt.Errorf("could not locate box %q", name)
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// FindBox returns a Box instance for given name.
|
||||
// When the given name is a relative path, it's base path will be the calling pkg/cmd's source root.
|
||||
// When the given name is absolute, it's absolute. derp.
|
||||
// Make sure the path doesn't contain any sensitive information as it might be placed into generated go source (embedded).
|
||||
func FindBox(name string) (*Box, error) {
|
||||
return findBox(name, defaultLocateOrder)
|
||||
}
|
||||
|
||||
// MustFindBox returns a Box instance for given name, like FindBox does.
|
||||
// It does not return an error, instead it panics when an error occurs.
|
||||
func MustFindBox(name string) *Box {
|
||||
box, err := findBox(name, defaultLocateOrder)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return box
|
||||
}
|
||||
|
||||
// This is injected as a mutable function literal so that we can mock it out in
|
||||
// tests and return a fixed test file.
|
||||
var resolveAbsolutePathFromCaller = func(name string, nStackFrames int) (string, error) {
|
||||
_, callingGoFile, _, ok := runtime.Caller(nStackFrames)
|
||||
if !ok {
|
||||
return "", errors.New("couldn't find caller on stack")
|
||||
}
|
||||
|
||||
// resolve to proper path
|
||||
pkgDir := filepath.Dir(callingGoFile)
|
||||
// fix for go cover
|
||||
const coverPath = "_test/_obj_test"
|
||||
if !filepath.IsAbs(pkgDir) {
|
||||
if i := strings.Index(pkgDir, coverPath); i >= 0 {
|
||||
pkgDir = pkgDir[:i] + pkgDir[i+len(coverPath):] // remove coverPath
|
||||
pkgDir = filepath.Join(os.Getenv("GOPATH"), "src", pkgDir) // make absolute
|
||||
}
|
||||
}
|
||||
return filepath.Join(pkgDir, name), nil
|
||||
}
|
||||
|
||||
func (b *Box) resolveAbsolutePathFromCaller() error {
|
||||
path, err := resolveAbsolutePathFromCaller(b.name, 4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.absolutePath = path
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
func (b *Box) resolveAbsolutePathFromWorkingDirectory() error {
|
||||
path, err := os.Getwd()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
b.absolutePath = filepath.Join(path, b.name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsEmbedded indicates wether this box was embedded into the application
|
||||
func (b *Box) IsEmbedded() bool {
|
||||
return b.embed != nil
|
||||
}
|
||||
|
||||
// IsAppended indicates wether this box was appended to the application
|
||||
func (b *Box) IsAppended() bool {
|
||||
return b.appendd != nil
|
||||
}
|
||||
|
||||
// Time returns how actual the box is.
|
||||
// When the box is embedded, it's value is saved in the embedding code.
|
||||
// When the box is live, this methods returns time.Now()
|
||||
func (b *Box) Time() time.Time {
|
||||
if b.IsEmbedded() {
|
||||
return b.embed.Time
|
||||
}
|
||||
|
||||
//++ TODO: return time for appended box
|
||||
|
||||
return time.Now()
|
||||
}
|
||||
|
||||
// Open opens a File from the box
|
||||
// If there is an error, it will be of type *os.PathError.
|
||||
func (b *Box) Open(name string) (*File, error) {
|
||||
if Debug {
|
||||
fmt.Printf("Open(%s)\n", name)
|
||||
}
|
||||
|
||||
if b.IsEmbedded() {
|
||||
if Debug {
|
||||
fmt.Println("Box is embedded")
|
||||
}
|
||||
|
||||
// trim prefix (paths are relative to box)
|
||||
name = strings.TrimLeft(name, "/")
|
||||
if Debug {
|
||||
fmt.Printf("Trying %s\n", name)
|
||||
}
|
||||
|
||||
// search for file
|
||||
ef := b.embed.Files[name]
|
||||
if ef == nil {
|
||||
if Debug {
|
||||
fmt.Println("Didn't find file in embed")
|
||||
}
|
||||
// file not found, try dir
|
||||
ed := b.embed.Dirs[name]
|
||||
if ed == nil {
|
||||
if Debug {
|
||||
fmt.Println("Didn't find dir in embed")
|
||||
}
|
||||
// dir not found, error out
|
||||
return nil, &os.PathError{
|
||||
Op: "open",
|
||||
Path: name,
|
||||
Err: os.ErrNotExist,
|
||||
}
|
||||
}
|
||||
if Debug {
|
||||
fmt.Println("Found dir. Returning virtual dir")
|
||||
}
|
||||
vd := newVirtualDir(ed)
|
||||
return &File{virtualD: vd}, nil
|
||||
}
|
||||
|
||||
// box is embedded
|
||||
if Debug {
|
||||
fmt.Println("Found file. Returning virtual file")
|
||||
}
|
||||
vf := newVirtualFile(ef)
|
||||
return &File{virtualF: vf}, nil
|
||||
}
|
||||
|
||||
if b.IsAppended() {
|
||||
// trim prefix (paths are relative to box)
|
||||
name = strings.TrimLeft(name, "/")
|
||||
|
||||
// search for file
|
||||
appendedFile := b.appendd.Files[name]
|
||||
if appendedFile == nil {
|
||||
return nil, &os.PathError{
|
||||
Op: "open",
|
||||
Path: name,
|
||||
Err: os.ErrNotExist,
|
||||
}
|
||||
}
|
||||
|
||||
// create new file
|
||||
f := &File{
|
||||
appendedF: appendedFile,
|
||||
}
|
||||
|
||||
// if this file is a directory, we want to be able to read and seek
|
||||
if !appendedFile.dir {
|
||||
// looks like malformed data in zip, error now
|
||||
if appendedFile.content == nil {
|
||||
return nil, &os.PathError{
|
||||
Op: "open",
|
||||
Path: "name",
|
||||
Err: errors.New("error reading data from zip file"),
|
||||
}
|
||||
}
|
||||
// create new bytes.Reader
|
||||
f.appendedFileReader = bytes.NewReader(appendedFile.content)
|
||||
}
|
||||
|
||||
// all done
|
||||
return f, nil
|
||||
}
|
||||
|
||||
// perform os open
|
||||
if Debug {
|
||||
fmt.Printf("Using os.Open(%s)", filepath.Join(b.absolutePath, name))
|
||||
}
|
||||
file, err := os.Open(filepath.Join(b.absolutePath, name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &File{realF: file}, nil
|
||||
}
|
||||
|
||||
// Bytes returns the content of the file with given name as []byte.
|
||||
func (b *Box) Bytes(name string) ([]byte, error) {
|
||||
file, err := b.Open(name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
// MustBytes returns the content of the file with given name as []byte.
|
||||
// panic's on error.
|
||||
func (b *Box) MustBytes(name string) []byte {
|
||||
bts, err := b.Bytes(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bts
|
||||
}
|
||||
|
||||
// String returns the content of the file with given name as string.
|
||||
func (b *Box) String(name string) (string, error) {
|
||||
// check if box is embedded, optimized fast path
|
||||
if b.IsEmbedded() {
|
||||
// find file in embed
|
||||
ef := b.embed.Files[name]
|
||||
if ef == nil {
|
||||
return "", os.ErrNotExist
|
||||
}
|
||||
// return as string
|
||||
return ef.Content, nil
|
||||
}
|
||||
|
||||
bts, err := b.Bytes(name)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bts), nil
|
||||
}
|
||||
|
||||
// MustString returns the content of the file with given name as string.
|
||||
// panic's on error.
|
||||
func (b *Box) MustString(name string) string {
|
||||
str, err := b.String(name)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// Name returns the name of the box
|
||||
func (b *Box) Name() string {
|
||||
return b.name
|
||||
}
|
39
vendor/github.com/GeertJohan/go.rice/config.go
generated
vendored
Normal file
39
vendor/github.com/GeertJohan/go.rice/config.go
generated
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
package rice
|
||||
|
||||
// LocateMethod defines how a box is located.
|
||||
type LocateMethod int
|
||||
|
||||
const (
|
||||
LocateFS = LocateMethod(iota) // Locate on the filesystem according to package path.
|
||||
LocateAppended // Locate boxes appended to the executable.
|
||||
LocateEmbedded // Locate embedded boxes.
|
||||
LocateWorkingDirectory // Locate on the binary working directory
|
||||
)
|
||||
|
||||
// Config allows customizing the box lookup behavior.
|
||||
type Config struct {
|
||||
// LocateOrder defines the priority order that boxes are searched for. By
|
||||
// default, the package global FindBox searches for embedded boxes first,
|
||||
// then appended boxes, and then finally boxes on the filesystem. That
|
||||
// search order may be customized by provided the ordered list here. Leaving
|
||||
// out a particular method will omit that from the search space. For
|
||||
// example, []LocateMethod{LocateEmbedded, LocateAppended} will never search
|
||||
// the filesystem for boxes.
|
||||
LocateOrder []LocateMethod
|
||||
}
|
||||
|
||||
// FindBox searches for boxes using the LocateOrder of the config.
|
||||
func (c *Config) FindBox(boxName string) (*Box, error) {
|
||||
return findBox(boxName, c.LocateOrder)
|
||||
}
|
||||
|
||||
// MustFindBox searches for boxes using the LocateOrder of the config, like
|
||||
// FindBox does. It does not return an error, instead it panics when an error
|
||||
// occurs.
|
||||
func (c *Config) MustFindBox(boxName string) *Box {
|
||||
box, err := findBox(boxName, c.LocateOrder)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return box
|
||||
}
|
4
vendor/github.com/GeertJohan/go.rice/debug.go
generated
vendored
Normal file
4
vendor/github.com/GeertJohan/go.rice/debug.go
generated
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
package rice
|
||||
|
||||
// Debug can be set to true to enable debugging.
|
||||
var Debug = false
|
90
vendor/github.com/GeertJohan/go.rice/embedded.go
generated
vendored
Normal file
90
vendor/github.com/GeertJohan/go.rice/embedded.go
generated
vendored
Normal file
@ -0,0 +1,90 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/GeertJohan/go.rice/embedded"
|
||||
)
|
||||
|
||||
// re-type to make exported methods invisible to user (godoc)
|
||||
// they're not required for the user
|
||||
// embeddedDirInfo implements os.FileInfo
|
||||
type embeddedDirInfo embedded.EmbeddedDir
|
||||
|
||||
// Name returns the base name of the directory
|
||||
// (implementing os.FileInfo)
|
||||
func (ed *embeddedDirInfo) Name() string {
|
||||
return ed.Filename
|
||||
}
|
||||
|
||||
// Size always returns 0
|
||||
// (implementing os.FileInfo)
|
||||
func (ed *embeddedDirInfo) Size() int64 {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Mode returns the file mode bits
|
||||
// (implementing os.FileInfo)
|
||||
func (ed *embeddedDirInfo) Mode() os.FileMode {
|
||||
return os.FileMode(0555 | os.ModeDir) // dr-xr-xr-x
|
||||
}
|
||||
|
||||
// ModTime returns the modification time
|
||||
// (implementing os.FileInfo)
|
||||
func (ed *embeddedDirInfo) ModTime() time.Time {
|
||||
return ed.DirModTime
|
||||
}
|
||||
|
||||
// IsDir returns the abbreviation for Mode().IsDir() (always true)
|
||||
// (implementing os.FileInfo)
|
||||
func (ed *embeddedDirInfo) IsDir() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Sys returns the underlying data source (always nil)
|
||||
// (implementing os.FileInfo)
|
||||
func (ed *embeddedDirInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
||||
|
||||
// re-type to make exported methods invisible to user (godoc)
|
||||
// they're not required for the user
|
||||
// embeddedFileInfo implements os.FileInfo
|
||||
type embeddedFileInfo embedded.EmbeddedFile
|
||||
|
||||
// Name returns the base name of the file
|
||||
// (implementing os.FileInfo)
|
||||
func (ef *embeddedFileInfo) Name() string {
|
||||
return ef.Filename
|
||||
}
|
||||
|
||||
// Size returns the length in bytes for regular files; system-dependent for others
|
||||
// (implementing os.FileInfo)
|
||||
func (ef *embeddedFileInfo) Size() int64 {
|
||||
return int64(len(ef.Content))
|
||||
}
|
||||
|
||||
// Mode returns the file mode bits
|
||||
// (implementing os.FileInfo)
|
||||
func (ef *embeddedFileInfo) Mode() os.FileMode {
|
||||
return os.FileMode(0555) // r-xr-xr-x
|
||||
}
|
||||
|
||||
// ModTime returns the modification time
|
||||
// (implementing os.FileInfo)
|
||||
func (ef *embeddedFileInfo) ModTime() time.Time {
|
||||
return ef.FileModTime
|
||||
}
|
||||
|
||||
// IsDir returns the abbreviation for Mode().IsDir() (always false)
|
||||
// (implementing os.FileInfo)
|
||||
func (ef *embeddedFileInfo) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Sys returns the underlying data source (always nil)
|
||||
// (implementing os.FileInfo)
|
||||
func (ef *embeddedFileInfo) Sys() interface{} {
|
||||
return nil
|
||||
}
|
80
vendor/github.com/GeertJohan/go.rice/embedded/embedded.go
generated
vendored
Normal file
80
vendor/github.com/GeertJohan/go.rice/embedded/embedded.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
// Package embedded defines embedded data types that are shared between the go.rice package and generated code.
|
||||
package embedded
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
EmbedTypeGo = 0
|
||||
EmbedTypeSyso = 1
|
||||
)
|
||||
|
||||
// EmbeddedBox defines an embedded box
|
||||
type EmbeddedBox struct {
|
||||
Name string // box name
|
||||
Time time.Time // embed time
|
||||
EmbedType int // kind of embedding
|
||||
Files map[string]*EmbeddedFile // ALL embedded files by full path
|
||||
Dirs map[string]*EmbeddedDir // ALL embedded dirs by full path
|
||||
}
|
||||
|
||||
// Link creates the ChildDirs and ChildFiles links in all EmbeddedDir's
|
||||
func (e *EmbeddedBox) Link() {
|
||||
for path, ed := range e.Dirs {
|
||||
fmt.Println(path)
|
||||
ed.ChildDirs = make([]*EmbeddedDir, 0)
|
||||
ed.ChildFiles = make([]*EmbeddedFile, 0)
|
||||
}
|
||||
for path, ed := range e.Dirs {
|
||||
parentDirpath, _ := filepath.Split(path)
|
||||
if strings.HasSuffix(parentDirpath, "/") {
|
||||
parentDirpath = parentDirpath[:len(parentDirpath)-1]
|
||||
}
|
||||
parentDir := e.Dirs[parentDirpath]
|
||||
if parentDir == nil {
|
||||
panic("parentDir `" + parentDirpath + "` is missing in embedded box")
|
||||
}
|
||||
parentDir.ChildDirs = append(parentDir.ChildDirs, ed)
|
||||
}
|
||||
for path, ef := range e.Files {
|
||||
dirpath, _ := filepath.Split(path)
|
||||
if strings.HasSuffix(dirpath, "/") {
|
||||
dirpath = dirpath[:len(dirpath)-1]
|
||||
}
|
||||
dir := e.Dirs[dirpath]
|
||||
if dir == nil {
|
||||
panic("dir `" + dirpath + "` is missing in embedded box")
|
||||
}
|
||||
dir.ChildFiles = append(dir.ChildFiles, ef)
|
||||
}
|
||||
}
|
||||
|
||||
// EmbeddedDir is instanced in the code generated by the rice tool and contains all necicary information about an embedded file
|
||||
type EmbeddedDir struct {
|
||||
Filename string
|
||||
DirModTime time.Time
|
||||
ChildDirs []*EmbeddedDir // direct childs, as returned by virtualDir.Readdir()
|
||||
ChildFiles []*EmbeddedFile // direct childs, as returned by virtualDir.Readdir()
|
||||
}
|
||||
|
||||
// EmbeddedFile is instanced in the code generated by the rice tool and contains all necicary information about an embedded file
|
||||
type EmbeddedFile struct {
|
||||
Filename string // filename
|
||||
FileModTime time.Time
|
||||
Content string
|
||||
}
|
||||
|
||||
// EmbeddedBoxes is a public register of embedded boxes
|
||||
var EmbeddedBoxes = make(map[string]*EmbeddedBox)
|
||||
|
||||
// RegisterEmbeddedBox registers an EmbeddedBox
|
||||
func RegisterEmbeddedBox(name string, box *EmbeddedBox) {
|
||||
if _, exists := EmbeddedBoxes[name]; exists {
|
||||
panic(fmt.Sprintf("EmbeddedBox with name `%s` exists already", name))
|
||||
}
|
||||
EmbeddedBoxes[name] = box
|
||||
}
|
2
vendor/github.com/GeertJohan/go.rice/example/example-files/file.txt
generated
vendored
Normal file
2
vendor/github.com/GeertJohan/go.rice/example/example-files/file.txt
generated
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
test content
|
||||
break
|
BIN
vendor/github.com/GeertJohan/go.rice/example/example-files/img/doge.jpg
generated
vendored
Normal file
BIN
vendor/github.com/GeertJohan/go.rice/example/example-files/img/doge.jpg
generated
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 52 KiB |
1
vendor/github.com/GeertJohan/go.rice/example/example-templates/message.tmpl
generated
vendored
Normal file
1
vendor/github.com/GeertJohan/go.rice/example/example-templates/message.tmpl
generated
vendored
Normal file
@ -0,0 +1 @@
|
||||
I have a message for you: {{.Message}}
|
69
vendor/github.com/GeertJohan/go.rice/example/example.go
generated
vendored
Normal file
69
vendor/github.com/GeertJohan/go.rice/example/example.go
generated
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"text/template"
|
||||
|
||||
"github.com/GeertJohan/go.rice"
|
||||
"github.com/davecgh/go-spew/spew"
|
||||
)
|
||||
|
||||
func main() {
|
||||
conf := rice.Config{
|
||||
LocateOrder: []rice.LocateMethod{rice.LocateEmbedded, rice.LocateAppended, rice.LocateFS},
|
||||
}
|
||||
box, err := conf.FindBox("example-files")
|
||||
if err != nil {
|
||||
log.Fatalf("error opening rice.Box: %s\n", err)
|
||||
}
|
||||
// spew.Dump(box)
|
||||
|
||||
contentString, err := box.String("file.txt")
|
||||
if err != nil {
|
||||
log.Fatalf("could not read file contents as string: %s\n", err)
|
||||
}
|
||||
log.Printf("Read some file contents as string:\n%s\n", contentString)
|
||||
|
||||
contentBytes, err := box.Bytes("file.txt")
|
||||
if err != nil {
|
||||
log.Fatalf("could not read file contents as byteSlice: %s\n", err)
|
||||
}
|
||||
log.Printf("Read some file contents as byteSlice:\n%s\n", hex.Dump(contentBytes))
|
||||
|
||||
file, err := box.Open("file.txt")
|
||||
if err != nil {
|
||||
log.Fatalf("could not open file: %s\n", err)
|
||||
}
|
||||
spew.Dump(file)
|
||||
|
||||
// find/create a rice.Box
|
||||
templateBox, err := rice.FindBox("example-templates")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// get file contents as string
|
||||
templateString, err := templateBox.String("message.tmpl")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
// parse and execute the template
|
||||
tmplMessage, err := template.New("message").Parse(templateString)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
tmplMessage.Execute(os.Stdout, map[string]string{"Message": "Hello, world!"})
|
||||
|
||||
http.Handle("/", http.FileServer(box.HTTPBox()))
|
||||
go func() {
|
||||
fmt.Println("Serving files on :8080, press ctrl-C to exit")
|
||||
err := http.ListenAndServe(":8080", nil)
|
||||
if err != nil {
|
||||
log.Fatalf("error serving files: %v", err)
|
||||
}
|
||||
}()
|
||||
select {}
|
||||
}
|
144
vendor/github.com/GeertJohan/go.rice/file.go
generated
vendored
Normal file
144
vendor/github.com/GeertJohan/go.rice/file.go
generated
vendored
Normal file
@ -0,0 +1,144 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
// File implements the io.Reader, io.Seeker, io.Closer and http.File interfaces
|
||||
type File struct {
|
||||
// File abstracts file methods so the user doesn't see the difference between rice.virtualFile, rice.virtualDir and os.File
|
||||
// TODO: maybe use internal File interface and four implementations: *os.File, appendedFile, virtualFile, virtualDir
|
||||
|
||||
// real file on disk
|
||||
realF *os.File
|
||||
|
||||
// when embedded (go)
|
||||
virtualF *virtualFile
|
||||
virtualD *virtualDir
|
||||
|
||||
// when appended (zip)
|
||||
appendedF *appendedFile
|
||||
appendedFileReader *bytes.Reader
|
||||
// TODO: is appendedFileReader subject of races? Might need a lock here..
|
||||
}
|
||||
|
||||
// Close is like (*os.File).Close()
|
||||
// Visit http://golang.org/pkg/os/#File.Close for more information
|
||||
func (f *File) Close() error {
|
||||
if f.appendedF != nil {
|
||||
if f.appendedFileReader == nil {
|
||||
return errors.New("already closed")
|
||||
}
|
||||
f.appendedFileReader = nil
|
||||
return nil
|
||||
}
|
||||
if f.virtualF != nil {
|
||||
return f.virtualF.close()
|
||||
}
|
||||
if f.virtualD != nil {
|
||||
return f.virtualD.close()
|
||||
}
|
||||
return f.realF.Close()
|
||||
}
|
||||
|
||||
// Stat is like (*os.File).Stat()
|
||||
// Visit http://golang.org/pkg/os/#File.Stat for more information
|
||||
func (f *File) Stat() (os.FileInfo, error) {
|
||||
if f.appendedF != nil {
|
||||
if f.appendedF.dir {
|
||||
return f.appendedF.dirInfo, nil
|
||||
}
|
||||
if f.appendedFileReader == nil {
|
||||
return nil, errors.New("file is closed")
|
||||
}
|
||||
return f.appendedF.zipFile.FileInfo(), nil
|
||||
}
|
||||
if f.virtualF != nil {
|
||||
return f.virtualF.stat()
|
||||
}
|
||||
if f.virtualD != nil {
|
||||
return f.virtualD.stat()
|
||||
}
|
||||
return f.realF.Stat()
|
||||
}
|
||||
|
||||
// Readdir is like (*os.File).Readdir()
|
||||
// Visit http://golang.org/pkg/os/#File.Readdir for more information
|
||||
func (f *File) Readdir(count int) ([]os.FileInfo, error) {
|
||||
if f.appendedF != nil {
|
||||
if f.appendedF.dir {
|
||||
fi := make([]os.FileInfo, 0, len(f.appendedF.children))
|
||||
for _, childAppendedFile := range f.appendedF.children {
|
||||
if childAppendedFile.dir {
|
||||
fi = append(fi, childAppendedFile.dirInfo)
|
||||
} else {
|
||||
fi = append(fi, childAppendedFile.zipFile.FileInfo())
|
||||
}
|
||||
}
|
||||
return fi, nil
|
||||
}
|
||||
//++ TODO: is os.ErrInvalid the correct error for Readdir on file?
|
||||
return nil, os.ErrInvalid
|
||||
}
|
||||
if f.virtualF != nil {
|
||||
return f.virtualF.readdir(count)
|
||||
}
|
||||
if f.virtualD != nil {
|
||||
return f.virtualD.readdir(count)
|
||||
}
|
||||
return f.realF.Readdir(count)
|
||||
}
|
||||
|
||||
// Read is like (*os.File).Read()
|
||||
// Visit http://golang.org/pkg/os/#File.Read for more information
|
||||
func (f *File) Read(bts []byte) (int, error) {
|
||||
if f.appendedF != nil {
|
||||
if f.appendedFileReader == nil {
|
||||
return 0, &os.PathError{
|
||||
Op: "read",
|
||||
Path: filepath.Base(f.appendedF.zipFile.Name),
|
||||
Err: errors.New("file is closed"),
|
||||
}
|
||||
}
|
||||
if f.appendedF.dir {
|
||||
return 0, &os.PathError{
|
||||
Op: "read",
|
||||
Path: filepath.Base(f.appendedF.zipFile.Name),
|
||||
Err: errors.New("is a directory"),
|
||||
}
|
||||
}
|
||||
return f.appendedFileReader.Read(bts)
|
||||
}
|
||||
if f.virtualF != nil {
|
||||
return f.virtualF.read(bts)
|
||||
}
|
||||
if f.virtualD != nil {
|
||||
return f.virtualD.read(bts)
|
||||
}
|
||||
return f.realF.Read(bts)
|
||||
}
|
||||
|
||||
// Seek is like (*os.File).Seek()
|
||||
// Visit http://golang.org/pkg/os/#File.Seek for more information
|
||||
func (f *File) Seek(offset int64, whence int) (int64, error) {
|
||||
if f.appendedF != nil {
|
||||
if f.appendedFileReader == nil {
|
||||
return 0, &os.PathError{
|
||||
Op: "seek",
|
||||
Path: filepath.Base(f.appendedF.zipFile.Name),
|
||||
Err: errors.New("file is closed"),
|
||||
}
|
||||
}
|
||||
return f.appendedFileReader.Seek(offset, whence)
|
||||
}
|
||||
if f.virtualF != nil {
|
||||
return f.virtualF.seek(offset, whence)
|
||||
}
|
||||
if f.virtualD != nil {
|
||||
return f.virtualD.seek(offset, whence)
|
||||
}
|
||||
return f.realF.Seek(offset, whence)
|
||||
}
|
21
vendor/github.com/GeertJohan/go.rice/http.go
generated
vendored
Normal file
21
vendor/github.com/GeertJohan/go.rice/http.go
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// HTTPBox implements http.FileSystem which allows the use of Box with a http.FileServer.
|
||||
// e.g.: http.Handle("/", http.FileServer(rice.MustFindBox("http-files").HTTPBox()))
|
||||
type HTTPBox struct {
|
||||
*Box
|
||||
}
|
||||
|
||||
// HTTPBox creates a new HTTPBox from an existing Box
|
||||
func (b *Box) HTTPBox() *HTTPBox {
|
||||
return &HTTPBox{b}
|
||||
}
|
||||
|
||||
// Open returns a File using the http.File interface
|
||||
func (hb *HTTPBox) Open(name string) (http.File, error) {
|
||||
return hb.Box.Open(name)
|
||||
}
|
157
vendor/github.com/GeertJohan/go.rice/rice/append.go
generated
vendored
Normal file
157
vendor/github.com/GeertJohan/go.rice/rice/append.go
generated
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
zipexe "github.com/daaku/go.zipexe"
|
||||
)
|
||||
|
||||
func operationAppend(pkgs []*build.Package) {
|
||||
// create tmp zipfile
|
||||
tmpZipfileName := filepath.Join(os.TempDir(), fmt.Sprintf("ricebox-%d-%s.zip", time.Now().Unix(), randomString(10)))
|
||||
verbosef("Will create tmp zipfile: %s\n", tmpZipfileName)
|
||||
tmpZipfile, err := os.Create(tmpZipfileName)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating tmp zipfile: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer func() {
|
||||
tmpZipfile.Close()
|
||||
os.Remove(tmpZipfileName)
|
||||
}()
|
||||
|
||||
// find abs path for binary file
|
||||
binfileName, err := filepath.Abs(flags.Append.Executable)
|
||||
if err != nil {
|
||||
fmt.Printf("Error finding absolute path for executable to append: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
verbosef("Will append to file: %s\n", binfileName)
|
||||
|
||||
// check that command doesn't already have zip appended
|
||||
if rd, _ := zipexe.Open(binfileName); rd != nil {
|
||||
fmt.Printf("Cannot append to already appended executable. Please remove %s and build a fresh one.\n", binfileName)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// open binfile
|
||||
binfile, err := os.OpenFile(binfileName, os.O_WRONLY, os.ModeAppend)
|
||||
if err != nil {
|
||||
fmt.Printf("Error: unable to open executable file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer binfile.Close()
|
||||
|
||||
binfileInfo, err := binfile.Stat()
|
||||
if err != nil {
|
||||
fmt.Printf("Error: unable to stat executable file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// create zip.Writer
|
||||
zipWriter := zip.NewWriter(tmpZipfile)
|
||||
|
||||
// write the zip offset into the zip data
|
||||
zipWriter.SetOffset(binfileInfo.Size())
|
||||
|
||||
for _, pkg := range pkgs {
|
||||
// find boxes for this command
|
||||
boxMap := findBoxes(pkg)
|
||||
|
||||
// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
|
||||
if len(boxMap) == 0 {
|
||||
fmt.Printf("no calls to rice.FindBox() or rice.MustFindBox() found in import path `%s`\n", pkg.ImportPath)
|
||||
continue
|
||||
}
|
||||
|
||||
verbosef("\n")
|
||||
|
||||
for boxname := range boxMap {
|
||||
appendedBoxName := strings.Replace(boxname, `/`, `-`, -1)
|
||||
|
||||
// walk box path's and insert files
|
||||
boxPath := filepath.Clean(filepath.Join(pkg.Dir, boxname))
|
||||
filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
|
||||
if info == nil {
|
||||
fmt.Printf("Error: box \"%s\" not found on disk\n", path)
|
||||
os.Exit(1)
|
||||
}
|
||||
// create zipFilename
|
||||
zipFileName := filepath.Join(appendedBoxName, strings.TrimPrefix(path, boxPath))
|
||||
// write directories as empty file with comment "dir"
|
||||
if info.IsDir() {
|
||||
_, err := zipWriter.CreateHeader(&zip.FileHeader{
|
||||
Name: zipFileName,
|
||||
Comment: "dir",
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating dir in tmp zip: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// create zipFileWriter
|
||||
zipFileHeader, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating zip FileHeader: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
zipFileHeader.Name = zipFileName
|
||||
zipFileWriter, err := zipWriter.CreateHeader(zipFileHeader)
|
||||
if err != nil {
|
||||
fmt.Printf("Error creating file in tmp zip: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
srcFile, err := os.Open(path)
|
||||
if err != nil {
|
||||
fmt.Printf("Error opening file to append: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
_, err = io.Copy(zipFileWriter, srcFile)
|
||||
if err != nil {
|
||||
fmt.Printf("Error copying file contents to zip: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
srcFile.Close()
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
err = zipWriter.Close()
|
||||
if err != nil {
|
||||
fmt.Printf("Error closing tmp zipfile: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
err = tmpZipfile.Sync()
|
||||
if err != nil {
|
||||
fmt.Printf("Error syncing tmp zipfile: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
_, err = tmpZipfile.Seek(0, 0)
|
||||
if err != nil {
|
||||
fmt.Printf("Error seeking tmp zipfile: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
_, err = binfile.Seek(0, 2)
|
||||
if err != nil {
|
||||
fmt.Printf("Error seeking bin file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
_, err = io.Copy(binfile, tmpZipfile)
|
||||
if err != nil {
|
||||
fmt.Printf("Error appending zipfile to executable: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
33
vendor/github.com/GeertJohan/go.rice/rice/clean.go
generated
vendored
Normal file
33
vendor/github.com/GeertJohan/go.rice/rice/clean.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func operationClean(pkg *build.Package) {
|
||||
filepath.Walk(pkg.Dir, func(filename string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Printf("error walking pkg dir to clean files: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
verbosef("checking file '%s'\n", filename)
|
||||
if filepath.Base(filename) == "rice-box.go" ||
|
||||
strings.HasSuffix(filename, ".rice-box.go") ||
|
||||
strings.HasSuffix(filename, ".rice-box.syso") {
|
||||
err := os.Remove(filename)
|
||||
if err != nil {
|
||||
fmt.Printf("error removing file (%s): %s\n", filename, err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
verbosef("removed file '%s'\n", filename)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
161
vendor/github.com/GeertJohan/go.rice/rice/embed-go.go
generated
vendored
Normal file
161
vendor/github.com/GeertJohan/go.rice/rice/embed-go.go
generated
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"go/format"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const boxFilename = "rice-box.go"
|
||||
|
||||
func writeBoxesGo(pkg *build.Package, out io.Writer) error {
|
||||
boxMap := findBoxes(pkg)
|
||||
|
||||
// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
|
||||
if len(boxMap) == 0 {
|
||||
fmt.Println("no calls to rice.FindBox() found")
|
||||
return nil
|
||||
}
|
||||
|
||||
verbosef("\n")
|
||||
|
||||
var boxes []*boxDataType
|
||||
|
||||
for boxname := range boxMap {
|
||||
// find path and filename for this box
|
||||
boxPath := filepath.Join(pkg.Dir, boxname)
|
||||
|
||||
// Check to see if the path for the box is a symbolic link. If so, simply
|
||||
// box what the symbolic link points to. Note: the filepath.Walk function
|
||||
// will NOT follow any nested symbolic links. This only handles the case
|
||||
// where the root of the box is a symbolic link.
|
||||
symPath, serr := os.Readlink(boxPath)
|
||||
if serr == nil {
|
||||
boxPath = symPath
|
||||
}
|
||||
|
||||
// verbose info
|
||||
verbosef("embedding box '%s' to '%s'\n", boxname, boxFilename)
|
||||
|
||||
// read box metadata
|
||||
boxInfo, ierr := os.Stat(boxPath)
|
||||
if ierr != nil {
|
||||
return fmt.Errorf("Error: unable to access box at %s\n", boxPath)
|
||||
}
|
||||
|
||||
// create box datastructure (used by template)
|
||||
box := &boxDataType{
|
||||
BoxName: boxname,
|
||||
UnixNow: boxInfo.ModTime().Unix(),
|
||||
Files: make([]*fileDataType, 0),
|
||||
Dirs: make(map[string]*dirDataType),
|
||||
}
|
||||
|
||||
if !boxInfo.IsDir() {
|
||||
return fmt.Errorf("Error: Box %s must point to a directory but points to %s instead\n",
|
||||
boxname, boxPath)
|
||||
}
|
||||
|
||||
// fill box datastructure with file data
|
||||
err := filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("error walking box: %s\n", err)
|
||||
}
|
||||
|
||||
filename := strings.TrimPrefix(path, boxPath)
|
||||
filename = strings.Replace(filename, "\\", "/", -1)
|
||||
filename = strings.TrimPrefix(filename, "/")
|
||||
if info.IsDir() {
|
||||
dirData := &dirDataType{
|
||||
Identifier: "dir" + nextIdentifier(),
|
||||
FileName: filename,
|
||||
ModTime: info.ModTime().Unix(),
|
||||
ChildFiles: make([]*fileDataType, 0),
|
||||
ChildDirs: make([]*dirDataType, 0),
|
||||
}
|
||||
verbosef("\tincludes dir: '%s'\n", dirData.FileName)
|
||||
box.Dirs[dirData.FileName] = dirData
|
||||
|
||||
// add tree entry (skip for root, it'll create a recursion)
|
||||
if dirData.FileName != "" {
|
||||
pathParts := strings.Split(dirData.FileName, "/")
|
||||
parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
|
||||
parentDir.ChildDirs = append(parentDir.ChildDirs, dirData)
|
||||
}
|
||||
} else {
|
||||
fileData := &fileDataType{
|
||||
Identifier: "file" + nextIdentifier(),
|
||||
FileName: filename,
|
||||
ModTime: info.ModTime().Unix(),
|
||||
}
|
||||
verbosef("\tincludes file: '%s'\n", fileData.FileName)
|
||||
fileData.Content, err = ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading file content while walking box: %s\n", err)
|
||||
}
|
||||
box.Files = append(box.Files, fileData)
|
||||
|
||||
// add tree entry
|
||||
pathParts := strings.Split(fileData.FileName, "/")
|
||||
parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
|
||||
if parentDir == nil {
|
||||
return fmt.Errorf("Error: parent of %s is not within the box\n", path)
|
||||
}
|
||||
parentDir.ChildFiles = append(parentDir.ChildFiles, fileData)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
boxes = append(boxes, box)
|
||||
|
||||
}
|
||||
|
||||
embedSourceUnformated := bytes.NewBuffer(make([]byte, 0))
|
||||
|
||||
// execute template to buffer
|
||||
err := tmplEmbeddedBox.Execute(
|
||||
embedSourceUnformated,
|
||||
embedFileDataType{pkg.Name, boxes},
|
||||
)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing embedded box to file (template execute): %s\n", err)
|
||||
}
|
||||
|
||||
// format the source code
|
||||
embedSource, err := format.Source(embedSourceUnformated.Bytes())
|
||||
if err != nil {
|
||||
return fmt.Errorf("error formatting embedSource: %s\n", err)
|
||||
}
|
||||
|
||||
// write source to file
|
||||
_, err = io.Copy(out, bytes.NewBuffer(embedSource))
|
||||
if err != nil {
|
||||
return fmt.Errorf("error writing embedSource to file: %s\n", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func operationEmbedGo(pkg *build.Package) {
|
||||
// create go file for box
|
||||
boxFile, err := os.Create(filepath.Join(pkg.Dir, boxFilename))
|
||||
if err != nil {
|
||||
log.Printf("error creating embedded box file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer boxFile.Close()
|
||||
|
||||
err = writeBoxesGo(pkg, boxFile)
|
||||
if err != nil {
|
||||
log.Printf("error creating embedded box file: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
204
vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go
generated
vendored
Normal file
204
vendor/github.com/GeertJohan/go.rice/rice/embed-syso.go
generated
vendored
Normal file
@ -0,0 +1,204 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"go/build"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"github.com/GeertJohan/go.rice/embedded"
|
||||
"github.com/akavel/rsrc/coff"
|
||||
)
|
||||
|
||||
type sizedReader struct {
|
||||
*bytes.Reader
|
||||
}
|
||||
|
||||
func (s sizedReader) Size() int64 {
|
||||
return int64(s.Len())
|
||||
}
|
||||
|
||||
var tmplEmbeddedSysoHelper *template.Template
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
tmplEmbeddedSysoHelper, err = template.New("embeddedSysoHelper").Parse(`package {{.Package}}
|
||||
// ############# GENERATED CODE #####################
|
||||
// ## This file was generated by the rice tool.
|
||||
// ## Do not edit unless you know what you're doing.
|
||||
// ##################################################
|
||||
|
||||
// extern char _bricebox_{{.Symname}}[], _ericebox_{{.Symname}};
|
||||
// int get_{{.Symname}}_length() {
|
||||
// return &_ericebox_{{.Symname}} - _bricebox_{{.Symname}};
|
||||
// }
|
||||
import "C"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"github.com/GeertJohan/go.rice/embedded"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
ptr := unsafe.Pointer(&C._bricebox_{{.Symname}})
|
||||
bts := C.GoBytes(ptr, C.get_{{.Symname}}_length())
|
||||
embeddedBox := &embedded.EmbeddedBox{}
|
||||
err := gob.NewDecoder(bytes.NewReader(bts)).Decode(embeddedBox)
|
||||
if err != nil {
|
||||
panic("error decoding embedded box: "+err.Error())
|
||||
}
|
||||
embeddedBox.Link()
|
||||
embedded.RegisterEmbeddedBox(embeddedBox.Name, embeddedBox)
|
||||
}`)
|
||||
if err != nil {
|
||||
panic("could not parse template embeddedSysoHelper: " + err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
type embeddedSysoHelperData struct {
|
||||
Package string
|
||||
Symname string
|
||||
}
|
||||
|
||||
func operationEmbedSyso(pkg *build.Package) {
|
||||
|
||||
regexpSynameReplacer := regexp.MustCompile(`[^a-z0-9_]`)
|
||||
|
||||
boxMap := findBoxes(pkg)
|
||||
|
||||
// notify user when no calls to rice.FindBox are made (is this an error and therefore os.Exit(1) ?
|
||||
if len(boxMap) == 0 {
|
||||
fmt.Println("no calls to rice.FindBox() found")
|
||||
return
|
||||
}
|
||||
|
||||
verbosef("\n")
|
||||
|
||||
for boxname := range boxMap {
|
||||
// find path and filename for this box
|
||||
boxPath := filepath.Join(pkg.Dir, boxname)
|
||||
boxFilename := strings.Replace(boxname, "/", "-", -1)
|
||||
boxFilename = strings.Replace(boxFilename, "..", "back", -1)
|
||||
boxFilename = strings.Replace(boxFilename, ".", "-", -1)
|
||||
|
||||
// verbose info
|
||||
verbosef("embedding box '%s'\n", boxname)
|
||||
verbosef("\tto file %s\n", boxFilename)
|
||||
|
||||
// read box metadata
|
||||
boxInfo, ierr := os.Stat(boxPath)
|
||||
if ierr != nil {
|
||||
fmt.Printf("Error: unable to access box at %s\n", boxPath)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// create box datastructure (used by template)
|
||||
box := &embedded.EmbeddedBox{
|
||||
Name: boxname,
|
||||
Time: boxInfo.ModTime(),
|
||||
EmbedType: embedded.EmbedTypeSyso,
|
||||
Files: make(map[string]*embedded.EmbeddedFile),
|
||||
Dirs: make(map[string]*embedded.EmbeddedDir),
|
||||
}
|
||||
|
||||
// fill box datastructure with file data
|
||||
filepath.Walk(boxPath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
fmt.Printf("error walking box: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
filename := strings.TrimPrefix(path, boxPath)
|
||||
filename = strings.Replace(filename, "\\", "/", -1)
|
||||
filename = strings.TrimPrefix(filename, "/")
|
||||
if info.IsDir() {
|
||||
embeddedDir := &embedded.EmbeddedDir{
|
||||
Filename: filename,
|
||||
DirModTime: info.ModTime(),
|
||||
}
|
||||
verbosef("\tincludes dir: '%s'\n", embeddedDir.Filename)
|
||||
box.Dirs[embeddedDir.Filename] = embeddedDir
|
||||
|
||||
// add tree entry (skip for root, it'll create a recursion)
|
||||
if embeddedDir.Filename != "" {
|
||||
pathParts := strings.Split(embeddedDir.Filename, "/")
|
||||
parentDir := box.Dirs[strings.Join(pathParts[:len(pathParts)-1], "/")]
|
||||
parentDir.ChildDirs = append(parentDir.ChildDirs, embeddedDir)
|
||||
}
|
||||
} else {
|
||||
embeddedFile := &embedded.EmbeddedFile{
|
||||
Filename: filename,
|
||||
FileModTime: info.ModTime(),
|
||||
Content: "",
|
||||
}
|
||||
verbosef("\tincludes file: '%s'\n", embeddedFile.Filename)
|
||||
contentBytes, err := ioutil.ReadFile(path)
|
||||
if err != nil {
|
||||
fmt.Printf("error reading file content while walking box: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
embeddedFile.Content = string(contentBytes)
|
||||
box.Files[embeddedFile.Filename] = embeddedFile
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
// encode embedded box to gob file
|
||||
boxGobBuf := &bytes.Buffer{}
|
||||
err := gob.NewEncoder(boxGobBuf).Encode(box)
|
||||
if err != nil {
|
||||
fmt.Printf("error encoding box to gob: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
verbosef("gob-encoded embeddedBox is %d bytes large\n", boxGobBuf.Len())
|
||||
|
||||
// write coff
|
||||
symname := regexpSynameReplacer.ReplaceAllString(boxname, "_")
|
||||
createCoffSyso(boxname, symname, "386", boxGobBuf.Bytes())
|
||||
createCoffSyso(boxname, symname, "amd64", boxGobBuf.Bytes())
|
||||
|
||||
// write go
|
||||
sysoHelperData := embeddedSysoHelperData{
|
||||
Package: pkg.Name,
|
||||
Symname: symname,
|
||||
}
|
||||
fileSysoHelper, err := os.Create(boxFilename + ".rice-box.go")
|
||||
if err != nil {
|
||||
fmt.Printf("error creating syso helper: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
err = tmplEmbeddedSysoHelper.Execute(fileSysoHelper, sysoHelperData)
|
||||
if err != nil {
|
||||
fmt.Printf("error executing tmplEmbeddedSysoHelper: %v\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func createCoffSyso(boxFilename string, symname string, arch string, data []byte) {
|
||||
boxCoff := coff.NewRDATA()
|
||||
switch arch {
|
||||
case "386":
|
||||
case "amd64":
|
||||
boxCoff.FileHeader.Machine = 0x8664
|
||||
default:
|
||||
panic("invalid arch")
|
||||
}
|
||||
boxCoff.AddData("_bricebox_"+symname, sizedReader{bytes.NewReader(data)})
|
||||
boxCoff.AddData("_ericebox_"+symname, io.NewSectionReader(strings.NewReader("\000\000"), 0, 2)) // TODO: why? copied from rsrc, which copied it from as-generated
|
||||
boxCoff.Freeze()
|
||||
err := writeCoff(boxCoff, boxFilename+"_"+arch+".rice-box.syso")
|
||||
if err != nil {
|
||||
fmt.Printf("error writing %s coff/.syso: %v\n", arch, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
150
vendor/github.com/GeertJohan/go.rice/rice/find.go
generated
vendored
Normal file
150
vendor/github.com/GeertJohan/go.rice/rice/find.go
generated
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func badArgument(fileset *token.FileSet, p token.Pos) {
|
||||
pos := fileset.Position(p)
|
||||
filename := pos.Filename
|
||||
base, err := os.Getwd()
|
||||
if err == nil {
|
||||
rpath, perr := filepath.Rel(base, pos.Filename)
|
||||
if perr == nil {
|
||||
filename = rpath
|
||||
}
|
||||
}
|
||||
msg := fmt.Sprintf("%s:%d: Error: found call to rice.FindBox, "+
|
||||
"but argument must be a string literal.\n", filename, pos.Line)
|
||||
fmt.Println(msg)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
func findBoxes(pkg *build.Package) map[string]bool {
|
||||
// create map of boxes to embed
|
||||
var boxMap = make(map[string]bool)
|
||||
|
||||
// create one list of files for this package
|
||||
filenames := make([]string, 0, len(pkg.GoFiles)+len(pkg.CgoFiles))
|
||||
filenames = append(filenames, pkg.GoFiles...)
|
||||
filenames = append(filenames, pkg.CgoFiles...)
|
||||
|
||||
// loop over files, search for rice.FindBox(..) calls
|
||||
for _, filename := range filenames {
|
||||
// find full filepath
|
||||
fullpath := filepath.Join(pkg.Dir, filename)
|
||||
if strings.HasSuffix(filename, "rice-box.go") {
|
||||
// Ignore *.rice-box.go files
|
||||
verbosef("skipping file %q\n", fullpath)
|
||||
continue
|
||||
}
|
||||
verbosef("scanning file %q\n", fullpath)
|
||||
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, fullpath, nil, 0)
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var riceIsImported bool
|
||||
ricePkgName := "rice"
|
||||
for _, imp := range f.Imports {
|
||||
if strings.HasSuffix(imp.Path.Value, "go.rice\"") {
|
||||
if imp.Name != nil {
|
||||
ricePkgName = imp.Name.Name
|
||||
}
|
||||
riceIsImported = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !riceIsImported {
|
||||
// Rice wasn't imported, so we won't find a box.
|
||||
continue
|
||||
}
|
||||
if ricePkgName == "_" {
|
||||
// Rice pkg is unnamed, so we won't find a box.
|
||||
continue
|
||||
}
|
||||
|
||||
// Inspect AST, looking for calls to (Must)?FindBox.
|
||||
// First parameter of the func must be a basic literal.
|
||||
// Identifiers won't be resolved.
|
||||
var nextIdentIsBoxFunc bool
|
||||
var nextBasicLitParamIsBoxName bool
|
||||
var boxCall token.Pos
|
||||
var variableToRemember string
|
||||
var validVariablesForBoxes map[string]bool = make(map[string]bool)
|
||||
|
||||
ast.Inspect(f, func(node ast.Node) bool {
|
||||
if node == nil {
|
||||
return false
|
||||
}
|
||||
switch x := node.(type) {
|
||||
// this case fixes the var := func() style assignments, not assignments to vars declared separately from the assignment.
|
||||
case *ast.AssignStmt:
|
||||
var assign = node.(*ast.AssignStmt)
|
||||
name, found := assign.Lhs[0].(*ast.Ident)
|
||||
if found {
|
||||
variableToRemember = name.Name
|
||||
composite, first := assign.Rhs[0].(*ast.CompositeLit)
|
||||
if first {
|
||||
riceSelector, second := composite.Type.(*ast.SelectorExpr)
|
||||
|
||||
if second {
|
||||
callCorrect := riceSelector.Sel.Name == "Config"
|
||||
packageName, third := riceSelector.X.(*ast.Ident)
|
||||
|
||||
if third && callCorrect && packageName.Name == ricePkgName {
|
||||
validVariablesForBoxes[name.Name] = true
|
||||
verbosef("\tfound variable, saving to scan for boxes: %q\n", name.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
case *ast.Ident:
|
||||
if nextIdentIsBoxFunc || ricePkgName == "." {
|
||||
nextIdentIsBoxFunc = false
|
||||
if x.Name == "FindBox" || x.Name == "MustFindBox" {
|
||||
nextBasicLitParamIsBoxName = true
|
||||
boxCall = x.Pos()
|
||||
}
|
||||
} else {
|
||||
if x.Name == ricePkgName || validVariablesForBoxes[x.Name] {
|
||||
nextIdentIsBoxFunc = true
|
||||
}
|
||||
}
|
||||
case *ast.BasicLit:
|
||||
if nextBasicLitParamIsBoxName {
|
||||
if x.Kind == token.STRING {
|
||||
nextBasicLitParamIsBoxName = false
|
||||
// trim "" or ``
|
||||
name := x.Value[1 : len(x.Value)-1]
|
||||
boxMap[name] = true
|
||||
verbosef("\tfound box %q\n", name)
|
||||
} else {
|
||||
badArgument(fset, boxCall)
|
||||
}
|
||||
}
|
||||
|
||||
default:
|
||||
if nextIdentIsBoxFunc {
|
||||
nextIdentIsBoxFunc = false
|
||||
}
|
||||
if nextBasicLitParamIsBoxName {
|
||||
badArgument(fset, boxCall)
|
||||
}
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return boxMap
|
||||
}
|
80
vendor/github.com/GeertJohan/go.rice/rice/flags.go
generated
vendored
Normal file
80
vendor/github.com/GeertJohan/go.rice/rice/flags.go
generated
vendored
Normal file
@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"os"
|
||||
|
||||
goflags "github.com/jessevdk/go-flags" // rename import to `goflags` (file scope) so we can use `var flags` (package scope)
|
||||
)
|
||||
|
||||
// flags
|
||||
var flags struct {
|
||||
Verbose bool `long:"verbose" short:"v" description:"Show verbose debug information"`
|
||||
ImportPaths []string `long:"import-path" short:"i" description:"Import path(s) to use. Using PWD when left empty. Specify multiple times for more import paths to append"`
|
||||
|
||||
Append struct {
|
||||
Executable string `long:"exec" description:"Executable to append" required:"true"`
|
||||
} `command:"append"`
|
||||
|
||||
EmbedGo struct{} `command:"embed-go" alias:"embed"`
|
||||
EmbedSyso struct{} `command:"embed-syso"`
|
||||
Clean struct{} `command:"clean"`
|
||||
}
|
||||
|
||||
// flags parser
|
||||
var flagsParser *goflags.Parser
|
||||
|
||||
// initFlags parses the given flags.
|
||||
// when the user asks for help (-h or --help): the application exists with status 0
|
||||
// when unexpected flags is given: the application exits with status 1
|
||||
func parseArguments() {
|
||||
// create flags parser in global var, for flagsParser.Active.Name (operation)
|
||||
flagsParser = goflags.NewParser(&flags, goflags.Default)
|
||||
|
||||
// parse flags
|
||||
args, err := flagsParser.Parse()
|
||||
if err != nil {
|
||||
// assert the err to be a flags.Error
|
||||
flagError := err.(*goflags.Error)
|
||||
if flagError.Type == goflags.ErrHelp {
|
||||
// user asked for help on flags.
|
||||
// program can exit successfully
|
||||
os.Exit(0)
|
||||
}
|
||||
if flagError.Type == goflags.ErrUnknownFlag {
|
||||
fmt.Println("Use --help to view available options.")
|
||||
os.Exit(1)
|
||||
}
|
||||
if flagError.Type == goflags.ErrRequired {
|
||||
os.Exit(1)
|
||||
}
|
||||
fmt.Printf("Error parsing flags: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// error on left-over arguments
|
||||
if len(args) > 0 {
|
||||
fmt.Printf("Unexpected arguments: %s\nUse --help to view available options.", args)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// default ImportPath to pwd when not set
|
||||
if len(flags.ImportPaths) == 0 {
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Printf("error getting pwd: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
verbosef("using pwd as import path\n")
|
||||
// find non-absolute path for this pwd
|
||||
pkg, err := build.ImportDir(pwd, build.FindOnly)
|
||||
if err != nil {
|
||||
fmt.Printf("error using current directory as import path: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
flags.ImportPaths = append(flags.ImportPaths, pkg.ImportPath)
|
||||
verbosef("using import paths: %s\n", flags.ImportPaths)
|
||||
return
|
||||
}
|
||||
}
|
14
vendor/github.com/GeertJohan/go.rice/rice/identifier.go
generated
vendored
Normal file
14
vendor/github.com/GeertJohan/go.rice/rice/identifier.go
generated
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"strconv"
|
||||
|
||||
"github.com/GeertJohan/go.incremental"
|
||||
)
|
||||
|
||||
var identifierCount incremental.Uint64
|
||||
|
||||
func nextIdentifier() string {
|
||||
num := identifierCount.Next()
|
||||
return strconv.FormatUint(num, 36) // 0123456789abcdefghijklmnopqrstuvwxyz
|
||||
}
|
68
vendor/github.com/GeertJohan/go.rice/rice/main.go
generated
vendored
Normal file
68
vendor/github.com/GeertJohan/go.rice/rice/main.go
generated
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/build"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// parser arguments
|
||||
parseArguments()
|
||||
|
||||
// find package for path
|
||||
var pkgs []*build.Package
|
||||
for _, importPath := range flags.ImportPaths {
|
||||
pkg := pkgForPath(importPath)
|
||||
pkgs = append(pkgs, pkg)
|
||||
}
|
||||
|
||||
// switch on the operation to perform
|
||||
switch flagsParser.Active.Name {
|
||||
case "embed", "embed-go":
|
||||
for _, pkg := range pkgs {
|
||||
operationEmbedGo(pkg)
|
||||
}
|
||||
case "embed-syso":
|
||||
log.Println("WARNING: embedding .syso is experimental..")
|
||||
for _, pkg := range pkgs {
|
||||
operationEmbedSyso(pkg)
|
||||
}
|
||||
case "append":
|
||||
operationAppend(pkgs)
|
||||
case "clean":
|
||||
for _, pkg := range pkgs {
|
||||
operationClean(pkg)
|
||||
}
|
||||
}
|
||||
|
||||
// all done
|
||||
verbosef("\n")
|
||||
verbosef("rice finished successfully\n")
|
||||
}
|
||||
|
||||
// helper function to get *build.Package for given path
|
||||
func pkgForPath(path string) *build.Package {
|
||||
// get pwd for relative imports
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
fmt.Printf("error getting pwd (required for relative imports): %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// read full package information
|
||||
pkg, err := build.Import(path, pwd, 0)
|
||||
if err != nil {
|
||||
fmt.Printf("error reading package: %s\n", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
return pkg
|
||||
}
|
||||
|
||||
func verbosef(format string, stuff ...interface{}) {
|
||||
if flags.Verbose {
|
||||
log.Printf(format, stuff...)
|
||||
}
|
||||
}
|
98
vendor/github.com/GeertJohan/go.rice/rice/templates.go
generated
vendored
Normal file
98
vendor/github.com/GeertJohan/go.rice/rice/templates.go
generated
vendored
Normal file
@ -0,0 +1,98 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var tmplEmbeddedBox *template.Template
|
||||
|
||||
func init() {
|
||||
var err error
|
||||
|
||||
// parse embedded box template
|
||||
tmplEmbeddedBox, err = template.New("embeddedBox").Parse(`package {{.Package}}
|
||||
|
||||
import (
|
||||
"github.com/GeertJohan/go.rice/embedded"
|
||||
"time"
|
||||
)
|
||||
|
||||
{{range .Boxes}}
|
||||
func init() {
|
||||
|
||||
// define files
|
||||
{{range .Files}}{{.Identifier}} := &embedded.EmbeddedFile{
|
||||
Filename: {{.FileName | printf "%q"}},
|
||||
FileModTime: time.Unix({{.ModTime}}, 0),
|
||||
Content: string({{.Content | printf "%q"}}),
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// define dirs
|
||||
{{range .Dirs}}{{.Identifier}} := &embedded.EmbeddedDir{
|
||||
Filename: {{.FileName | printf "%q"}},
|
||||
DirModTime: time.Unix({{.ModTime}}, 0),
|
||||
ChildFiles: []*embedded.EmbeddedFile{
|
||||
{{range .ChildFiles}}{{.Identifier}}, // {{.FileName | printf "%q"}}
|
||||
{{end}}
|
||||
},
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// link ChildDirs
|
||||
{{range .Dirs}}{{.Identifier}}.ChildDirs = []*embedded.EmbeddedDir{
|
||||
{{range .ChildDirs}}{{.Identifier}}, // {{.FileName | printf "%q"}}
|
||||
{{end}}
|
||||
}
|
||||
{{end}}
|
||||
|
||||
// register embeddedBox
|
||||
embedded.RegisterEmbeddedBox(` + "`" + `{{.BoxName}}` + "`" + `, &embedded.EmbeddedBox{
|
||||
Name: ` + "`" + `{{.BoxName}}` + "`" + `,
|
||||
Time: time.Unix({{.UnixNow}}, 0),
|
||||
Dirs: map[string]*embedded.EmbeddedDir{
|
||||
{{range .Dirs}}{{.FileName | printf "%q"}}: {{.Identifier}},
|
||||
{{end}}
|
||||
},
|
||||
Files: map[string]*embedded.EmbeddedFile{
|
||||
{{range .Files}}{{.FileName | printf "%q"}}: {{.Identifier}},
|
||||
{{end}}
|
||||
},
|
||||
})
|
||||
}
|
||||
{{end}}`)
|
||||
if err != nil {
|
||||
fmt.Printf("error parsing embedded box template: %s\n", err)
|
||||
os.Exit(-1)
|
||||
}
|
||||
}
|
||||
|
||||
type embedFileDataType struct {
|
||||
Package string
|
||||
Boxes []*boxDataType
|
||||
}
|
||||
|
||||
type boxDataType struct {
|
||||
BoxName string
|
||||
UnixNow int64
|
||||
Files []*fileDataType
|
||||
Dirs map[string]*dirDataType
|
||||
}
|
||||
|
||||
type fileDataType struct {
|
||||
Identifier string
|
||||
FileName string
|
||||
Content []byte
|
||||
ModTime int64
|
||||
}
|
||||
|
||||
type dirDataType struct {
|
||||
Identifier string
|
||||
FileName string
|
||||
Content []byte
|
||||
ModTime int64
|
||||
ChildDirs []*dirDataType
|
||||
ChildFiles []*fileDataType
|
||||
}
|
22
vendor/github.com/GeertJohan/go.rice/rice/util.go
generated
vendored
Normal file
22
vendor/github.com/GeertJohan/go.rice/rice/util.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"time"
|
||||
)
|
||||
|
||||
// randomString generates a pseudo-random alpha-numeric string with given length.
|
||||
func randomString(length int) string {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
k := make([]rune, length)
|
||||
for i := 0; i < length; i++ {
|
||||
c := rand.Intn(35)
|
||||
if c < 10 {
|
||||
c += 48 // numbers (0-9) (0+48 == 48 == '0', 9+48 == 57 == '9')
|
||||
} else {
|
||||
c += 87 // lower case alphabets (a-z) (10+87 == 97 == 'a', 35+87 == 122 = 'z')
|
||||
}
|
||||
k[i] = rune(c)
|
||||
}
|
||||
return string(k)
|
||||
}
|
42
vendor/github.com/GeertJohan/go.rice/rice/writecoff.go
generated
vendored
Normal file
42
vendor/github.com/GeertJohan/go.rice/rice/writecoff.go
generated
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"reflect"
|
||||
|
||||
"github.com/akavel/rsrc/binutil"
|
||||
"github.com/akavel/rsrc/coff"
|
||||
)
|
||||
|
||||
// copied from github.com/akavel/rsrc
|
||||
// LICENSE: MIT
|
||||
// Copyright 2013-2014 The rsrc Authors. (https://github.com/akavel/rsrc/blob/master/AUTHORS)
|
||||
func writeCoff(coff *coff.Coff, fnameout string) error {
|
||||
out, err := os.Create(fnameout)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
w := binutil.Writer{W: out}
|
||||
|
||||
// write the resulting file to disk
|
||||
binutil.Walk(coff, func(v reflect.Value, path string) error {
|
||||
if binutil.Plain(v.Kind()) {
|
||||
w.WriteLE(v.Interface())
|
||||
return nil
|
||||
}
|
||||
vv, ok := v.Interface().(binutil.SizedReader)
|
||||
if ok {
|
||||
w.WriteFromSized(vv)
|
||||
return binutil.WALK_SKIP
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
if w.Err != nil {
|
||||
return fmt.Errorf("Error writing output file: %s", w.Err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
19
vendor/github.com/GeertJohan/go.rice/sort.go
generated
vendored
Normal file
19
vendor/github.com/GeertJohan/go.rice/sort.go
generated
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
package rice
|
||||
|
||||
import "os"
|
||||
|
||||
// SortByName allows an array of os.FileInfo objects
|
||||
// to be easily sorted by filename using sort.Sort(SortByName(array))
|
||||
type SortByName []os.FileInfo
|
||||
|
||||
func (f SortByName) Len() int { return len(f) }
|
||||
func (f SortByName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
|
||||
func (f SortByName) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
||||
|
||||
// SortByModified allows an array of os.FileInfo objects
|
||||
// to be easily sorted by modified date using sort.Sort(SortByModified(array))
|
||||
type SortByModified []os.FileInfo
|
||||
|
||||
func (f SortByModified) Len() int { return len(f) }
|
||||
func (f SortByModified) Less(i, j int) bool { return f[i].ModTime().Unix() > f[j].ModTime().Unix() }
|
||||
func (f SortByModified) Swap(i, j int) { f[i], f[j] = f[j], f[i] }
|
252
vendor/github.com/GeertJohan/go.rice/virtual.go
generated
vendored
Normal file
252
vendor/github.com/GeertJohan/go.rice/virtual.go
generated
vendored
Normal file
@ -0,0 +1,252 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/GeertJohan/go.rice/embedded"
|
||||
)
|
||||
|
||||
//++ TODO: IDEA: merge virtualFile and virtualDir, this decreases work done by rice.File
|
||||
|
||||
// Error indicating some function is not implemented yet (but available to satisfy an interface)
|
||||
var ErrNotImplemented = errors.New("not implemented yet")
|
||||
|
||||
// virtualFile is a 'stateful' virtual file.
|
||||
// virtualFile wraps an *EmbeddedFile for a call to Box.Open() and virtualizes 'read cursor' (offset) and 'closing'.
|
||||
// virtualFile is only internally visible and should be exposed through rice.File
|
||||
type virtualFile struct {
|
||||
*embedded.EmbeddedFile // the actual embedded file, embedded to obtain methods
|
||||
offset int64 // read position on the virtual file
|
||||
closed bool // closed when true
|
||||
}
|
||||
|
||||
// create a new virtualFile for given EmbeddedFile
|
||||
func newVirtualFile(ef *embedded.EmbeddedFile) *virtualFile {
|
||||
vf := &virtualFile{
|
||||
EmbeddedFile: ef,
|
||||
offset: 0,
|
||||
closed: false,
|
||||
}
|
||||
return vf
|
||||
}
|
||||
|
||||
//++ TODO check for nil pointers in all these methods. When so: return os.PathError with Err: os.ErrInvalid
|
||||
|
||||
func (vf *virtualFile) close() error {
|
||||
if vf.closed {
|
||||
return &os.PathError{
|
||||
Op: "close",
|
||||
Path: vf.EmbeddedFile.Filename,
|
||||
Err: errors.New("already closed"),
|
||||
}
|
||||
}
|
||||
vf.EmbeddedFile = nil
|
||||
vf.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vf *virtualFile) stat() (os.FileInfo, error) {
|
||||
if vf.closed {
|
||||
return nil, &os.PathError{
|
||||
Op: "stat",
|
||||
Path: vf.EmbeddedFile.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
return (*embeddedFileInfo)(vf.EmbeddedFile), nil
|
||||
}
|
||||
|
||||
func (vf *virtualFile) readdir(count int) ([]os.FileInfo, error) {
|
||||
if vf.closed {
|
||||
return nil, &os.PathError{
|
||||
Op: "readdir",
|
||||
Path: vf.EmbeddedFile.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
//TODO: return proper error for a readdir() call on a file
|
||||
return nil, ErrNotImplemented
|
||||
}
|
||||
|
||||
func (vf *virtualFile) read(bts []byte) (int, error) {
|
||||
if vf.closed {
|
||||
return 0, &os.PathError{
|
||||
Op: "read",
|
||||
Path: vf.EmbeddedFile.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
|
||||
end := vf.offset + int64(len(bts))
|
||||
|
||||
if end >= int64(len(vf.Content)) {
|
||||
// end of file, so return what we have + EOF
|
||||
n := copy(bts, vf.Content[vf.offset:])
|
||||
vf.offset = 0
|
||||
return n, io.EOF
|
||||
}
|
||||
|
||||
n := copy(bts, vf.Content[vf.offset:end])
|
||||
vf.offset += int64(n)
|
||||
return n, nil
|
||||
|
||||
}
|
||||
|
||||
func (vf *virtualFile) seek(offset int64, whence int) (int64, error) {
|
||||
if vf.closed {
|
||||
return 0, &os.PathError{
|
||||
Op: "seek",
|
||||
Path: vf.EmbeddedFile.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
var e error
|
||||
|
||||
//++ TODO: check if this is correct implementation for seek
|
||||
switch whence {
|
||||
case os.SEEK_SET:
|
||||
//++ check if new offset isn't out of bounds, set e when it is, then break out of switch
|
||||
vf.offset = offset
|
||||
case os.SEEK_CUR:
|
||||
//++ check if new offset isn't out of bounds, set e when it is, then break out of switch
|
||||
vf.offset += offset
|
||||
case os.SEEK_END:
|
||||
//++ check if new offset isn't out of bounds, set e when it is, then break out of switch
|
||||
vf.offset = int64(len(vf.EmbeddedFile.Content)) - offset
|
||||
}
|
||||
|
||||
if e != nil {
|
||||
return 0, &os.PathError{
|
||||
Op: "seek",
|
||||
Path: vf.Filename,
|
||||
Err: e,
|
||||
}
|
||||
}
|
||||
|
||||
return vf.offset, nil
|
||||
}
|
||||
|
||||
// virtualDir is a 'stateful' virtual directory.
|
||||
// virtualDir wraps an *EmbeddedDir for a call to Box.Open() and virtualizes 'closing'.
|
||||
// virtualDir is only internally visible and should be exposed through rice.File
|
||||
type virtualDir struct {
|
||||
*embedded.EmbeddedDir
|
||||
offset int // readdir position on the directory
|
||||
closed bool
|
||||
}
|
||||
|
||||
// create a new virtualDir for given EmbeddedDir
|
||||
func newVirtualDir(ed *embedded.EmbeddedDir) *virtualDir {
|
||||
vd := &virtualDir{
|
||||
EmbeddedDir: ed,
|
||||
offset: 0,
|
||||
closed: false,
|
||||
}
|
||||
return vd
|
||||
}
|
||||
|
||||
func (vd *virtualDir) close() error {
|
||||
//++ TODO: needs sync mutex?
|
||||
if vd.closed {
|
||||
return &os.PathError{
|
||||
Op: "close",
|
||||
Path: vd.EmbeddedDir.Filename,
|
||||
Err: errors.New("already closed"),
|
||||
}
|
||||
}
|
||||
vd.closed = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (vd *virtualDir) stat() (os.FileInfo, error) {
|
||||
if vd.closed {
|
||||
return nil, &os.PathError{
|
||||
Op: "stat",
|
||||
Path: vd.EmbeddedDir.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
return (*embeddedDirInfo)(vd.EmbeddedDir), nil
|
||||
}
|
||||
|
||||
func (vd *virtualDir) readdir(n int) (fi []os.FileInfo, err error) {
|
||||
|
||||
if vd.closed {
|
||||
return nil, &os.PathError{
|
||||
Op: "readdir",
|
||||
Path: vd.EmbeddedDir.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
|
||||
// Build up the array of our contents
|
||||
var files []os.FileInfo
|
||||
|
||||
// Add the child directories
|
||||
for _, child := range vd.ChildDirs {
|
||||
child.Filename = filepath.Base(child.Filename)
|
||||
files = append(files, (*embeddedDirInfo)(child))
|
||||
}
|
||||
|
||||
// Add the child files
|
||||
for _, child := range vd.ChildFiles {
|
||||
child.Filename = filepath.Base(child.Filename)
|
||||
files = append(files, (*embeddedFileInfo)(child))
|
||||
}
|
||||
|
||||
// Sort it by filename (lexical order)
|
||||
sort.Sort(SortByName(files))
|
||||
|
||||
// Return all contents if that's what is requested
|
||||
if n <= 0 {
|
||||
vd.offset = 0
|
||||
return files, nil
|
||||
}
|
||||
|
||||
// If user has requested past the end of our list
|
||||
// return what we can and send an EOF
|
||||
if vd.offset+n >= len(files) {
|
||||
offset := vd.offset
|
||||
vd.offset = 0
|
||||
return files[offset:], io.EOF
|
||||
}
|
||||
|
||||
offset := vd.offset
|
||||
vd.offset += n
|
||||
return files[offset : offset+n], nil
|
||||
|
||||
}
|
||||
|
||||
func (vd *virtualDir) read(bts []byte) (int, error) {
|
||||
if vd.closed {
|
||||
return 0, &os.PathError{
|
||||
Op: "read",
|
||||
Path: vd.EmbeddedDir.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
return 0, &os.PathError{
|
||||
Op: "read",
|
||||
Path: vd.EmbeddedDir.Filename,
|
||||
Err: errors.New("is a directory"),
|
||||
}
|
||||
}
|
||||
|
||||
func (vd *virtualDir) seek(offset int64, whence int) (int64, error) {
|
||||
if vd.closed {
|
||||
return 0, &os.PathError{
|
||||
Op: "seek",
|
||||
Path: vd.EmbeddedDir.Filename,
|
||||
Err: errors.New("bad file descriptor"),
|
||||
}
|
||||
}
|
||||
return 0, &os.PathError{
|
||||
Op: "seek",
|
||||
Path: vd.Filename,
|
||||
Err: errors.New("is a directory"),
|
||||
}
|
||||
}
|
122
vendor/github.com/GeertJohan/go.rice/walk.go
generated
vendored
Normal file
122
vendor/github.com/GeertJohan/go.rice/walk.go
generated
vendored
Normal file
@ -0,0 +1,122 @@
|
||||
package rice
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// Walk is like filepath.Walk()
|
||||
// Visit http://golang.org/pkg/path/filepath/#Walk for more information
|
||||
func (b *Box) Walk(path string, walkFn filepath.WalkFunc) error {
|
||||
|
||||
pathFile, err := b.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer pathFile.Close()
|
||||
|
||||
pathInfo, err := pathFile.Stat()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if b.IsAppended() || b.IsEmbedded() {
|
||||
return b.walk(path, pathInfo, walkFn)
|
||||
}
|
||||
|
||||
// We don't have any embedded or appended box so use live filesystem mode
|
||||
return filepath.Walk(b.absolutePath+string(os.PathSeparator)+path, func(path string, info os.FileInfo, err error) error {
|
||||
|
||||
// Strip out the box name from the returned paths
|
||||
path = strings.TrimPrefix(path, b.absolutePath+string(os.PathSeparator))
|
||||
return walkFn(path, info, err)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
// walk recursively descends path.
|
||||
// See walk() in $GOROOT/src/pkg/path/filepath/path.go
|
||||
func (b *Box) walk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error {
|
||||
|
||||
err := walkFn(path, info, nil)
|
||||
if err != nil {
|
||||
if info.IsDir() && err == filepath.SkipDir {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
return nil
|
||||
}
|
||||
|
||||
names, err := b.readDirNames(path)
|
||||
if err != nil {
|
||||
return walkFn(path, info, err)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
|
||||
filename := filepath.Join(path, name)
|
||||
fileObject, err := b.Open(filename)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer fileObject.Close()
|
||||
|
||||
fileInfo, err := fileObject.Stat()
|
||||
if err != nil {
|
||||
if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = b.walk(filename, fileInfo, walkFn)
|
||||
if err != nil {
|
||||
if !fileInfo.IsDir() || err != filepath.SkipDir {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
}
|
||||
|
||||
// readDirNames reads the directory named by path and returns a sorted list of directory entries.
|
||||
// See readDirNames() in $GOROOT/pkg/path/filepath/path.go
|
||||
func (b *Box) readDirNames(path string) ([]string, error) {
|
||||
|
||||
f, err := b.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
stat, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !stat.IsDir() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
infos, err := f.Readdir(0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var names []string
|
||||
|
||||
for _, info := range infos {
|
||||
names = append(names, info.Name())
|
||||
}
|
||||
|
||||
sort.Strings(names)
|
||||
return names, nil
|
||||
|
||||
}
|
21
vendor/github.com/daaku/go.zipexe/license
generated
vendored
Normal file
21
vendor/github.com/daaku/go.zipexe/license
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright © 2012-2015 Carlos Castillo
|
||||
|
||||
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.
|
5
vendor/github.com/daaku/go.zipexe/readme.md
generated
vendored
Normal file
5
vendor/github.com/daaku/go.zipexe/readme.md
generated
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
go.zipexe
|
||||
=========
|
||||
|
||||
This module was taken as-is from https://github.com/cookieo9/resources-go.
|
||||
Documentation: https://godoc.org/github.com/daaku/go.zipexe
|
142
vendor/github.com/daaku/go.zipexe/zipexe.go
generated
vendored
Normal file
142
vendor/github.com/daaku/go.zipexe/zipexe.go
generated
vendored
Normal file
@ -0,0 +1,142 @@
|
||||
// Package zipexe attempts to open an executable binary file as a zip file.
|
||||
package zipexe
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"debug/elf"
|
||||
"debug/macho"
|
||||
"debug/pe"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Opens a zip file by path.
|
||||
func Open(path string) (*zip.Reader, error) {
|
||||
_, rd, err := OpenCloser(path)
|
||||
return rd, err
|
||||
}
|
||||
|
||||
// OpenCloser is like Open but returns an additional Closer to avoid leaking open files.
|
||||
func OpenCloser(path string) (io.Closer, *zip.Reader, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
finfo, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
zr, err := NewReader(file, finfo.Size())
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return file, zr, nil
|
||||
}
|
||||
|
||||
// Open a zip file, specially handling various binaries that may have been
|
||||
// augmented with zip data.
|
||||
func NewReader(rda io.ReaderAt, size int64) (*zip.Reader, error) {
|
||||
handlers := []func(io.ReaderAt, int64) (*zip.Reader, error){
|
||||
zip.NewReader,
|
||||
zipExeReaderMacho,
|
||||
zipExeReaderElf,
|
||||
zipExeReaderPe,
|
||||
}
|
||||
|
||||
for _, handler := range handlers {
|
||||
zfile, err := handler(rda, size)
|
||||
if err == nil {
|
||||
return zfile, nil
|
||||
}
|
||||
}
|
||||
return nil, errors.New("Couldn't Open As Executable")
|
||||
}
|
||||
|
||||
// zipExeReaderMacho treats the file as a Mach-O binary
|
||||
// (Mac OS X / Darwin executable) and attempts to find a zip archive.
|
||||
func zipExeReaderMacho(rda io.ReaderAt, size int64) (*zip.Reader, error) {
|
||||
file, err := macho.NewFile(rda)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var max int64
|
||||
for _, load := range file.Loads {
|
||||
seg, ok := load.(*macho.Segment)
|
||||
if ok {
|
||||
// Check if the segment contains a zip file
|
||||
if zfile, err := zip.NewReader(seg, int64(seg.Filesz)); err == nil {
|
||||
return zfile, nil
|
||||
}
|
||||
|
||||
// Otherwise move end of file pointer
|
||||
end := int64(seg.Offset + seg.Filesz)
|
||||
if end > max {
|
||||
max = end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No zip file within binary, try appended to end
|
||||
section := io.NewSectionReader(rda, max, size-max)
|
||||
return zip.NewReader(section, section.Size())
|
||||
}
|
||||
|
||||
// zipExeReaderPe treats the file as a Portable Exectuable binary
|
||||
// (Windows executable) and attempts to find a zip archive.
|
||||
func zipExeReaderPe(rda io.ReaderAt, size int64) (*zip.Reader, error) {
|
||||
file, err := pe.NewFile(rda)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var max int64
|
||||
for _, sec := range file.Sections {
|
||||
// Check if this section has a zip file
|
||||
if zfile, err := zip.NewReader(sec, int64(sec.Size)); err == nil {
|
||||
return zfile, nil
|
||||
}
|
||||
|
||||
// Otherwise move end of file pointer
|
||||
end := int64(sec.Offset + sec.Size)
|
||||
if end > max {
|
||||
max = end
|
||||
}
|
||||
}
|
||||
|
||||
// No zip file within binary, try appended to end
|
||||
section := io.NewSectionReader(rda, max, size-max)
|
||||
return zip.NewReader(section, section.Size())
|
||||
}
|
||||
|
||||
// zipExeReaderElf treats the file as a ELF binary
|
||||
// (linux/BSD/etc... executable) and attempts to find a zip archive.
|
||||
func zipExeReaderElf(rda io.ReaderAt, size int64) (*zip.Reader, error) {
|
||||
file, err := elf.NewFile(rda)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var max int64
|
||||
for _, sect := range file.Sections {
|
||||
if sect.Type == elf.SHT_NOBITS {
|
||||
continue
|
||||
}
|
||||
|
||||
// Check if this section has a zip file
|
||||
if zfile, err := zip.NewReader(sect, int64(sect.Size)); err == nil {
|
||||
return zfile, nil
|
||||
}
|
||||
|
||||
// Otherwise move end of file pointer
|
||||
end := int64(sect.Offset + sect.Size)
|
||||
if end > max {
|
||||
max = end
|
||||
}
|
||||
}
|
||||
|
||||
// No zip file within binary, try appended to end
|
||||
section := io.NewSectionReader(rda, max, size-max)
|
||||
return zip.NewReader(section, section.Size())
|
||||
}
|
27
vendor/github.com/kardianos/osext/LICENSE
generated
vendored
Normal file
27
vendor/github.com/kardianos/osext/LICENSE
generated
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2012 The Go Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21
vendor/github.com/kardianos/osext/README.md
generated
vendored
Normal file
21
vendor/github.com/kardianos/osext/README.md
generated
vendored
Normal file
@ -0,0 +1,21 @@
|
||||
### Extensions to the "os" package.
|
||||
|
||||
[](https://godoc.org/github.com/kardianos/osext)
|
||||
|
||||
## Find the current Executable and ExecutableFolder.
|
||||
|
||||
As of go1.8 the Executable function may be found in `os`. The Executable function
|
||||
in the std lib `os` package is used if available.
|
||||
|
||||
There is sometimes utility in finding the current executable file
|
||||
that is running. This can be used for upgrading the current executable
|
||||
or finding resources located relative to the executable file. Both
|
||||
working directory and the os.Args[0] value are arbitrary and cannot
|
||||
be relied on; os.Args[0] can be "faked".
|
||||
|
||||
Multi-platform and supports:
|
||||
* Linux
|
||||
* OS X
|
||||
* Windows
|
||||
* Plan 9
|
||||
* BSDs.
|
33
vendor/github.com/kardianos/osext/osext.go
generated
vendored
Normal file
33
vendor/github.com/kardianos/osext/osext.go
generated
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Extensions to the standard "os" package.
|
||||
package osext // import "github.com/kardianos/osext"
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
var cx, ce = executableClean()
|
||||
|
||||
func executableClean() (string, error) {
|
||||
p, err := executable()
|
||||
return filepath.Clean(p), err
|
||||
}
|
||||
|
||||
// Executable returns an absolute path that can be used to
|
||||
// re-invoke the current program.
|
||||
// It may not be valid after the current program exits.
|
||||
func Executable() (string, error) {
|
||||
return cx, ce
|
||||
}
|
||||
|
||||
// Returns same path as Executable, returns just the folder
|
||||
// path. Excludes the executable name and any trailing slash.
|
||||
func ExecutableFolder() (string, error) {
|
||||
p, err := Executable()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return filepath.Dir(p), nil
|
||||
}
|
9
vendor/github.com/kardianos/osext/osext_go18.go
generated
vendored
Normal file
9
vendor/github.com/kardianos/osext/osext_go18.go
generated
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
//+build go1.8,!openbsd
|
||||
|
||||
package osext
|
||||
|
||||
import "os"
|
||||
|
||||
func executable() (string, error) {
|
||||
return os.Executable()
|
||||
}
|
22
vendor/github.com/kardianos/osext/osext_plan9.go
generated
vendored
Normal file
22
vendor/github.com/kardianos/osext/osext_plan9.go
generated
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//+build !go1.8
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"os"
|
||||
"strconv"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func executable() (string, error) {
|
||||
f, err := os.Open("/proc/" + strconv.Itoa(os.Getpid()) + "/text")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer f.Close()
|
||||
return syscall.Fd2path(int(f.Fd()))
|
||||
}
|
36
vendor/github.com/kardianos/osext/osext_procfs.go
generated
vendored
Normal file
36
vendor/github.com/kardianos/osext/osext_procfs.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.8,android !go1.8,linux !go1.8,netbsd !go1.8,solaris !go1.8,dragonfly
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func executable() (string, error) {
|
||||
switch runtime.GOOS {
|
||||
case "linux", "android":
|
||||
const deletedTag = " (deleted)"
|
||||
execpath, err := os.Readlink("/proc/self/exe")
|
||||
if err != nil {
|
||||
return execpath, err
|
||||
}
|
||||
execpath = strings.TrimSuffix(execpath, deletedTag)
|
||||
execpath = strings.TrimPrefix(execpath, deletedTag)
|
||||
return execpath, nil
|
||||
case "netbsd":
|
||||
return os.Readlink("/proc/curproc/exe")
|
||||
case "dragonfly":
|
||||
return os.Readlink("/proc/curproc/file")
|
||||
case "solaris":
|
||||
return os.Readlink(fmt.Sprintf("/proc/%d/path/a.out", os.Getpid()))
|
||||
}
|
||||
return "", errors.New("ExecPath not implemented for " + runtime.GOOS)
|
||||
}
|
126
vendor/github.com/kardianos/osext/osext_sysctl.go
generated
vendored
Normal file
126
vendor/github.com/kardianos/osext/osext_sysctl.go
generated
vendored
Normal file
@ -0,0 +1,126 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// +build !go1.8,darwin !go1.8,freebsd openbsd
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var initCwd, initCwdErr = os.Getwd()
|
||||
|
||||
func executable() (string, error) {
|
||||
var mib [4]int32
|
||||
switch runtime.GOOS {
|
||||
case "freebsd":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1}
|
||||
case "darwin":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 38 /* KERN_PROCARGS */, int32(os.Getpid()), -1}
|
||||
case "openbsd":
|
||||
mib = [4]int32{1 /* CTL_KERN */, 55 /* KERN_PROC_ARGS */, int32(os.Getpid()), 1 /* KERN_PROC_ARGV */}
|
||||
}
|
||||
|
||||
n := uintptr(0)
|
||||
// Get length.
|
||||
_, _, errNum := syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, 0, uintptr(unsafe.Pointer(&n)), 0, 0)
|
||||
if errNum != 0 {
|
||||
return "", errNum
|
||||
}
|
||||
if n == 0 { // This shouldn't happen.
|
||||
return "", nil
|
||||
}
|
||||
buf := make([]byte, n)
|
||||
_, _, errNum = syscall.Syscall6(syscall.SYS___SYSCTL, uintptr(unsafe.Pointer(&mib[0])), 4, uintptr(unsafe.Pointer(&buf[0])), uintptr(unsafe.Pointer(&n)), 0, 0)
|
||||
if errNum != 0 {
|
||||
return "", errNum
|
||||
}
|
||||
if n == 0 { // This shouldn't happen.
|
||||
return "", nil
|
||||
}
|
||||
|
||||
var execPath string
|
||||
switch runtime.GOOS {
|
||||
case "openbsd":
|
||||
// buf now contains **argv, with pointers to each of the C-style
|
||||
// NULL terminated arguments.
|
||||
var args []string
|
||||
argv := uintptr(unsafe.Pointer(&buf[0]))
|
||||
Loop:
|
||||
for {
|
||||
argp := *(**[1 << 20]byte)(unsafe.Pointer(argv))
|
||||
if argp == nil {
|
||||
break
|
||||
}
|
||||
for i := 0; uintptr(i) < n; i++ {
|
||||
// we don't want the full arguments list
|
||||
if string(argp[i]) == " " {
|
||||
break Loop
|
||||
}
|
||||
if argp[i] != 0 {
|
||||
continue
|
||||
}
|
||||
args = append(args, string(argp[:i]))
|
||||
n -= uintptr(i)
|
||||
break
|
||||
}
|
||||
if n < unsafe.Sizeof(argv) {
|
||||
break
|
||||
}
|
||||
argv += unsafe.Sizeof(argv)
|
||||
n -= unsafe.Sizeof(argv)
|
||||
}
|
||||
execPath = args[0]
|
||||
// There is no canonical way to get an executable path on
|
||||
// OpenBSD, so check PATH in case we are called directly
|
||||
if execPath[0] != '/' && execPath[0] != '.' {
|
||||
execIsInPath, err := exec.LookPath(execPath)
|
||||
if err == nil {
|
||||
execPath = execIsInPath
|
||||
}
|
||||
}
|
||||
default:
|
||||
for i, v := range buf {
|
||||
if v == 0 {
|
||||
buf = buf[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
execPath = string(buf)
|
||||
}
|
||||
|
||||
var err error
|
||||
// execPath will not be empty due to above checks.
|
||||
// Try to get the absolute path if the execPath is not rooted.
|
||||
if execPath[0] != '/' {
|
||||
execPath, err = getAbs(execPath)
|
||||
if err != nil {
|
||||
return execPath, err
|
||||
}
|
||||
}
|
||||
// For darwin KERN_PROCARGS may return the path to a symlink rather than the
|
||||
// actual executable.
|
||||
if runtime.GOOS == "darwin" {
|
||||
if execPath, err = filepath.EvalSymlinks(execPath); err != nil {
|
||||
return execPath, err
|
||||
}
|
||||
}
|
||||
return execPath, nil
|
||||
}
|
||||
|
||||
func getAbs(execPath string) (string, error) {
|
||||
if initCwdErr != nil {
|
||||
return execPath, initCwdErr
|
||||
}
|
||||
// The execPath may begin with a "../" or a "./" so clean it first.
|
||||
// Join the two paths, trailing and starting slashes undetermined, so use
|
||||
// the generic Join function.
|
||||
return filepath.Join(initCwd, filepath.Clean(execPath)), nil
|
||||
}
|
36
vendor/github.com/kardianos/osext/osext_windows.go
generated
vendored
Normal file
36
vendor/github.com/kardianos/osext/osext_windows.go
generated
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
// Copyright 2012 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//+build !go1.8
|
||||
|
||||
package osext
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"unicode/utf16"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
var (
|
||||
kernel = syscall.MustLoadDLL("kernel32.dll")
|
||||
getModuleFileNameProc = kernel.MustFindProc("GetModuleFileNameW")
|
||||
)
|
||||
|
||||
// GetModuleFileName() with hModule = NULL
|
||||
func executable() (exePath string, err error) {
|
||||
return getModuleFileName()
|
||||
}
|
||||
|
||||
func getModuleFileName() (string, error) {
|
||||
var n uint32
|
||||
b := make([]uint16, syscall.MAX_PATH)
|
||||
size := uint32(len(b))
|
||||
|
||||
r0, _, e1 := getModuleFileNameProc.Call(0, uintptr(unsafe.Pointer(&b[0])), uintptr(size))
|
||||
n = uint32(r0)
|
||||
if n == 0 {
|
||||
return "", e1
|
||||
}
|
||||
return string(utf16.Decode(b[0:n])), nil
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user