Compare commits
62 Commits
0.8.71-alp
...
0.9.33-alp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
779679a809 | ||
|
|
ec49f75717 | ||
|
|
23598ce1c6 | ||
|
|
2831949814 | ||
|
|
e712e3d0e2 | ||
|
|
7df1c64740 | ||
|
|
91325f9ca3 | ||
|
|
7326325c19 | ||
|
|
59e195fa94 | ||
|
|
5ed4f8795a | ||
|
|
a02e7e66af | ||
|
|
9c1d093bb8 | ||
|
|
302877d4b4 | ||
|
|
871bb29dbe | ||
|
|
3be144f644 | ||
|
|
2560dc23fc | ||
|
|
3d6c3d10bf | ||
|
|
5f811693f1 | ||
|
|
0068fb92eb | ||
|
|
71174ead45 | ||
|
|
43c18caceb | ||
|
|
7b4c9c3154 | ||
|
|
9d2649433d | ||
|
|
6353fa7dd3 | ||
|
|
bfa837c88d | ||
|
|
bdc454e7e5 | ||
|
|
9b3e85754c | ||
|
|
af3dcc5f31 | ||
|
|
c375fb9eaf | ||
|
|
70c314229f | ||
|
|
66e23ead00 | ||
|
|
2e5666c2b6 | ||
|
|
7675656a54 | ||
|
|
3d7f7b0ad1 | ||
|
|
a1ccbd6cab | ||
|
|
33cb4ce63c | ||
|
|
aefb4497e2 | ||
|
|
0047e66f10 | ||
|
|
6bae4254af | ||
|
|
a9689993b0 | ||
|
|
8c0182b29f | ||
|
|
02d55c7143 | ||
|
|
f343b537f1 | ||
|
|
a84e7da65f | ||
|
|
f3b64387cb | ||
|
|
e132435ff8 | ||
|
|
fb492fa6f7 | ||
|
|
159714491d | ||
|
|
64cbbc70bb | ||
|
|
d0559f627e | ||
|
|
0a6784e270 | ||
|
|
b6fd3c7e98 | ||
|
|
1c05534071 | ||
|
|
3627d5bb40 | ||
|
|
1f7714c1e9 | ||
|
|
d868ebf4a1 | ||
|
|
4640379b06 | ||
|
|
922120efbb | ||
|
|
91fec99b00 | ||
|
|
2f89c1fe1f | ||
|
|
2298f39cca | ||
|
|
23d68bc27b |
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
@@ -19,8 +19,7 @@ jobs:
|
||||
|
||||
- name: lint
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint \
|
||||
golangci-lint run -v
|
||||
make lint
|
||||
|
||||
- name: unit test
|
||||
env:
|
||||
@@ -29,7 +28,7 @@ jobs:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
export KUBECONFIG="$(kind get kubeconfig-path)"
|
||||
./scripts/coverage.sh
|
||||
make unit-test
|
||||
bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}
|
||||
|
||||
- name: build fx
|
||||
@@ -43,11 +42,6 @@ jobs:
|
||||
make docker-build
|
||||
make test
|
||||
# make docker-publish #TODO in release workflow
|
||||
- name: test fx docker cloud
|
||||
run: |
|
||||
make start_docker_infra
|
||||
make test_docker_infra
|
||||
make stop_docker_infra
|
||||
|
||||
- name: test fx cli
|
||||
env:
|
||||
|
||||
18
.github/workflows/docker.yml
vendored
18
.github/workflows/docker.yml
vendored
@@ -35,10 +35,10 @@ jobs:
|
||||
docker build -t metrue/fx-d-base:latest -f ./assets/dockerfiles/base/d/Dockerfile ./assets/dockerfiles/base/d
|
||||
docker push metrue/fx-d-base:latest
|
||||
|
||||
# - name: build and publish fx java image
|
||||
# run: |
|
||||
# docker build -t metrue/fx-go-base:latest -f ./assets/dockerfiles/base/java/Dockerfile ./assets/dockerfiles/base/java
|
||||
# docker push metrue/fx-java-base:latest
|
||||
- name: build and publish fx go image
|
||||
run: |
|
||||
docker build -t metrue/fx-go-base:latest -f ./assets/dockerfiles/base/go/Dockerfile ./assets/dockerfiles/base/go
|
||||
docker push metrue/fx-go-base:latest
|
||||
|
||||
- name: build and publish fx node image
|
||||
if: always()
|
||||
@@ -57,11 +57,11 @@ jobs:
|
||||
run: |
|
||||
docker push metrue/fx-python-base:latest
|
||||
|
||||
# - name: build and publish fx rust image
|
||||
# if: always()
|
||||
# run: |
|
||||
# docker build -t metrue/fx-rust-base:latest -f ./assets/dockerfiles/base/rust/Dockerfile ./assets/dockerfiles/base/python
|
||||
# docker push metrue/fx-rust-base:latest
|
||||
- name: build and publish fx perl image
|
||||
if: always()
|
||||
run: |
|
||||
docker build -t metrue/fx-perl-base:latest -f ./assets/dockerfiles/base/perl/Dockerfile ./assets/dockerfiles/base/perl
|
||||
docker push metrue/fx-perl-base:latest
|
||||
|
||||
- name: build and publish fx julia image
|
||||
if: always()
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -33,7 +33,7 @@ jobs:
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
run: |
|
||||
export KUBECONFIG="$(kind get kubeconfig-path)"
|
||||
DEBUG=true go test -v ./...
|
||||
make unit-test
|
||||
|
||||
- name: build fx
|
||||
run: |
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
run:
|
||||
deadline: 10m
|
||||
timeout: 10m
|
||||
deadline: 20m
|
||||
timeout: 20m
|
||||
issues-exit-code: 1
|
||||
tests: true
|
||||
skip-dirs:
|
||||
- examples
|
||||
- api/images
|
||||
- test/functions
|
||||
- assets/
|
||||
- bundler/go/assets
|
||||
linters:
|
||||
enable:
|
||||
- goimports
|
||||
|
||||
@@ -32,3 +32,5 @@ brews:
|
||||
caveats: ""
|
||||
homepage: "https://github.com/metrue/fx"
|
||||
description: "fx, a simple but powerful Function as a Service build tools"
|
||||
dependencies:
|
||||
- docker
|
||||
|
||||
11
Makefile
11
Makefile
@@ -4,16 +4,17 @@ DOCKER_REMOTE_HOST_ADDR ?= "127.0.0.1"
|
||||
DOCKER_REMOTE_HOST_USER ?= $(whoami)
|
||||
|
||||
lint:
|
||||
golangci-lint run
|
||||
docker pull golangci/golangci-lint
|
||||
docker run --rm -v $(CURDIR):/app -w /app golangci/golangci-lint golangci-lint run -v
|
||||
|
||||
generate:
|
||||
packr
|
||||
|
||||
b:
|
||||
go build -o ${OUTPUT_DIR}/fx fx.go
|
||||
go build -ldflags="-s -w" -o ${OUTPUT_DIR}/fx fx.go
|
||||
|
||||
build:
|
||||
go build -o ${OUTPUT_DIR}/fx fx.go
|
||||
go build -ldflags="-s -w" -o ${OUTPUT_DIR}/fx fx.go
|
||||
|
||||
pull:
|
||||
./scripts/pull.sh
|
||||
@@ -26,13 +27,13 @@ clean:
|
||||
rm -rf ${DIST_DIR}
|
||||
|
||||
unit-test:
|
||||
./scripts/coverage.sh
|
||||
CI=true ./scripts/coverage.sh
|
||||
|
||||
cli-test-ci:
|
||||
./scripts/test_cli.sh 'js'
|
||||
|
||||
cli-test:
|
||||
./scripts/test_cli.sh 'js rb py go php java d rs'
|
||||
./scripts/test_cli.sh 'js rb py go php java d rs pl'
|
||||
|
||||
http-test:
|
||||
./scripts/http_test.sh
|
||||
|
||||
93
README.md
93
README.md
@@ -4,6 +4,7 @@ fx
|
||||
Poor man's function as a service.
|
||||
<br/>
|
||||

|
||||

|
||||
[](https://codecov.io/gh/metrue/fx)
|
||||
[](https://goreportcard.com/report/github.com/metrue/fx)
|
||||
[](http://godoc.org/github.com/metrue/fx)
|
||||
@@ -14,14 +15,11 @@ Poor man's function as a service.
|
||||
- [Introduction](#introduction)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [Manage Infrastructure](#manage-infrastructure)
|
||||
- [Contribute](#contribute)
|
||||
|
||||
|
||||
## Introduction
|
||||
|
||||

|
||||
|
||||
fx is a tool to help you do Function as a Service on your own server, fx can make your stateless function a service in seconds, both Docker host and Kubernetes cluster supported. The most exciting thing is that you can write your functions with most programming languages.
|
||||
|
||||
Feel free hacking fx to support the languages not listed. Welcome to tweet me [@_metrue](https://twitter.com/_metrue) on Twitter, [@metrue](https://www.weibo.com/u/2165714507) on Weibo.
|
||||
@@ -38,6 +36,7 @@ Feel free hacking fx to support the languages not listed. Welcome to tweet me [@
|
||||
| PHP | Supported | [@chlins](https://github.com/chlins)| [/examples/PHP](https://github.com/metrue/fx/tree/master/examples/functions/PHP) |
|
||||
| Julia | Supported | [@matbesancon](https://github.com/matbesancon)| [/examples/Julia](https://github.com/metrue/fx/tree/master/examples/functions/Julia) |
|
||||
| D | Supported | [@andre2007](https://github.com/andre2007)| [/examples/D](https://github.com/metrue/fx/tree/master/examples/functions/D) |
|
||||
| Perl | Supported | fx | [/examples/Perl](https://github.com/metrue/fx/tree/master/examples/functions/Perl) |
|
||||
| R | Working on [need your help](https://github.com/metrue/fx/issues/31) | ||
|
||||
|
||||
# Installation
|
||||
@@ -71,8 +70,6 @@ You can go the release page to [download](https://github.com/metrue/fx/releases)
|
||||
|
||||
## Usage
|
||||
|
||||
Make sure [Docker](https://docs.docker.com/engine/installation/) installed and running on your server first. then type `fx -h` on your terminal to check out basic help.
|
||||
|
||||
```
|
||||
NAME:
|
||||
fx - makes function as a service
|
||||
@@ -81,16 +78,13 @@ USAGE:
|
||||
fx [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
0.8.7
|
||||
0.9.33
|
||||
|
||||
COMMANDS:
|
||||
infra manage infrastructure
|
||||
up deploy a function
|
||||
down destroy a service
|
||||
list, ls list deployed services
|
||||
call run a function instantly
|
||||
image manage image of service
|
||||
doctor health check for fx
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
@@ -98,22 +92,40 @@ GLOBAL OPTIONS:
|
||||
--version, -v print the version
|
||||
```
|
||||
|
||||
### Deploy your function to Docker
|
||||
### Deploy function
|
||||
|
||||
#### Local Docker environment
|
||||
|
||||
By default, function will be deployed on localhost, make sure [Docker](https://docs.docker.com/engine/installation/) installed and running on your server first. then type `fx -h` on your terminal to check out basic help.
|
||||
|
||||
```
|
||||
$ fx up --name hello-fx ./examples/functions/JavaScript/func.js
|
||||
$ fx up --name hello ./examples/functions/JavaScript/func.js
|
||||
|
||||
+------------------------------------------------------------------+-----------+---------------+
|
||||
| ID | NAME | ENDPOINT |
|
||||
+------------------------------------------------------------------+-----------+---------------+
|
||||
| 5b24d36608ee392c937a61a530805f74551ddec304aea3aca2ffa0fabcf98cf3 | /hello-fx | 0.0.0.0:58328 |
|
||||
| 5b24d36608ee392c937a61a530805f74551ddec304aea3aca2ffa0fabcf98cf3 | /hello | 0.0.0.0:58328 |
|
||||
+------------------------------------------------------------------+-----------+---------------+
|
||||
```
|
||||
|
||||
### Deploy your function to Kubernetes
|
||||
#### Remote host
|
||||
|
||||
Use `--host` to specify the target host for your function,
|
||||
|
||||
```shell
|
||||
$ fx up --host roo@<your host> --name hello ./examples/functions/JavaScript/func.js
|
||||
|
||||
+------------------------------------------------------------------+-----------+---------------+
|
||||
| ID | NAME | ENDPOINT |
|
||||
+------------------------------------------------------------------+-----------+---------------+
|
||||
| 5b24d36608ee392c937a61a530805f74551ddec304aea3aca2ffa0fabcf98cf3 | /hello | 0.0.0.0:58345 |
|
||||
+------------------------------------------------------------------+-----------+---------------+
|
||||
```
|
||||
|
||||
#### Kubernetes
|
||||
|
||||
```
|
||||
$ KUBECONFIG=~/.kube/config ./build/fx up examples/functions/JavaScript/func.js --name hello-fx
|
||||
$ FX_KUBECONF=~/.kube/config fx up examples/functions/JavaScript/func.js --name hello
|
||||
|
||||
+-------------------------------+------+----------------+
|
||||
| ID | NAME | ENDPOINT |
|
||||
@@ -122,7 +134,7 @@ $ KUBECONFIG=~/.kube/config ./build/fx up examples/functions/JavaScript/func.js
|
||||
+------------------------+-------------+----------------+
|
||||
```
|
||||
|
||||
### Test your service
|
||||
### Test service
|
||||
|
||||
then you can test your service:
|
||||
|
||||
@@ -149,31 +161,6 @@ hello world
|
||||
|
||||
```
|
||||
|
||||
## Manage Infrastructure
|
||||
|
||||
**fx** is originally designed to turn a function into a runnable Docker container in a easiest way, on a host with Docker running, you can just deploy your function with `fx up` command, and now **fx** supports deploy function to be a service onto Kubernetes cluster infrasture, and we encourage you to do that other than on bare Docker environment, there are lots of advantage to run your function on Kubernetes like self-healing, load balancing, easy horizontal scaling, etc. It's pretty simple to deploy your function onto Kubernetes with **fx**, you just set KUBECONFIG in your enviroment.
|
||||
|
||||
By default. **fx** use localhost as target infrastructure to run your service, and you can also setup your remote virtual machines as **fx**'s infrastructure and deploy your functions onto it.
|
||||
|
||||
### `fx infra create`
|
||||
|
||||
You can create types (docker and k8s) of infrastructures for **fx** to deploy functions
|
||||
|
||||
```shell
|
||||
$ fx infra create --name infra_us --type docker --host <user>@<ip> ## create docker type infrasture on <ip>
|
||||
$ fx infra create --name infra_bj --type k8s --master <user>@<ip> --agents '<user1>@<ip1>,<user2>@<ip2>' ## create k8s type infrasture use <ip> as master node, and <ip1> and <ip2> as agents nodes
|
||||
```
|
||||
|
||||
### `fx infra use`
|
||||
|
||||
To use a infrastructure, you can use `fx infra use` command to activate it.
|
||||
|
||||
```shell
|
||||
fx infra use <infrastructure name>
|
||||
```
|
||||
|
||||
and you can list your infrastructure with `fx infra list`
|
||||
|
||||
## Use Public Cloud Kubernetes Service as infrastructure to run your functions
|
||||
|
||||
* Azure Kubernetes Service (AKS)
|
||||
@@ -198,7 +185,7 @@ aks-nodepool1-31718369-0 Ready agent 6m44s v1.12.8
|
||||
Since AKS's config will be merged into `~/.kube/config` and set to be current context after you run `az aks get-credentials` command, so you can just set KUBECONFIG to default config also,
|
||||
|
||||
```shell
|
||||
$ export KUBECONFIG=~/.kube/config # then fx will take the config to deloy function
|
||||
$ export FX_KUBECONF=~/.kube/config # then fx will take the config to deloy function
|
||||
```
|
||||
|
||||
But we would suggest you run `kubectl config current-context` to check if the current context is what you want.
|
||||
@@ -206,13 +193,29 @@ But we would suggest you run `kubectl config current-context` to check if the cu
|
||||
* Amazon Elastic Kubernetes Service (EKS)
|
||||
TODO
|
||||
|
||||
* Google Kubernetes Engine (GKET)
|
||||
TODO
|
||||
* Google Kubernetes Engine (GKE)
|
||||
|
||||
First you should create a Kubernetes cluster in your GKE, then make sure your KUBECONFIG is ready in `~/.kube/config`, if not, you can run following commands,
|
||||
|
||||
``` shell
|
||||
$ gcloud auth login
|
||||
$ gcloud container clusters get-credentials <your cluster> --zone <zone> --project <project>
|
||||
```
|
||||
|
||||
Then make sure you current context is GKE cluster, you can check it with command,
|
||||
|
||||
``` shell
|
||||
$ kubectl config current-context
|
||||
```
|
||||
|
||||
Then you can deploy your function onto GKE cluster with,
|
||||
|
||||
```shell
|
||||
$ FX_KUBECONF=~/.kube/config fx up examples/functions/JavaScript/func.js --name hellojs
|
||||
```
|
||||
|
||||
* Setup your own Kubernetes cluster
|
||||
|
||||

|
||||
|
||||
```shell
|
||||
fx infra create --type k3s --name fx-cluster-1 --master root@123.11.2.3 --agents 'root@1.1.1.1,root@2.2.2.2'
|
||||
```
|
||||
|
||||
4
assets/dockerfiles/base/go/Dockerfile
vendored
Normal file
4
assets/dockerfiles/base/go/Dockerfile
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM golang:latest
|
||||
|
||||
# dependency management
|
||||
RUN go get github.com/gin-gonic/gin
|
||||
26
assets/dockerfiles/base/node/package-lock.json
generated
vendored
Normal file
26
assets/dockerfiles/base/node/package-lock.json
generated
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "fx-node-base",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"@koa/cors": {
|
||||
"version": "2.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@koa/cors/-/cors-2.2.3.tgz",
|
||||
"integrity": "sha512-tCVVXa39ETsit5kGBtEWWimjLn1sDaeu8+0phgb8kT3GmBDZOykkI3ZO8nMjV2p3MGkJI4K5P+bxR8Ztq0bwsA==",
|
||||
"requires": {
|
||||
"vary": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
|
||||
"integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
|
||||
},
|
||||
"vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
}
|
||||
}
|
||||
}
|
||||
9
assets/dockerfiles/base/node/package.json
vendored
9
assets/dockerfiles/base/node/package.json
vendored
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"name": "aok",
|
||||
"name": "fx-node-base",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
@@ -10,12 +10,11 @@
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@koa/cors": "^2.2.3",
|
||||
"get-port": "^3.2.0",
|
||||
"is-generator-function": "^1.0.6",
|
||||
"koa": "^2.3.0",
|
||||
"koa-bodyparser": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"get-port-cli": "^1.1.0"
|
||||
"koa-bodyparser": "^4.2.0",
|
||||
"node-fetch": "^2.6.0"
|
||||
}
|
||||
}
|
||||
|
||||
10
assets/dockerfiles/base/perl/Dockerfile
vendored
Normal file
10
assets/dockerfiles/base/perl/Dockerfile
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
FROM alpine:3.4
|
||||
MAINTAINER Mojolicious
|
||||
|
||||
ADD . .
|
||||
COPY cpanfile /
|
||||
ENV EV_EXTRA_DEFS -DEV_NO_ATFORK
|
||||
|
||||
RUN apk update && \
|
||||
apk add perl perl-io-socket-ssl perl-dbd-pg perl-dev g++ make wget curl && \
|
||||
curl -L https://cpanmin.us | perl - App::cpanminus && cpanm --installdeps . -M https://cpan.metacpan.org
|
||||
3
assets/dockerfiles/base/perl/cpanfile
vendored
Normal file
3
assets/dockerfiles/base/perl/cpanfile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
requires "EV";
|
||||
requires "JSON";
|
||||
requires "Mojolicious::Lite";
|
||||
3
assets/dockerfiles/base/ruby/Dockerfile
vendored
Normal file
3
assets/dockerfiles/base/ruby/Dockerfile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM ruby:latest
|
||||
|
||||
RUN gem install sinatra
|
||||
44
bundle/bundle.go
Normal file
44
bundle/bundle.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/metrue/fx/bundler"
|
||||
"github.com/metrue/fx/bundler/d"
|
||||
golang "github.com/metrue/fx/bundler/go"
|
||||
"github.com/metrue/fx/bundler/java"
|
||||
"github.com/metrue/fx/bundler/julia"
|
||||
"github.com/metrue/fx/bundler/node"
|
||||
"github.com/metrue/fx/bundler/perl"
|
||||
"github.com/metrue/fx/bundler/python"
|
||||
"github.com/metrue/fx/bundler/ruby"
|
||||
"github.com/metrue/fx/bundler/rust"
|
||||
)
|
||||
|
||||
// Bundle function to project
|
||||
func Bundle(workdir string, language string, fn string, deps ...string) error {
|
||||
var bundler bundler.Bundler
|
||||
switch language {
|
||||
case "d":
|
||||
bundler = d.New()
|
||||
case "node":
|
||||
bundler = node.New()
|
||||
case "go":
|
||||
bundler = golang.New()
|
||||
case "java":
|
||||
bundler = java.New()
|
||||
case "julia":
|
||||
bundler = julia.New()
|
||||
case "perl":
|
||||
bundler = perl.New()
|
||||
case "python":
|
||||
bundler = python.New()
|
||||
case "ruby":
|
||||
bundler = ruby.New()
|
||||
case "rust":
|
||||
bundler = rust.New()
|
||||
default:
|
||||
return fmt.Errorf("%s not suppported yet", language)
|
||||
}
|
||||
return bundler.Bundle(workdir, fn, deps...)
|
||||
}
|
||||
117
bundle/bundler_test.go
Normal file
117
bundle/bundler_test.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func createFn(content string, t *testing.T) string {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
return fd.Name()
|
||||
}
|
||||
|
||||
func TestBundle(t *testing.T) {
|
||||
workdir, err := ioutil.TempDir("", "fx-test")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(workdir)
|
||||
|
||||
cases := []struct {
|
||||
workdir string
|
||||
language string
|
||||
fn string
|
||||
deps []string
|
||||
}{
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "d",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "go",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "java",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "julia",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "perl",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "python",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "ruby",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
{
|
||||
workdir: workdir,
|
||||
language: "rust",
|
||||
fn: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
fn := createFn(c.fn, t)
|
||||
defer os.Remove(fn)
|
||||
|
||||
if err := Bundle(c.workdir, c.language, fn, c.deps...); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
88
bundler/bundler.go
Normal file
88
bundler/bundler.go
Normal file
@@ -0,0 +1,88 @@
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/gobuffalo/packd"
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/constants"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Bundler defines interface
|
||||
type Bundler interface {
|
||||
Scaffold(output string) error
|
||||
Bundle(output string, fn string, deps ...string) error
|
||||
}
|
||||
|
||||
// IsHandler check if it's handle file
|
||||
func IsHandler(name string, lang string) bool {
|
||||
basename := filepath.Base(name)
|
||||
nameWithoutExt := strings.TrimSuffix(basename, filepath.Ext(basename))
|
||||
if constants.ExtLangMapping[filepath.Ext(basename)] != lang {
|
||||
return false
|
||||
}
|
||||
|
||||
return (nameWithoutExt == "fx" ||
|
||||
// Fx is for Java
|
||||
nameWithoutExt == "Fx" ||
|
||||
// mod.rs is for Rust)
|
||||
nameWithoutExt == "mod")
|
||||
}
|
||||
|
||||
// Restore directory from packr box
|
||||
func Restore(box *packr.Box, output string) error {
|
||||
if err := box.Walk(func(name string, fd packd.File) error {
|
||||
content, err := box.Find(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dest := filepath.Join(output, name)
|
||||
if err := utils.EnsureFile(dest); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(dest, content, 0644); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bundle bundle a function
|
||||
func Bundle(box *packr.Box, output string, language string, fn string, deps ...string) error {
|
||||
if err := Restore(box, output); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := utils.Merge(output, deps...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Replace the default handler source file with given function source file
|
||||
if err := filepath.Walk(output, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if IsHandler(path, language) {
|
||||
if err := utils.CopyFile(fn, path); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
51
bundler/bundler_test.go
Normal file
51
bundler/bundler_test.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
)
|
||||
|
||||
func TestBundler(t *testing.T) {
|
||||
t.Run("Restore", func(t *testing.T) {
|
||||
box := packr.New("", "./node/assets")
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
if err := Restore(box, outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("Bundle", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}`
|
||||
if err = ioutil.WriteFile(fd.Name(), []byte(content), 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
box := packr.New("", "./node/assets")
|
||||
if err := Bundle(box, outputDir, "node", fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
8
bundler/d/d-packr.go
Normal file
8
bundler/d/d-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package d
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/d/packrd"
|
||||
32
bundler/d/d.go
Normal file
32
bundler/d/d.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package d
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// D defines d bundler
|
||||
type D struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *D {
|
||||
return &D{
|
||||
assets: packr.New("d", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (d *D) Scaffold(output string) error {
|
||||
return bundler.Restore(d.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (d *D) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(d.assets, output, "d", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &D{}
|
||||
)
|
||||
35
bundler/d/packrd/packed-packr.go
Normal file
35
bundler/d/packrd/packed-packr.go
Normal file
File diff suppressed because one or more lines are too long
@@ -1,11 +1,8 @@
|
||||
FROM golang:latest
|
||||
FROM metrue/fx-go-base
|
||||
|
||||
COPY . /go/src/github.com/metrue/fx
|
||||
WORKDIR /go/src/github.com/metrue/fx
|
||||
|
||||
# dependency management
|
||||
RUN go get github.com/gin-gonic/gin
|
||||
|
||||
RUN go build -ldflags "-w -s" -o fx fx.go app.go
|
||||
|
||||
EXPOSE 3000
|
||||
32
bundler/go/go.go
Normal file
32
bundler/go/go.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Gin defines javascript bundler
|
||||
type Gin struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Gin {
|
||||
return &Gin{
|
||||
assets: packr.New("go", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (g *Gin) Scaffold(output string) error {
|
||||
return bundler.Restore(g.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (g *Gin) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(g.assets, output, "go", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Gin{}
|
||||
)
|
||||
143
bundler/go/go_test.go
Normal file
143
bundler/go/go_test.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestKoaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
koa := New()
|
||||
if err := koa.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
koa := New()
|
||||
if err := koa.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/fx.go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/fx.go")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
koa := New()
|
||||
if err := koa.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
8
bundler/go/golang-packr.go
Normal file
8
bundler/go/golang-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package golang
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/go/packrd"
|
||||
33
bundler/go/packrd/packed-packr.go
Normal file
33
bundler/go/packrd/packed-packr.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "449af63614707e60b8b2ffe119b470cf"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"76eca10e3a22b8409f5af0b284f82ee4": "1f8b08000000000000ff7ccabdaac2301407f0fd3cc59fec490af711da5e10a929115111877ee5586839a569318fefe6e8fefbf7aec23c6ceb3ed890348b6e9b3810e5aebec3c0b2d8b87696c7edb5b7a693d97e315d9d3f1607ff1b91bf9cc082761fa71e7aeac3d47084d26fe8a8a005212124c38266590c0b5179abddb9c45f9665447955e0a18c0d493de9130000ffff44ef0fc1ae000000",
|
||||
"cf8b44c6431c48afd768cf293ee38cab": "1f8b08000000000000ff4c8cc1aac2301045d799af98975502efa585b7ab74a7b854d41f88218983edb40c0d08d27f9766e5eede03e7cc3e3c7d8e387a62001ae7491634a074a6e551ee2e4c639389fff2c414b6a5c102a4c2a12ac6e21b9460d7632676fb987c19166341893b1e6e4637fa17d3abfef3e9fa0d2861946a8abb1436bafb6fdb56db5dc53f3d320d5b5ccd9e2998286241adb0c2270000ffff1428eddcb3000000",
|
||||
"da1f5928cfe751551db26cc0459d944e": "1f8b08000000000000ff14c9b10e82301000d0b9f715974e601089a3ab8b71d0c12fa8b5948bed1d81233621fcbb617bc91b9dffba18303b6200caa34c8a36920ecbbbf5924f91f81885c9efb200fdc21efb52792d7888c4ed555843d11a57305e4b7b7f3d1fd5b9eb1adcf7b682313687797631d80bda21a424f893297d6c0366ab61837f000000ffffe12418cf85000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("go", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "76eca10e3a22b8409f5af0b284f82ee4"})
|
||||
b.SetResolver("app.go", packr.Pointer{ForwardBox: gk, ForwardPath: "cf8b44c6431c48afd768cf293ee38cab"})
|
||||
b.SetResolver("fx.go", packr.Pointer{ForwardBox: gk, ForwardPath: "da1f5928cfe751551db26cc0459d944e"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
8
bundler/java/java-packr.go
Normal file
8
bundler/java/java-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package java
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/java/packrd"
|
||||
32
bundler/java/java.go
Normal file
32
bundler/java/java.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Java defines javascript bundler
|
||||
type Java struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Java {
|
||||
return &Java{
|
||||
assets: packr.New("java", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Java) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Java) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, "java", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Java{}
|
||||
)
|
||||
155
bundler/java/java_test.go
Normal file
155
bundler/java/java_test.go
Normal file
@@ -0,0 +1,155 @@
|
||||
package java
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestJavaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_java")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
java := New()
|
||||
if err := java.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.java")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `package fx;
|
||||
|
||||
import io.javalin.Javalin;
|
||||
import org.json.JSONObject;
|
||||
|
||||
public class app {
|
||||
public static void main(String[] args) {
|
||||
Javalin app = Javalin.start(3000);
|
||||
Fx handler = new Fx();
|
||||
app.post("/", ctx -> {
|
||||
JSONObject obj = new JSONObject(ctx.body());
|
||||
ctx.result(""+handler.handle(obj));
|
||||
});
|
||||
}
|
||||
}
|
||||
`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_java")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
java := New()
|
||||
if err := java.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/src/main/java/fx/Fx.java")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/src/main/java/fx/Fx.java")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_java")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
java := New()
|
||||
if err := java.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
35
bundler/java/packrd/packed-packr.go
Normal file
35
bundler/java/packrd/packed-packr.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "472df26e20796ab2f7966f2dbcce8ee2"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"3ce2296391d96d76aaff2d829f1f612d": "1f8b08000000000000ff4c4fb16ec32014dcf98a274f586da9a58e563a66c8d00c19ab0e0f4c5d2801042f2955e57faf9c10c7b71cdc9dee20a2fac651c367e91933c718128109c2e2199df16277e5fe6685340a9b8317bbc3fe6d2fad56d433164fd21905ca61ce8031c21f0300a8722624a3e01ccc0047349e1f28193fbe7f00a631b7353ca3ae5d2a36b79bc88489f84bd7756dbf44b705bed00f4e27d880d73fb02d7c65638c22864cbc796e1e415181a7d7d5d0656cf90104696bcb5de48a8a9061f8e5edaa77c66c249d4f8e78d33cd457882bf320ed3a3fd5f3c426f61f0000ffff88067e0e6b010000",
|
||||
"74b2f70d9674f4e1a69013f26355fca9": "1f8b08000000000000ff8c55516fdb20107ecfafb0fc1eb0bb4aab2a4a1f264daad46ad3d64d7bab6ef8ec90da808024debf9f0c4e63c775dc3c85fb3eeebeef8033bb6f9b3ad9a37552abbb3427599aa012ba90aaba4b7f3d7f5ddfa4f77cc58cd55b143e699b5ab9bb74e3bdb9a5b4813d2a0206c40689b615fdfeed895e93accb1298b7ad936fecc3e1400e9f02ef2acb72fae7e9f1a7d860036ba99c0725305d254992b44edeba003c6a013e085b2c98cc314260bdbf7ec95e32d2ba22e5a1086b7481f5ef689c87148c8e62915659bd330f05d7b622ce58a9aad24283076d5f193d82910ad6cb12847f2878d9aec198f516f6c0e8201e8906c42b5452557c0b96d1d332c2fd69f08ce49da8e37215d1bf3b59f78962b27a5749e54e9141741c9cf8e9bb145bd6e7393335da3b3012bbea3650e03aee9cfa1ced3dbab822f9c0d284862d8a5d77e46e0a8e09efe3d1fc061cf2d85664342ee7e995867aa6dc88c3835d46c3fff97474211f135a95b2da59b86c2370bd05e54a6d1bb40b12cfe98be4ee271b536383caf7cf6cee5690609d58747a6705922750b244e77ff481e753dd74596690da80545f6a708e972d0163183d45968dd281d38516d28ff590d10f9c0ba317eedf003c7f8ef4fc3d1e233d91d1c1b3ee86ad41eb250ed2b0781e423746d66849ec3bbf61f47d6076a3075ba17f67630fac82b8910256a04155a01293c0bfb3312935e9865eddcd83d9e9f8c6984cc6e360c8497e3627181dd79c97d0dde1add317050478b6fa55967fceb3fce6b2003aee4a685af78de4abff010000ffff2998100355070000",
|
||||
"9d097ccc5e31491bd2ee70619fc36101": "1f8b08000000000000ff74cbc1aac2301005d07dbe62e82ae1417ea0bced83be855df40b26718ca97512922914a4ff2ed282a87897f79e9bd15f30109c9656a978cda908a412ec5813dbffa13ff46e242fad52797653f4e027ac15fe16b8290080bd8d2c70463e4ea49f27889c6731bb7c6490123900c2efb6d940a21b6c8c95b46ddab4efdabd6af7451792b930742c14a8d88ca552c7a2d1c0cf67ebf6e7aa56750f0000ffffeb12798604010000",
|
||||
"bde0ba82beaa4757c20608eb0bcc46bd": "1f8b08000000000000ff2ccecf4a033110c7f17b9e6288d7661351c46b71ebad562a82507a984da64bd2e60f93ece2e3cbae3dcde1cbfcf8bc1f0f7b88d478227df955016754035612e201b6cef93442cd135bda80cdb1f81b01260705ed1547029f5a06840b3608c862dbf750d982b6d991ae6cc5f1fb034e32ce496e40debfe45988ddcfe7e16b074fc618f1b6efe124f55459dffca0c31cf5ea7855b9500aeeaa30ba97673df8b486654a05e4e536e491da42c752fef9a67bec4cb7f4b3f80b0000ffff3eecd9bedf000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("java", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "bde0ba82beaa4757c20608eb0bcc46bd"})
|
||||
b.SetResolver("pom.xml", packr.Pointer{ForwardBox: gk, ForwardPath: "74b2f70d9674f4e1a69013f26355fca9"})
|
||||
b.SetResolver("src/main/java/fx/Fx.java", packr.Pointer{ForwardBox: gk, ForwardPath: "9d097ccc5e31491bd2ee70619fc36101"})
|
||||
b.SetResolver("src/main/java/fx/app.java", packr.Pointer{ForwardBox: gk, ForwardPath: "3ce2296391d96d76aaff2d829f1f612d"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
8
bundler/julia/julia-packr.go
Normal file
8
bundler/julia/julia-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package julia
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/julia/packrd"
|
||||
32
bundler/julia/julia.go
Normal file
32
bundler/julia/julia.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package julia
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Julia defines javascript bundler
|
||||
type Julia struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Julia {
|
||||
return &Julia{
|
||||
assets: packr.New("julia", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Julia) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, "julia", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Julia{}
|
||||
)
|
||||
148
bundler/julia/julia_test.go
Normal file
148
bundler/julia/julia_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package julia
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestJuliaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.julia")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
end
|
||||
|
||||
fx = function(input::Input)
|
||||
return input.a + input.b
|
||||
end
|
||||
`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle function should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/fx.jl")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/fx.jl")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
37
bundler/julia/packrd/packed-packr.go
Normal file
37
bundler/julia/packrd/packed-packr.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "9e78c349d756cf23066df37690663267"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"17bc9961cffa014e8d7ac818d8a3ec14": "1f8b08000000000000ff4c8fc16ac3300c86ef7e8a9f9e6c2826b09d0a39edb2edb08d959dc61866515a975449243bf4f18793a69bc020ebe3d36f678d7cc0634ac39e642231f13cf492f0bc7f7d59fb0f3e07d163e88c89fcd3e586eca6bdf853b771c6a84ca8b1c8d6a1e92134ee76ef3466d2b48590969b0e3d2b1900882d3ae2433a5aa1d137210587ba4635c35242ea3585941535eeab055077d54b0d41949aefe2a29edfeadfca48fc4ceca98f6c3f1f8e41ece4d0f6820991b1e67d39775b75dd71fba3cf6b679f78c869fb3fec4fd324910fb6bdd879be00e2c6946324b35599b6b8abaaca99df000000ffffa9ee463365010000",
|
||||
"516dab4c6ff105b6210ce90d2afa826f": "1f8b08000000000000ff2a2e292a4d2e51f0cc2b282de15250505048b4b2f22bcd4d4a2d02f392e0bcd4bc142eaeb40a055b85b4d2bce492ccfc3c8d4c90262b2bb05e4db0f2a2d492d2a23c05b0845ea28236949504d60d080000ffff662990f46b000000",
|
||||
"b4a52bf8c0e242a9573eebd6bd5881fd": "1f8b08000000000000ff4ccd31cbc2301080e1fd7ec54dddd206bee103d75ab7da5211743c9b5053cf723417417fbd98415c9fe17d7743d7e29c38d0c696ff0075d79fb1c48a440086e31e49d44c5e318923f558145f094b546246f3c4691c33270d1c312daf2078a79b470e97abaa18a135fad538ffc8d13ccc93ca7989e5cc0075bbfd7512f97073eabb43837fd65a78070000ffff383c868aac000000",
|
||||
"c85770f1f90561b2df722b26d344976a": "1f8b08000000000000ff14c9310ac3300c46e1593a85f0642fcd093a06da2d0df4002ebf5c4c832de4f4fec1c35bded74d5b0c4b365bf6f5f57eee6b48822e85096a43eee29a71d4a62396c454ba0ba43699ca44dbef7bcb404462d2069ecdf7f9d703313cced3b6ec433d24be020000ffff9afc26056c000000",
|
||||
"ccfa88310f9e4f3419a50e352a228292": "1f8b08000000000000fff228292908482c2a4e2de2023183538bca528bb8bc82fdfdb842f372138b8a33127300010000ffffd7a8f0a324000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("julia", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "b4a52bf8c0e242a9573eebd6bd5881fd"})
|
||||
b.SetResolver("REQUIRE", packr.Pointer{ForwardBox: gk, ForwardPath: "ccfa88310f9e4f3419a50e352a228292"})
|
||||
b.SetResolver("app.jl", packr.Pointer{ForwardBox: gk, ForwardPath: "17bc9961cffa014e8d7ac818d8a3ec14"})
|
||||
b.SetResolver("deps.jl", packr.Pointer{ForwardBox: gk, ForwardPath: "c85770f1f90561b2df722b26d344976a"})
|
||||
b.SetResolver("fx.jl", packr.Pointer{ForwardBox: gk, ForwardPath: "516dab4c6ff105b6210ce90d2afa826f"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
@@ -1,8 +1,12 @@
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const cors = require('@koa/cors');
|
||||
const fx = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(cors({
|
||||
origin: '*',
|
||||
}));
|
||||
app.use(bodyParser());
|
||||
app.use(fx);
|
||||
|
||||
8
bundler/node/node-packr.go
Normal file
8
bundler/node/node-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package node
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/node/packrd"
|
||||
34
bundler/node/node.go
Normal file
34
bundler/node/node.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
const language = "node"
|
||||
|
||||
// Node defines node bundler
|
||||
type Node struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Node {
|
||||
return &Node{
|
||||
assets: packr.New("node", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Node) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Node) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, language, fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Node{}
|
||||
)
|
||||
143
bundler/node/node_test.go
Normal file
143
bundler/node/node_test.go
Normal file
@@ -0,0 +1,143 @@
|
||||
package node
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestNodeBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
koa := New()
|
||||
if err := koa.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello fx'
|
||||
}`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
koa := New()
|
||||
if err := koa.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/fx.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/fx.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_koa")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
koa := New()
|
||||
if err := koa.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
33
bundler/node/packrd/packed-packr.go
Normal file
33
bundler/node/packrd/packed-packr.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "099a799bb033d71a85f319790ea9425b"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"06d0f22f31cc0848f733e8dcaa11962c": "1f8b08000000000000ffcacd4f29cd49d54bad28c82f2a2956b055d0482ea9d054b0b553a8e65250482ea9d04bca4fa954b05550cf48cdc9c95728cf2fca4951e7aae502040000ffff4a686e4639000000",
|
||||
"2c75a41a4116ea4ba707c129527fd11c": "1f8b08000000000000ff5c8ec10ac2301044eff98abd25116d0bde2c05ef5efc8558b7122ad9b869b122febbac0a091e67de63989e429ae0400e3a60bccd9ed1e8919cb6adfab2139d1f47c709f94fd908891f92ed9e3895de7e24574b9995612985aa1e16613fe862840e02dee593b1ad7231567342231be6a90088fdc5871de8955eab972d94fcd494f5b0c8bca4ab4f1306b36d9ac6b6ea1d0000ffffc9e8e169fb000000",
|
||||
"98bb98a34bd158dd2fdd41ca90f4e64d": "1f8b08000000000000ff720bf2f755c84d2d292a4dd54fabd0cdcb4f49d54d4a2c4ee5e272f60f8854d053d0e3728d08f00f765530363030e072f67551885602a952d251504a2c28d0cb2a568ae502040000ffff6c95391846000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("node", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "98bb98a34bd158dd2fdd41ca90f4e64d"})
|
||||
b.SetResolver("app.js", packr.Pointer{ForwardBox: gk, ForwardPath: "2c75a41a4116ea4ba707c129527fd11c"})
|
||||
b.SetResolver("fx.js", packr.Pointer{ForwardBox: gk, ForwardPath: "06d0f22f31cc0848f733e8dcaa11962c"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
6
bundler/perl/assets/Dockerfile
Normal file
6
bundler/perl/assets/Dockerfile
Normal file
@@ -0,0 +1,6 @@
|
||||
FROM metrue/fx-perl-base
|
||||
|
||||
ADD . .
|
||||
|
||||
EXPOSE 3000
|
||||
CMD ["perl", "app.pl", "daemon"]
|
||||
17
bundler/perl/assets/app.pl
Normal file
17
bundler/perl/assets/app.pl
Normal file
@@ -0,0 +1,17 @@
|
||||
use Mojolicious::Lite;
|
||||
|
||||
require "./fx.pl";
|
||||
|
||||
get '/' => sub {
|
||||
my $ctx = shift;
|
||||
my $res = fx($ctx);
|
||||
$ctx->render(json => $res);
|
||||
};
|
||||
|
||||
post '/' => sub {
|
||||
my $ctx = shift;
|
||||
my $res = fx($ctx);
|
||||
$ctx->render(json => $res);
|
||||
};
|
||||
|
||||
app->start;
|
||||
6
bundler/perl/assets/fx.pl
Normal file
6
bundler/perl/assets/fx.pl
Normal file
@@ -0,0 +1,6 @@
|
||||
sub fx {
|
||||
my $ctx = shift;
|
||||
return 'hello fx'
|
||||
}
|
||||
|
||||
1;
|
||||
33
bundler/perl/packrd/packed-packr.go
Normal file
33
bundler/perl/packrd/packed-packr.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "77d2d2753a1e41552ea722fb94d9bca6"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"2e6c11f0e86d189a5f33d2eda0bc7406": "1f8b08000000000000ff720bf2f755c84d2d292a4dd54fabd02d482dcad14d4a2c4ee5e272747151d053d0e3e2728d08f00f765530363030e072f67551885602a952d251504a2c28d02b00b352125373f3f39462b900010000ffff0583b6ed50000000",
|
||||
"b3a2e75d2833aa5c271d28326dee512c": "1f8b08000000000000ff2a2e4d5248ab50a8e65250c8ad5450492ea950b05528cec84c2bb1e65250284a2d292dca5350cf48cdc9c95748ab50e7aae5e232b4e602040000ffffd1aa6a1336000000",
|
||||
"cd2f2d8e12b35147ad2b9cb35d65d3ab": "1f8b08000000000000ffb48c41aa83401044f77d8a423ea80b75efa027f83984316d32629c49770f1842ee1e067285ec8a578f9794710a6bd8fcec43d2befff7c68e48f891bc308ab65b8e366e8523bab2a1ec4a0c23349df122e0fec4df6c0706e8cd2fe6be4858316039aa7cd699e6d18cc2fb85a55a35ecb992bddad1db11c5a0bf8b4f3136a3da24e6e8130000ffff6c5481b5f1000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("perl", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "2e6c11f0e86d189a5f33d2eda0bc7406"})
|
||||
b.SetResolver("app.pl", packr.Pointer{ForwardBox: gk, ForwardPath: "cd2f2d8e12b35147ad2b9cb35d65d3ab"})
|
||||
b.SetResolver("fx.pl", packr.Pointer{ForwardBox: gk, ForwardPath: "b3a2e75d2833aa5c271d28326dee512c"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
8
bundler/perl/perl-packr.go
Normal file
8
bundler/perl/perl-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package perl
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/perl/packrd"
|
||||
32
bundler/perl/perl.go
Normal file
32
bundler/perl/perl.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package perl
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Julia defines javascript bundler
|
||||
type Julia struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Julia {
|
||||
return &Julia{
|
||||
assets: packr.New("perl", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Julia) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, "perl", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Julia{}
|
||||
)
|
||||
148
bundler/perl/perl_test.go
Normal file
148
bundler/perl/perl_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package perl
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestJuliaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.julia")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
end
|
||||
|
||||
fx = function(input::Input)
|
||||
return input.a + input.b
|
||||
end
|
||||
`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle function should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/fx.pl")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/fx.pl")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
33
bundler/python/packrd/packed-packr.go
Normal file
33
bundler/python/packrd/packed-packr.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "37124a38bea92e4ec995016569c93ec9"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"0541aa67f1217ee20e491552a545a7ca": "1f8b08000000000000ff4a494d5348abd0284a2d2c4d2d2ed1b4e252505050284a2d292dca5350ca48cdc9c95728cf2fca4951e202040000ffffc6a7b4282a000000",
|
||||
"46416dc28552c117e810b36196e043ca": "1f8b08000000000000ff720bf2f755c84d2d292a4dd54fabd02da82cc9c8cfd34d4a2c4ee5e272f60f8854d053d0e3728d08f00f765530363030e072f6755148cb492cce56282acd53d0cd5030d0034305dd02880240000000ffff21aa3b6b52000000",
|
||||
"65d09a53a70631fa1bbd7c5e1906d910": "1f8b08000000000000ff34cdbd0ac23014c5f1fd3ec5d99240d05d28b8a8a382dd4442a037b4da7c98a410df5ea43a9edf19fe2e470fd730f91473856bb4ca6ccbf38fc7efd0c8fc5ab8548d478961726fb229a15b5f694cb09e8d51447b9bd226c7a5b2145ba1e1b98e7128dd4d5cced75e6888d3a1177745033b8c360c334bb52300c85c971ce09afcc5147d020000ffff9da83eeaa1000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("python", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "46416dc28552c117e810b36196e043ca"})
|
||||
b.SetResolver("app.py", packr.Pointer{ForwardBox: gk, ForwardPath: "65d09a53a70631fa1bbd7c5e1906d910"})
|
||||
b.SetResolver("fx.py", packr.Pointer{ForwardBox: gk, ForwardPath: "0541aa67f1217ee20e491552a545a7ca"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
8
bundler/python/python-packr.go
Normal file
8
bundler/python/python-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package python
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/python/packrd"
|
||||
32
bundler/python/python.go
Normal file
32
bundler/python/python.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package python
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Julia defines javascript bundler
|
||||
type Julia struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Julia {
|
||||
return &Julia{
|
||||
assets: packr.New("python", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Julia) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, "python", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Julia{}
|
||||
)
|
||||
148
bundler/python/python_test.go
Normal file
148
bundler/python/python_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package python
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestJuliaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.julia")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
end
|
||||
|
||||
fx = function(input::Input)
|
||||
return input.a + input.b
|
||||
end
|
||||
`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle function should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/fx.py")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/fx.py")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
FROM ruby:latest
|
||||
|
||||
RUN gem install sinatra
|
||||
FROM metrue/fx-ruby-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
33
bundler/ruby/packrd/packed-packr.go
Normal file
33
bundler/ruby/packrd/packed-packr.go
Normal file
@@ -0,0 +1,33 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr2 clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package packrd
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/gobuffalo/packr/v2/file/resolver"
|
||||
)
|
||||
|
||||
var _ = func() error {
|
||||
const gk = "5957c0f80ccc65e6ad8f2c329312596e"
|
||||
g := packr.New(gk, "")
|
||||
hgr, err := resolver.NewHexGzip(map[string]string{
|
||||
"5d0faa4e62eb53572bfc7410d0f064f9": "1f8b08000000000000ff720bf2f755c84d2d292a4dd54fabd02d2a4daad44d4a2c4ee5e272f60f8854d053d0e3728d08f00f765530363030e072f6755100a951482c28d02b4a52d02d008b2be8e62b18e8812117200000ffff79eb4a3952000000",
|
||||
"93130b893788876c223c2a0f3de05793": "1f8b08000000000000ffccce41aac23010c6f1fd9ce2dbcda6bc577057a8579168a75a91a4ce4ca520de5ddad4780537e19ffc207c2af7695001db10836b602a2f574b91e9733fa8dc820f0f01f7f39f1e99c8c4d18c49bdc2aeae6ba2319983ff195d220038f98c16cfb58166f949ccd1eeb165f5251b5334c996bba079f0c916ca55e022a1135d65cb4caff5ece7650049ec88cef29bc3de010000ffff22ee4db77f010000",
|
||||
"973570cec900912c2cdd5c5531be70ac": "1f8b08000000000000ff3ccd410ac2301085e1fd9ce2d16c14c40308f122e2a276a674111acd4c3022de5d6262773fef8319470e931578bcc9013825796451833fa3e7e10f7a8fab4a93d69dd446cb5aa1559f171959d26fef59e1432c33e6b29bacec09f5fb653b7e3dde22bfe0312c1242c433a6c003c9caf40d0000ffff99b9e753aa000000",
|
||||
})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
g.DefaultResolver = hgr
|
||||
|
||||
func() {
|
||||
b := packr.New("ruby", "./assets")
|
||||
b.SetResolver("Dockerfile", packr.Pointer{ForwardBox: gk, ForwardPath: "5d0faa4e62eb53572bfc7410d0f064f9"})
|
||||
b.SetResolver("app.rb", packr.Pointer{ForwardBox: gk, ForwardPath: "93130b893788876c223c2a0f3de05793"})
|
||||
b.SetResolver("fx.rb", packr.Pointer{ForwardBox: gk, ForwardPath: "973570cec900912c2cdd5c5531be70ac"})
|
||||
}()
|
||||
return nil
|
||||
}()
|
||||
8
bundler/ruby/ruby-packr.go
Normal file
8
bundler/ruby/ruby-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package ruby
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/ruby/packrd"
|
||||
32
bundler/ruby/ruby.go
Normal file
32
bundler/ruby/ruby.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package ruby
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Julia defines javascript bundler
|
||||
type Julia struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Julia {
|
||||
return &Julia{
|
||||
assets: packr.New("ruby", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Julia) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, "ruby", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Julia{}
|
||||
)
|
||||
148
bundler/ruby/ruby_test.go
Normal file
148
bundler/ruby/ruby_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package ruby
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestJuliaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.julia")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
end
|
||||
|
||||
fx = function(input::Input)
|
||||
return input.a + input.b
|
||||
end
|
||||
`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle function should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/fx.rb")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/fx.rb")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
41
bundler/rust/packrd/packed-packr.go
Normal file
41
bundler/rust/packrd/packed-packr.go
Normal file
File diff suppressed because one or more lines are too long
8
bundler/rust/rust-packr.go
Normal file
8
bundler/rust/rust-packr.go
Normal file
@@ -0,0 +1,8 @@
|
||||
// +build !skippackr
|
||||
// Code generated by github.com/gobuffalo/packr/v2. DO NOT EDIT.
|
||||
|
||||
// You can use the "packr clean" command to clean up this,
|
||||
// and any other packr generated files.
|
||||
package rust
|
||||
|
||||
import _ "github.com/metrue/fx/bundler/rust/packrd"
|
||||
32
bundler/rust/rust.go
Normal file
32
bundler/rust/rust.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package rust
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr/v2"
|
||||
"github.com/metrue/fx/bundler"
|
||||
)
|
||||
|
||||
// Julia defines javascript bundler
|
||||
type Julia struct {
|
||||
assets *packr.Box
|
||||
}
|
||||
|
||||
// New a koa bundler
|
||||
func New() *Julia {
|
||||
return &Julia{
|
||||
assets: packr.New("rust", "./assets"),
|
||||
}
|
||||
}
|
||||
|
||||
// Scaffold a koa app
|
||||
func (k *Julia) Scaffold(output string) error {
|
||||
return bundler.Restore(k.assets, output)
|
||||
}
|
||||
|
||||
// Bundle a function into a koa project
|
||||
func (k *Julia) Bundle(output string, fn string, deps ...string) error {
|
||||
return bundler.Bundle(k.assets, output, "rust", fn, deps...)
|
||||
}
|
||||
|
||||
var (
|
||||
_ bundler.Bundler = &Julia{}
|
||||
)
|
||||
148
bundler/rust/rust_test.go
Normal file
148
bundler/rust/rust_test.go
Normal file
@@ -0,0 +1,148 @@
|
||||
package rust
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func TestJuliaBundler(t *testing.T) {
|
||||
t.Run("Scaffold", func(t *testing.T) {
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Scaffold(outputDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, _, _, err := utils.Diff(outputDir, "./assets")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if diff {
|
||||
t.Fatalf("%s is not equal with %s", outputDir, "./assets")
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleSingleFunc", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.julia")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content := `struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
end
|
||||
|
||||
fx = function(input::Input)
|
||||
return input.a + input.b
|
||||
end
|
||||
`
|
||||
err = ioutil.WriteFile(fd.Name(), []byte(content), 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle function should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(content)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
|
||||
preHandleFunc, err := ioutil.ReadFile("./assets/src/fns/mod.rs")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !reflect.DeepEqual(pre, preHandleFunc) {
|
||||
{
|
||||
}
|
||||
t.Fatalf("it should get %s but got %s", preHandleFunc, pre)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("BundleFuncAndDeps", func(t *testing.T) {
|
||||
fd, err := ioutil.TempFile("", "fx_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Remove(fd.Name())
|
||||
|
||||
content, err := ioutil.ReadFile("./assets/src/fns/mod.rs")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = ioutil.WriteFile(fd.Name(), content, 0666)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
addFunc := `
|
||||
module.exports = (a, b) => a+b
|
||||
`
|
||||
addFd, err := ioutil.TempFile("", "fx_add_func_*.js")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(addFd.Name(), []byte(addFunc), 0644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
outputDir, err := ioutil.TempDir("", "fx_julia")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(outputDir)
|
||||
|
||||
julia := New()
|
||||
if err := julia.Bundle(outputDir, fd.Name(), addFd.Name()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
diff, pre, cur, err := utils.Diff("./assets", outputDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if !diff {
|
||||
t.Fatalf("handle functino should be changed")
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(cur, []byte(addFunc)) {
|
||||
t.Fatalf("it should be %s but got %s", content, cur)
|
||||
}
|
||||
if pre != nil {
|
||||
t.Fatal(pre)
|
||||
}
|
||||
})
|
||||
}
|
||||
195
config/config.go
195
config/config.go
@@ -1,195 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/user"
|
||||
"path"
|
||||
"sync"
|
||||
|
||||
"github.com/metrue/fx/utils"
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"gopkg.in/yaml.v2"
|
||||
)
|
||||
|
||||
// Items data of config file
|
||||
type Items struct {
|
||||
Clouds map[string]map[string]string `json:"clouds"`
|
||||
CurrentCloud string `json:"current_cloud"`
|
||||
}
|
||||
|
||||
// Config config of fx
|
||||
type Config struct {
|
||||
mux sync.Mutex
|
||||
configFile string
|
||||
Items
|
||||
}
|
||||
|
||||
// LoadDefault load default config
|
||||
func LoadDefault() (*Config, error) {
|
||||
configFile, err := homedir.Expand("~/.fx/config.yml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if os.Getenv("FX_CONFIG") != "" {
|
||||
configFile = os.Getenv("FX_CONFIG")
|
||||
|
||||
}
|
||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||
if err := utils.EnsureFile(configFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := writeDefaultConfig(configFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return load(configFile)
|
||||
}
|
||||
|
||||
// Load config
|
||||
func Load(configFile string) (*Config, error) {
|
||||
if configFile == "" {
|
||||
return nil, fmt.Errorf("invalid config file")
|
||||
}
|
||||
|
||||
if _, err := os.Stat(configFile); os.IsNotExist(err) {
|
||||
if err := utils.EnsureFile(configFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := writeDefaultConfig(configFile); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return load(configFile)
|
||||
}
|
||||
|
||||
// AddCloud add a cloud
|
||||
func (c *Config) addCloud(name string, cloud map[string]string) error {
|
||||
c.Items.Clouds[name] = cloud
|
||||
return save(c)
|
||||
}
|
||||
|
||||
// AddDockerCloud add docker cloud
|
||||
func (c *Config) AddDockerCloud(name string, config []byte) error {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
var conf map[string]string
|
||||
err := json.Unmarshal(config, &conf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cloud := map[string]string{
|
||||
"type": "docker",
|
||||
"host": conf["ip"],
|
||||
"user": conf["user"],
|
||||
}
|
||||
return c.addCloud(name, cloud)
|
||||
}
|
||||
|
||||
// AddK8SCloud add k8s cloud
|
||||
func (c *Config) AddK8SCloud(name string, kubeconfig []byte) error {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
dir := path.Dir(c.configFile)
|
||||
kubecfg := path.Join(dir, name+".kubeconfig")
|
||||
if err := utils.EnsureFile(kubecfg); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(kubecfg, kubeconfig, 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cloud := map[string]string{
|
||||
"type": "k8s",
|
||||
"kubeConfig": kubecfg,
|
||||
}
|
||||
|
||||
return c.addCloud(name, cloud)
|
||||
}
|
||||
|
||||
// Use set cloud instance with name as current context
|
||||
func (c *Config) Use(name string) error {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
has := false
|
||||
for n := range c.Clouds {
|
||||
if n == name {
|
||||
has = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !has {
|
||||
return fmt.Errorf("no cloud with name = %s", name)
|
||||
}
|
||||
c.Items.CurrentCloud = name
|
||||
return save(c)
|
||||
}
|
||||
|
||||
// View view current config
|
||||
func (c *Config) View() ([]byte, error) {
|
||||
c.mux.Lock()
|
||||
defer c.mux.Unlock()
|
||||
|
||||
return ioutil.ReadFile(c.configFile)
|
||||
}
|
||||
|
||||
func load(configFile string) (*Config, error) {
|
||||
conf, err := ioutil.ReadFile(configFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var items Items
|
||||
if err := yaml.Unmarshal(conf, &items); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var c = Config{
|
||||
configFile: configFile,
|
||||
Items: items,
|
||||
}
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
func save(c *Config) error {
|
||||
conf, err := yaml.Marshal(c.Items)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(c.configFile, conf, 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func writeDefaultConfig(configFile string) error {
|
||||
me, err := user.Current()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
items := Items{
|
||||
Clouds: map[string]map[string]string{
|
||||
"default": map[string]string{
|
||||
"type": "docker",
|
||||
"host": "127.0.0.1",
|
||||
"user": me.Username,
|
||||
},
|
||||
},
|
||||
CurrentCloud: "default",
|
||||
}
|
||||
|
||||
body, err := yaml.Marshal(items)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(configFile, body, 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
configPath := "./tmp/config.yml"
|
||||
defer func() {
|
||||
if err := os.RemoveAll("./tmp"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
c, err := Load(configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(c.Clouds) != 1 {
|
||||
t.Fatal("should contain default cloud")
|
||||
}
|
||||
|
||||
name := "fx_cluster_1"
|
||||
if err := c.Use(name); err == nil {
|
||||
t.Fatal("should get no such cloud error")
|
||||
}
|
||||
|
||||
if err := c.AddK8SCloud(name, []byte("sampe kubeconfg")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
config := map[string]string{
|
||||
"ip": "127.0.0.1",
|
||||
"user": "use1",
|
||||
}
|
||||
configData, _ := json.Marshal(config)
|
||||
if err := c.AddDockerCloud("docker-1", configData); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := c.Use(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if c.CurrentCloud != name {
|
||||
t.Fatalf("should get %s but got %s", name, c.CurrentCloud)
|
||||
}
|
||||
|
||||
conf, err := Load(configPath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if conf.CurrentCloud != name {
|
||||
t.Fatalf("should get %s but got %s", name, c.CurrentCloud)
|
||||
}
|
||||
|
||||
body, err := c.View()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
fmt.Println(string(body))
|
||||
}
|
||||
14
config/env.go
Normal file
14
config/env.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// DisableContainerAutoremove to tell if to run container with --rm
|
||||
var DisableContainerAutoremove = false
|
||||
|
||||
func init() {
|
||||
if os.Getenv("DISABLE_CONTAINER_AUTOREMOVE") == "true" {
|
||||
DisableContainerAutoremove = true
|
||||
}
|
||||
}
|
||||
17
config/env_test.go
Normal file
17
config/env_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var _ = func() (_ struct{}) {
|
||||
os.Setenv("DISABLE_CONTAINER_AUTOREMOVE", "true")
|
||||
return
|
||||
}()
|
||||
|
||||
func TestEnvLoad(t *testing.T) {
|
||||
if !DisableContainerAutoremove {
|
||||
t.Fatalf("should be true after set")
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package config
|
||||
|
||||
// CloudTypeDocker docker type
|
||||
const CloudTypeDocker = "docker"
|
||||
|
||||
// CloudTypeK8S k8s type
|
||||
const CloudTypeK8S = "k8s"
|
||||
15
constants/languages.go
Normal file
15
constants/languages.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package constants
|
||||
|
||||
// ExtLangMapping file extension mapping with programming language
|
||||
var ExtLangMapping = map[string]string{
|
||||
".js": "node",
|
||||
".go": "go",
|
||||
".rb": "ruby",
|
||||
".py": "python",
|
||||
".php": "php",
|
||||
".jl": "julia",
|
||||
".java": "java",
|
||||
".d": "d",
|
||||
".rs": "rust",
|
||||
".pl": "perl",
|
||||
}
|
||||
@@ -18,11 +18,11 @@ import (
|
||||
"github.com/apex/log"
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
dockerTypesContainer "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/google/uuid"
|
||||
fxConfig "github.com/metrue/fx/config"
|
||||
containerruntimes "github.com/metrue/fx/container_runtimes"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
@@ -31,33 +31,57 @@ import (
|
||||
|
||||
// API interact with dockerd http api
|
||||
type API struct {
|
||||
host string
|
||||
port string
|
||||
endpoint string
|
||||
version string
|
||||
}
|
||||
|
||||
// New a API
|
||||
func New(host string, port string) *API {
|
||||
return &API{
|
||||
host: host,
|
||||
port: port,
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize an API
|
||||
func (api *API) Initialize() error {
|
||||
addr := api.host + ":" + api.port
|
||||
v, err := version(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", api.host, api.port, v)
|
||||
api.endpoint = endpoint
|
||||
return nil
|
||||
}
|
||||
|
||||
// Create a API
|
||||
func Create(host string, port string) (*API, error) {
|
||||
version, err := utils.DockerVersion(host, port)
|
||||
addr := host + ":" + port
|
||||
v, err := version(addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", host, port, version)
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", host, port, v)
|
||||
return &API{
|
||||
endpoint: endpoint,
|
||||
version: version,
|
||||
version: v,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustCreate a api object, panic if not
|
||||
func MustCreate(host string, port string) *API {
|
||||
version, err := utils.DockerVersion(host, port)
|
||||
addr := host + ":" + port
|
||||
v, err := version(addr)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", host, port, version)
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", host, port, v)
|
||||
return &API{
|
||||
endpoint: endpoint,
|
||||
version: version,
|
||||
version: v,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +155,12 @@ func (api *API) post(path string, body []byte, expectStatus int, v interface{})
|
||||
|
||||
// Version get version of docker engine
|
||||
func (api *API) Version(ctx context.Context) (string, error) {
|
||||
path := api.endpoint + "/version"
|
||||
addr := api.host + ":" + api.port
|
||||
return version(addr)
|
||||
}
|
||||
|
||||
func version(endpoint string) (string, error) {
|
||||
path := endpoint + "/version"
|
||||
if !strings.HasPrefix(path, "http") {
|
||||
path = "http://" + path
|
||||
}
|
||||
@@ -221,17 +250,27 @@ func (api *API) ListContainer(ctx context.Context, name string) ([]types.Service
|
||||
|
||||
svs := make(map[string]types.Service)
|
||||
for _, container := range containers {
|
||||
name := "UNKNOWN"
|
||||
if len(container.Names) > 0 {
|
||||
name = container.Names[0]
|
||||
}
|
||||
|
||||
port := -1
|
||||
ip := "UNKNOWN"
|
||||
if len(container.Ports) > 0 {
|
||||
ip = container.Ports[0].IP
|
||||
port = int(container.Ports[0].PublicPort)
|
||||
}
|
||||
|
||||
// container name have extra forward slash
|
||||
// https://github.com/moby/moby/issues/6705
|
||||
if strings.HasPrefix(container.Names[0], fmt.Sprintf("/%s", name)) {
|
||||
svs[container.Image] = types.Service{
|
||||
Name: container.Names[0],
|
||||
Image: container.Image,
|
||||
ID: container.ID,
|
||||
Host: container.Ports[0].IP,
|
||||
Port: int(container.Ports[0].PublicPort),
|
||||
State: container.State,
|
||||
}
|
||||
svs[container.Image] = types.Service{
|
||||
Name: name,
|
||||
Image: container.Image,
|
||||
ID: container.ID,
|
||||
Host: ip,
|
||||
Port: port,
|
||||
State: container.State,
|
||||
}
|
||||
}
|
||||
services := []types.Service{}
|
||||
@@ -380,13 +419,13 @@ func (api *API) StartContainer(ctx context.Context, name string, image string, b
|
||||
portSet[port] = struct{}{}
|
||||
portMap[port] = bindings
|
||||
}
|
||||
config := &dockerTypesContainer.Config{
|
||||
config := &container.Config{
|
||||
Image: image,
|
||||
ExposedPorts: portSet,
|
||||
}
|
||||
|
||||
hostConfig := &dockerTypesContainer.HostConfig{
|
||||
AutoRemove: true,
|
||||
hostConfig := &container.HostConfig{
|
||||
AutoRemove: !fxConfig.DisableContainerAutoremove,
|
||||
PortBindings: portMap,
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import (
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/google/uuid"
|
||||
fxConfig "github.com/metrue/fx/config"
|
||||
containerruntimes "github.com/metrue/fx/container_runtimes"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
@@ -161,7 +162,7 @@ func (d *Docker) StartContainer(ctx context.Context, name string, image string,
|
||||
}
|
||||
|
||||
hostConfig := &dockerTypesContainer.HostConfig{
|
||||
AutoRemove: true,
|
||||
AutoRemove: !fxConfig.DisableContainerAutoremove,
|
||||
PortBindings: portMap,
|
||||
}
|
||||
resp, err := d.ContainerCreate(ctx, config, hostConfig, nil, name)
|
||||
|
||||
164
container_runtimes/mocks/runtime.go
Normal file
164
container_runtimes/mocks/runtime.go
Normal file
@@ -0,0 +1,164 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: runtimes.go
|
||||
|
||||
// Package mock_containerruntimes is a generated GoMock package.
|
||||
package mock_containerruntimes
|
||||
|
||||
import (
|
||||
context "context"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
types "github.com/metrue/fx/types"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockContainerRuntime is a mock of ContainerRuntime interface
|
||||
type MockContainerRuntime struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockContainerRuntimeMockRecorder
|
||||
}
|
||||
|
||||
// MockContainerRuntimeMockRecorder is the mock recorder for MockContainerRuntime
|
||||
type MockContainerRuntimeMockRecorder struct {
|
||||
mock *MockContainerRuntime
|
||||
}
|
||||
|
||||
// NewMockContainerRuntime creates a new mock instance
|
||||
func NewMockContainerRuntime(ctrl *gomock.Controller) *MockContainerRuntime {
|
||||
mock := &MockContainerRuntime{ctrl: ctrl}
|
||||
mock.recorder = &MockContainerRuntimeMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockContainerRuntime) EXPECT() *MockContainerRuntimeMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// BuildImage mocks base method
|
||||
func (m *MockContainerRuntime) BuildImage(ctx context.Context, workdir, name string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BuildImage", ctx, workdir, name)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// BuildImage indicates an expected call of BuildImage
|
||||
func (mr *MockContainerRuntimeMockRecorder) BuildImage(ctx, workdir, name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BuildImage", reflect.TypeOf((*MockContainerRuntime)(nil).BuildImage), ctx, workdir, name)
|
||||
}
|
||||
|
||||
// PushImage mocks base method
|
||||
func (m *MockContainerRuntime) PushImage(ctx context.Context, name string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PushImage", ctx, name)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PushImage indicates an expected call of PushImage
|
||||
func (mr *MockContainerRuntimeMockRecorder) PushImage(ctx, name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PushImage", reflect.TypeOf((*MockContainerRuntime)(nil).PushImage), ctx, name)
|
||||
}
|
||||
|
||||
// InspectImage mocks base method
|
||||
func (m *MockContainerRuntime) InspectImage(ctx context.Context, name string, img interface{}) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InspectImage", ctx, name, img)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InspectImage indicates an expected call of InspectImage
|
||||
func (mr *MockContainerRuntimeMockRecorder) InspectImage(ctx, name, img interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InspectImage", reflect.TypeOf((*MockContainerRuntime)(nil).InspectImage), ctx, name, img)
|
||||
}
|
||||
|
||||
// TagImage mocks base method
|
||||
func (m *MockContainerRuntime) TagImage(ctx context.Context, name, tag string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "TagImage", ctx, name, tag)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// TagImage indicates an expected call of TagImage
|
||||
func (mr *MockContainerRuntimeMockRecorder) TagImage(ctx, name, tag interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TagImage", reflect.TypeOf((*MockContainerRuntime)(nil).TagImage), ctx, name, tag)
|
||||
}
|
||||
|
||||
// StartContainer mocks base method
|
||||
func (m *MockContainerRuntime) StartContainer(ctx context.Context, name, image string, bindings []types.PortBinding) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StartContainer", ctx, name, image, bindings)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StartContainer indicates an expected call of StartContainer
|
||||
func (mr *MockContainerRuntimeMockRecorder) StartContainer(ctx, name, image, bindings interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartContainer", reflect.TypeOf((*MockContainerRuntime)(nil).StartContainer), ctx, name, image, bindings)
|
||||
}
|
||||
|
||||
// StopContainer mocks base method
|
||||
func (m *MockContainerRuntime) StopContainer(ctx context.Context, name string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StopContainer", ctx, name)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// StopContainer indicates an expected call of StopContainer
|
||||
func (mr *MockContainerRuntimeMockRecorder) StopContainer(ctx, name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopContainer", reflect.TypeOf((*MockContainerRuntime)(nil).StopContainer), ctx, name)
|
||||
}
|
||||
|
||||
// InspectContainer mocks base method
|
||||
func (m *MockContainerRuntime) InspectContainer(ctx context.Context, name string, container interface{}) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "InspectContainer", ctx, name, container)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// InspectContainer indicates an expected call of InspectContainer
|
||||
func (mr *MockContainerRuntimeMockRecorder) InspectContainer(ctx, name, container interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "InspectContainer", reflect.TypeOf((*MockContainerRuntime)(nil).InspectContainer), ctx, name, container)
|
||||
}
|
||||
|
||||
// ListContainer mocks base method
|
||||
func (m *MockContainerRuntime) ListContainer(ctx context.Context, filter string) ([]types.Service, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListContainer", ctx, filter)
|
||||
ret0, _ := ret[0].([]types.Service)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListContainer indicates an expected call of ListContainer
|
||||
func (mr *MockContainerRuntimeMockRecorder) ListContainer(ctx, filter interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListContainer", reflect.TypeOf((*MockContainerRuntime)(nil).ListContainer), ctx, filter)
|
||||
}
|
||||
|
||||
// Version mocks base method
|
||||
func (m *MockContainerRuntime) Version(ctx context.Context) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Version", ctx)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Version indicates an expected call of Version
|
||||
func (mr *MockContainerRuntimeMockRecorder) Version(ctx interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Version", reflect.TypeOf((*MockContainerRuntime)(nil).Version), ctx)
|
||||
}
|
||||
@@ -52,6 +52,7 @@ func (ctx *Context) GetCliContext() *cli.Context {
|
||||
|
||||
// Set a value with name
|
||||
func (ctx *Context) Set(name string, value interface{}) {
|
||||
// nolint
|
||||
newCtx := context.WithValue(ctx.Context, name, value)
|
||||
ctx.Context = newCtx
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 294 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 78 KiB |
@@ -36,11 +36,26 @@ $ curl 127.0.0.1:2000
|
||||
|
||||
## Deploy a function onto remote host
|
||||
|
||||
* make sure your instance can be ssh login
|
||||
* make sure you can ssh login to target host with root
|
||||
|
||||
Update `/etc/ssh/sshd_config` to allow login with root.
|
||||
|
||||
```
|
||||
PermitRootLogin yes
|
||||
```
|
||||
|
||||
Then restart sshd with,
|
||||
|
||||
```shell
|
||||
$ sudo service sshd restart
|
||||
```
|
||||
|
||||
* make sure your instance accept port 8866
|
||||
|
||||
[FYI](https://lightsail.aws.amazon.com/ls/docs/en_us/articles/understanding-firewall-and-port-mappings-in-amazon-lightsail)
|
||||
|
||||
then you can deploy function to remote host
|
||||
|
||||
```shell
|
||||
DOCKER_REMOTE_HOST_ADDR=<your host> DOCKER_REMOTE_HOST_USER=<your user> DOCKER_REMOTE_HOST_PASSWORD=<your password> fx up -p 2000 test/functions/func.js
|
||||
fx up --host root@<your host> test/functions/func.js
|
||||
```
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user