Compare commits
368 Commits
support-R
...
0.7.5-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
047fac2a0a | ||
|
|
1cb68766f7 | ||
|
|
91fd5dc59f | ||
|
|
184235acb2 | ||
|
|
aa49a59feb | ||
|
|
c9d382d903 | ||
|
|
81e18e5b0d | ||
|
|
3882f843bf | ||
|
|
293481f081 | ||
|
|
c12d967ced | ||
|
|
b2a62cbd94 | ||
|
|
536b757602 | ||
|
|
ddff53fff2 | ||
|
|
ae87215cfb | ||
|
|
90d7ec88f0 | ||
|
|
697277e1bb | ||
|
|
a17126c713 | ||
|
|
2c35262b9e | ||
|
|
017a34c13c | ||
|
|
bf8885e91a | ||
|
|
e04ed119a6 | ||
|
|
551e4986d3 | ||
|
|
fa05603599 | ||
|
|
4826726d65 | ||
|
|
f33b3560ce | ||
|
|
2e6ec2f8a2 | ||
|
|
d821b46744 | ||
|
|
dab52aae5a | ||
|
|
89ebf19859 | ||
|
|
d3d1a684cb | ||
|
|
2f1ed88dc6 | ||
|
|
a7cfa99643 | ||
|
|
3454ec0fdb | ||
|
|
f70ef1c406 | ||
|
|
a5db158fe5 | ||
|
|
a4d44a4fc0 | ||
|
|
6b25cac002 | ||
|
|
af28f4d345 | ||
|
|
c540163e5f | ||
|
|
ae3d76868d | ||
|
|
bea48d26b3 | ||
|
|
0196c11793 | ||
|
|
ab127a36ff | ||
|
|
24a9fb1c35 | ||
|
|
9c2f14ce27 | ||
|
|
ffa37ac77b | ||
|
|
d21e3cfb4a | ||
|
|
199339bdfa | ||
|
|
0d01728e20 | ||
|
|
e1b752407e | ||
|
|
73f3a3853f | ||
|
|
2b7176201e | ||
|
|
37b2733dcf | ||
|
|
33943c83f1 | ||
|
|
7d3cc8f8d0 | ||
|
|
278652559a | ||
|
|
87831d23f8 | ||
|
|
4ace1d285f | ||
|
|
d1191c2c85 | ||
|
|
2f238e9ce0 | ||
|
|
8fe146dabb | ||
|
|
5c83a05054 | ||
|
|
f0c4a8f159 | ||
|
|
edb6bbc585 | ||
|
|
e301d2d54f | ||
|
|
474cb26920 | ||
|
|
8c962bf31a | ||
|
|
c8c4d69b57 | ||
|
|
61c151ef11 | ||
|
|
7d709d8f19 | ||
|
|
9f14931d1f | ||
|
|
6a7d7b2353 | ||
|
|
52ffb3ef25 | ||
|
|
33ca880d73 | ||
|
|
8b13442a15 | ||
|
|
efe7ad5b00 | ||
|
|
b9cf6c9a07 | ||
|
|
7da8695b1b | ||
|
|
6c569458a1 | ||
|
|
fef6580134 | ||
|
|
fdae35cb37 | ||
|
|
6180c62d31 | ||
|
|
295745b3d6 | ||
|
|
32f4fab154 | ||
|
|
7859f57150 | ||
|
|
d9e132e49b | ||
|
|
4366f5cbca | ||
|
|
30133c534c | ||
|
|
77f7ee3092 | ||
|
|
bff8fdaf95 | ||
|
|
14c5e841a9 | ||
|
|
05f755ed64 | ||
|
|
0605ac2716 | ||
|
|
d54a4c23c8 | ||
|
|
778c718282 | ||
|
|
f04bbd2403 | ||
|
|
21ec74b03b | ||
|
|
1be99b5b25 | ||
|
|
cf7bf9e71c | ||
|
|
9d35b29ff5 | ||
|
|
56afefb143 | ||
|
|
f208d7c8d2 | ||
|
|
3ac61fea2d | ||
|
|
884fb65432 | ||
|
|
24f9b53e76 | ||
|
|
61e153b59a | ||
|
|
3105fe1b5a | ||
|
|
584e1a67fc | ||
|
|
cc3d3a8d9f | ||
|
|
303c75e9cb | ||
|
|
e775331f23 | ||
|
|
8dfc5b947f | ||
|
|
fb55abb6b5 | ||
|
|
c338d28498 | ||
|
|
26ef3c6027 | ||
|
|
843df76eb1 | ||
|
|
71f95067f8 | ||
|
|
95d36fc1f0 | ||
|
|
dbf6ee77fc | ||
|
|
aa68702476 | ||
|
|
b36b9979d8 | ||
|
|
9ed073a4f6 | ||
|
|
ab90fe4cde | ||
|
|
55d0dbeca9 | ||
|
|
e22d371722 | ||
|
|
5b9685a5b5 | ||
|
|
cd017b2e1e | ||
|
|
fef248849c | ||
|
|
50bdf6e31c | ||
|
|
d495a1d7f1 | ||
|
|
850b186592 | ||
|
|
b0df98600e | ||
|
|
d325753bb7 | ||
|
|
7b4a6a37c8 | ||
|
|
e51d6d86f8 | ||
|
|
d73afe8666 | ||
|
|
950c65d2c6 | ||
|
|
56967bf689 | ||
|
|
d66eadb710 | ||
|
|
77a97c1689 | ||
|
|
2d7af0ea27 | ||
|
|
60efd92527 | ||
|
|
5b172708e8 | ||
|
|
ce88cacfb5 | ||
|
|
aedba3ee7c | ||
|
|
a224c4add4 | ||
|
|
21a51d289c | ||
|
|
1f7c8ce5a2 | ||
|
|
1287ab8743 | ||
|
|
ed5ac21613 | ||
|
|
bdbc558470 | ||
|
|
fb39606933 | ||
|
|
06bd14fb45 | ||
|
|
0df6eb71e0 | ||
|
|
241e680302 | ||
|
|
7ada940f0a | ||
|
|
c156f68ea0 | ||
|
|
5b93ecd834 | ||
|
|
104a5705b9 | ||
|
|
1f5244e087 | ||
|
|
6b3cddf847 | ||
|
|
c2750e776f | ||
|
|
173a4207a9 | ||
|
|
b62026c692 | ||
|
|
9d1c6f6b60 | ||
|
|
af2e67e301 | ||
|
|
8a2ba8172c | ||
|
|
e050770473 | ||
|
|
1aebe626af | ||
|
|
3c24781d36 | ||
|
|
b57d7f79e9 | ||
|
|
dce74a9b57 | ||
|
|
391c1a9fa8 | ||
|
|
7de6f7db9d | ||
|
|
24661a6fa5 | ||
|
|
6d2c682d4b | ||
|
|
db4a0026a2 | ||
|
|
9524de1e9e | ||
|
|
a0d69eb61f | ||
|
|
0e11e453dc | ||
|
|
3ebcd2a857 | ||
|
|
a8c60ad9f7 | ||
|
|
11a0d21c0d | ||
|
|
96e0403dad | ||
|
|
8bedb38eb9 | ||
|
|
f386c007eb | ||
|
|
d8c616b2d3 | ||
|
|
5d57c5df51 | ||
|
|
8d89e63b14 | ||
|
|
ce290dcb3b | ||
|
|
cae4f3e3f7 | ||
|
|
1fc9ba1594 | ||
|
|
92f1ba2bf0 | ||
|
|
0fdebbd05b | ||
|
|
63fa802e63 | ||
|
|
70fd259ca6 | ||
|
|
37ace80123 | ||
|
|
3128421b6b | ||
|
|
7c6a22461c | ||
|
|
3371549c0b | ||
|
|
7aad3c6319 | ||
|
|
b8b1432ba3 | ||
|
|
ba3047b6f3 | ||
|
|
e5c60c933c | ||
|
|
ef2bd66bb1 | ||
|
|
327dbc2251 | ||
|
|
bce63388f2 | ||
|
|
665ffae490 | ||
|
|
8df9cd658a | ||
|
|
5b233491f0 | ||
|
|
599eeca2c2 | ||
|
|
e660a64c36 | ||
|
|
656a20b259 | ||
|
|
1862756282 | ||
|
|
15001efc39 | ||
|
|
e62adc99fa | ||
|
|
5c8be67a57 | ||
|
|
7eb6124dad | ||
|
|
3c57e130b9 | ||
|
|
0b93e7379b | ||
|
|
2396fec147 | ||
|
|
744308cf5b | ||
|
|
747273dad5 | ||
|
|
68b630aaeb | ||
|
|
4afbdbc83c | ||
|
|
b1b2ae5a15 | ||
|
|
f816bd9539 | ||
|
|
4a81e90469 | ||
|
|
9025464369 | ||
|
|
3317b936e3 | ||
|
|
98c1f65b66 | ||
|
|
a556e50d11 | ||
|
|
d02ed1d748 | ||
|
|
976deaad53 | ||
|
|
21ea85f33a | ||
|
|
484455d850 | ||
|
|
f911d34767 | ||
|
|
ed4d1c87d8 | ||
|
|
cebcfaaffd | ||
|
|
4c70089cde | ||
|
|
d1ff152bfe | ||
|
|
202ed7d1df | ||
|
|
2219c3f1c9 | ||
|
|
2616229307 | ||
|
|
05a0372672 | ||
|
|
501965fffc | ||
|
|
174607546f | ||
|
|
599966aea5 | ||
|
|
6dba9a4ef2 | ||
|
|
3cc9694c69 | ||
|
|
e53edb20cf | ||
|
|
dcf2d1e38f | ||
|
|
727963bb14 | ||
|
|
b13ac2943b | ||
|
|
4e2a5ff260 | ||
|
|
b77e8a6cd1 | ||
|
|
ed082eea49 | ||
|
|
e92a2ca4a0 | ||
|
|
612d83c8e2 | ||
|
|
7ee48f56b2 | ||
|
|
84b8778ddf | ||
|
|
db739c1209 | ||
|
|
a0e9bae89b | ||
|
|
317f00ea5b | ||
|
|
c93eada317 | ||
|
|
384c192c04 | ||
|
|
e72e0d5efa | ||
|
|
3735ec2260 | ||
|
|
8bf60ff016 | ||
|
|
cefcd77192 | ||
|
|
b95db62561 | ||
|
|
2872f64a12 | ||
|
|
07845db5ae | ||
|
|
2c450fa549 | ||
|
|
93ee7d868e | ||
|
|
775afd0d2b | ||
|
|
27a3dc92fb | ||
|
|
18ee51ff07 | ||
|
|
dfb372c42f | ||
|
|
06a79c3fa1 | ||
|
|
e50fd6b799 | ||
|
|
8ec1d29cec | ||
|
|
768232d625 | ||
|
|
599e9a596f | ||
|
|
e31f6605dd | ||
|
|
09ced6210d | ||
|
|
c077cb55d5 | ||
|
|
2f96dfefec | ||
|
|
61113c5404 | ||
|
|
1c56ae5037 | ||
|
|
998be24c84 | ||
|
|
c2d8545e15 | ||
|
|
10df127f55 | ||
|
|
f7ed3cc681 | ||
|
|
27a02c8a74 | ||
|
|
225e8723ba | ||
|
|
e50e144346 | ||
|
|
a836b9c9c9 | ||
|
|
61b82d28b6 | ||
|
|
e7b5d3f745 | ||
|
|
d5fae747f7 | ||
|
|
62379a410f | ||
|
|
8ed8fac9e9 | ||
|
|
fe54495f4d | ||
|
|
d945634de4 | ||
|
|
fb2c8d109b | ||
|
|
59053bf626 | ||
|
|
3fa4d1cbb6 | ||
|
|
6c3af11fd9 | ||
|
|
9f18f5f315 | ||
|
|
29a0745aea | ||
|
|
30a60d3ade | ||
|
|
ed5d57a32f | ||
|
|
b78012485f | ||
|
|
0ef5debd91 | ||
|
|
f3a2e99c24 | ||
|
|
8742f1c23d | ||
|
|
149006ee79 | ||
|
|
bf28762e0d | ||
|
|
12822414f8 | ||
|
|
16a0538c6d | ||
|
|
549a0f2896 | ||
|
|
88d91d630b | ||
|
|
66e906ce96 | ||
|
|
57bfd50c85 | ||
|
|
4bd92a88d1 | ||
|
|
50b37a72bd | ||
|
|
fb2d1e14ee | ||
|
|
f918878f6a | ||
|
|
5d8bcac543 | ||
|
|
da6b5795ee | ||
|
|
8c7a5bf6e4 | ||
|
|
9d8df70e80 | ||
|
|
f1655d81cb | ||
|
|
6b26c46e23 | ||
|
|
23932e1ded | ||
|
|
20b2fadf14 | ||
|
|
e9c39b4703 | ||
|
|
a80d98e6c0 | ||
|
|
f11b06e6d9 | ||
|
|
e81032bd46 | ||
|
|
b8620b71af | ||
|
|
f066e841e8 | ||
|
|
4bb67a9514 | ||
|
|
bef5250cfb | ||
|
|
e50ddaf004 | ||
|
|
a45151c8e5 | ||
|
|
2313d41e6c | ||
|
|
5390e74365 | ||
|
|
c9793cda30 | ||
|
|
0840644f69 | ||
|
|
315ff33cf7 | ||
|
|
268d308e1b | ||
|
|
bcf6dbd1a4 | ||
|
|
34df47d010 | ||
|
|
4dc7cc17c3 | ||
|
|
1ef791cd6e | ||
|
|
768be125cd | ||
|
|
5816870074 | ||
|
|
fa191b35b8 | ||
|
|
d961614d79 | ||
|
|
1ccd323d1c | ||
|
|
2b1bd16510 | ||
|
|
ca6493527e | ||
|
|
88adb68bb4 | ||
|
|
dd90aa09c1 | ||
|
|
81a58223c5 | ||
|
|
dfa8adf3ac |
@@ -1,55 +1,73 @@
|
||||
defaults: &defaults
|
||||
machine: true
|
||||
environment:
|
||||
IMPORT_PATH: "github.com/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME"
|
||||
OUTPUT_DIR: "./build"
|
||||
DIST_DIR: "./dist"
|
||||
|
||||
install_golang: &install_golang
|
||||
run:
|
||||
name: install Golang 1.11
|
||||
command: |
|
||||
sudo add-apt-repository ppa:gophers/archive
|
||||
sudo apt-get update
|
||||
sudo apt-get install golang-1.11-go
|
||||
alias go="/usr/lib/go-1.11/bin/go"
|
||||
go version
|
||||
|
||||
install_deps: &install_deps
|
||||
run:
|
||||
name: Install deps
|
||||
command: |
|
||||
/usr/lib/go-1.11/bin/go mod vendor
|
||||
/usr/lib/go-1.11/bin/go get -u github.com/gobuffalo/packr/packr
|
||||
|
||||
install_httpie: &install_httpie
|
||||
run:
|
||||
name: install httpie
|
||||
command: |
|
||||
sudo apt-get -y update && sudo apt-get -y install httpie
|
||||
|
||||
install_jq: &install_jq
|
||||
run:
|
||||
name: install jq
|
||||
command: |
|
||||
sudo apt-get update && sudo apt-get -y install jq
|
||||
|
||||
build_binary: &build_binary
|
||||
run:
|
||||
name: build binary
|
||||
command: |
|
||||
/usr/lib/go-1.11/bin/go build -o ${OUTPUT_DIR}/fx fx.go
|
||||
|
||||
unit_test: &unit_test
|
||||
run:
|
||||
name: unit test
|
||||
command: |
|
||||
make unit-test
|
||||
bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}
|
||||
cli_test: &cli_test
|
||||
run:
|
||||
name: cli test
|
||||
command: make cli-test
|
||||
|
||||
version: 2
|
||||
machine:
|
||||
services:
|
||||
- docker
|
||||
dependencies:
|
||||
override:
|
||||
- sudo add-apt-repository ppa:masterminds/glide -y
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install glide -y
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.8
|
||||
|
||||
working_directory: /go/src/github.com/metrue/fx
|
||||
|
||||
test:
|
||||
<<: *defaults
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- setup_remote_docker
|
||||
|
||||
- *install_golang
|
||||
- *install_deps
|
||||
- *unit_test
|
||||
- *build_binary
|
||||
- run:
|
||||
name: Install tools
|
||||
command: |
|
||||
go get github.com/golang/dep
|
||||
cd $GOPATH/src/github.com/golang/dep
|
||||
go install ./...
|
||||
name: Pull images
|
||||
command: make pull
|
||||
- *cli_test
|
||||
|
||||
- run:
|
||||
name: Build and Install
|
||||
command: |
|
||||
dep ensure
|
||||
go install ./
|
||||
|
||||
- run:
|
||||
name: Test
|
||||
command: |
|
||||
fx serve > server_output.log 2>&1 &
|
||||
sleep 20
|
||||
touch deploy.log
|
||||
fx up examples/functions/func.js >> deploy.log
|
||||
fx up examples/functions/func.rb >> deploy.log
|
||||
fx up examples/functions/func.py >> deploy.log
|
||||
fx up examples/functions/func.go >> deploy.log
|
||||
fx up examples/functions/func.php >> deploy.log
|
||||
fx up examples/functions/func.jl >> deploy.log
|
||||
cat server_output.log
|
||||
cat deploy.log;
|
||||
cat deploy.log | grep 'Succed: 1' | wc -l | grep 6
|
||||
|
||||
deployment:
|
||||
production:
|
||||
branch: master
|
||||
commands:
|
||||
- echo "Not Ready Yet"
|
||||
workflows:
|
||||
version: 2
|
||||
workflow:
|
||||
jobs:
|
||||
- test
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
version: 2
|
||||
dependencies:
|
||||
override:
|
||||
- sudo add-apt-repository ppa:masterminds/glide -y
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install glide -y
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/golang:1.8
|
||||
|
||||
working_directory: /go/src/github.com/metrue/fx
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install tools
|
||||
command: |
|
||||
wget "https://github.com/Masterminds/glide/releases/download/0.10.2/glide-0.10.2-linux-amd64.tar.gz"
|
||||
mkdir -p $HOME/bin
|
||||
tar -vxz -C $HOME/bin --strip=1 -f glide-0.10.2-linux-amd64.tar.gz
|
||||
export PATH="$HOME/bin:$PATH"
|
||||
- run:
|
||||
name: Build client
|
||||
command: |
|
||||
export PATH="$HOME/bin:$PATH"
|
||||
cd client && make install-deps && make clean && make build
|
||||
- run:
|
||||
name: Build server
|
||||
command: |
|
||||
export PATH="$HOME/bin:$PATH"
|
||||
cd server && make install-deps && make clean && make build
|
||||
deployment:
|
||||
production:
|
||||
branch: master
|
||||
commands:
|
||||
- echo "Not Ready Yet"
|
||||
5
.gitattributes
vendored
Normal file
5
.gitattributes
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
assets/**/* linguist-vendored
|
||||
api/assets/**/* linguist-vendored
|
||||
examples/**/* linguist-vendored
|
||||
packer/images/**/* linguist-vendored
|
||||
*.md linguist-documentation
|
||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
ko_fi: metrue
|
||||
9
.github/pull_request_template.md
vendored
Normal file
9
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
Issue: <url to the issue to fix>
|
||||
Summary: <a brief summary of PR purpose>
|
||||
|
||||
The checklist before PR is ready for review:
|
||||
|
||||
- [ ] has unit testing for new added codes
|
||||
- [ ] has functional testing for new added features
|
||||
- [ ] has checked the lint or style issues
|
||||
- [ ] README updated if need
|
||||
102
.github/workflows/ci.yml
vendored
Normal file
102
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
on: [push, pull_request]
|
||||
name: ci
|
||||
jobs:
|
||||
Test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup Go 1.12
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.12
|
||||
id: go
|
||||
|
||||
- name: check out
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: setup docker
|
||||
run: |
|
||||
./scripts/provision.sh
|
||||
|
||||
- name: setup k8s and kind
|
||||
run: |
|
||||
export GOBIN=$(go env GOPATH)/bin
|
||||
export PATH=$PATH:$GOBIN
|
||||
mkdir -p $GOBIN
|
||||
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
|
||||
chmod +x kubectl && mv kubectl $GOBIN
|
||||
wget https://github.com/kubernetes-sigs/kind/releases/download/v0.5.0/kind-linux-amd64 && chmod +x kind-linux-amd64 && mv kind-linux-amd64 $GOBIN/kind
|
||||
./scripts/setup_kind.sh
|
||||
|
||||
- name: unit test
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
run: |
|
||||
export KUBECONFIG=/home/runner/.kube/kind-config-fx-test
|
||||
DEBUG=true go test -v ./container_runtimes/... ./deploy/...
|
||||
|
||||
- name: build fx
|
||||
run: |
|
||||
make build
|
||||
|
||||
- name: test fx-docker
|
||||
run: |
|
||||
cd ./contrib/docker_packer
|
||||
make linux-build
|
||||
make docker-build
|
||||
make test
|
||||
# make docker-publish #TODO in release workflow
|
||||
|
||||
- name: lint
|
||||
run: |
|
||||
export GOBIN=$(go env GOPATH)/bin
|
||||
export PATH=$PATH:$GOBIN
|
||||
go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
golangci-lint run
|
||||
|
||||
|
||||
- name: test fx cli
|
||||
run: |
|
||||
echo $KUBECONFIG
|
||||
unset KUBECONFIG
|
||||
make cli-test
|
||||
|
||||
- name: test AKS
|
||||
env:
|
||||
AKS_KUBECONFIG: ${{ secrets.AKS_KUBECONFIG }}
|
||||
run: |
|
||||
export KUBECONFIG=${HOME}/.kube/aks
|
||||
echo ${AKS_KUBECONFIG} | base64 -d > $KUBECONFIG
|
||||
if [[ -z "$AKS_KUBECONFIG" ]];then
|
||||
echo "skip deploy test since no valid KUBECONFIG"
|
||||
else
|
||||
DEBUG=true ./build/fx deploy -n hello -p 12345 examples/functions/JavaScript/func.js
|
||||
./build/fx destroy hello
|
||||
rm ${KUBECONFIG}
|
||||
fi
|
||||
|
||||
Installation:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [Test]
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
# TODO enable window and mac
|
||||
# - macOS-latest
|
||||
# - windows-latest
|
||||
version:
|
||||
- latest
|
||||
- v0.117.0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: install fx
|
||||
run: |
|
||||
# install with non-root user
|
||||
bash ./scripts/install.sh
|
||||
./fx -v
|
||||
# install with root
|
||||
sudo bash ./scripts/install.sh
|
||||
./fx -v
|
||||
57
.github/workflows/docker.yml
vendored
Normal file
57
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 12 * * *'
|
||||
name: docker
|
||||
jobs:
|
||||
Docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
|
||||
- name: login
|
||||
uses: actions/docker/login@8cdf801b322af5f369e00d85e9cf3a7122f49108
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
|
||||
- name: build-fx-go-image
|
||||
uses: actions/docker/cli@master
|
||||
with:
|
||||
args: build -t metrue/fx-go-base:latest -f api/asserts/dockerfiles/base/go/Dockerfile
|
||||
api/asserts/dockerfiles/base/go
|
||||
|
||||
- name: push-fx-go-image
|
||||
uses: actions/docker/cli@master
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
with:
|
||||
args: push metrue/fx-go-base:latest
|
||||
|
||||
- name: build-fx-rust-image
|
||||
uses: actions/docker/cli@master
|
||||
with:
|
||||
args: build -t metrue/fx-rust-base:latest -f api/asserts/dockerfiles/base/rust/Dockerfile
|
||||
api/asserts/dockerfiles/base/rust
|
||||
|
||||
- name: push-fx-rust-image
|
||||
uses: actions/docker/cli@master
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
with:
|
||||
args: push metrue/fx-rust-base:latest
|
||||
|
||||
- name: build-fx-node-image
|
||||
uses: actions/docker/cli@master
|
||||
with:
|
||||
args: build -t metrue/fx-node-base:latest -f api/asserts/dockerfiles/base/node/Dockerfile
|
||||
api/asserts/dockerfiles/base/node
|
||||
|
||||
- name: push-fx-node-image
|
||||
uses: actions/docker/cli@master
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
with:
|
||||
args: push metrue/fx-node-base:latest
|
||||
117
.github/workflows/release.yml
vendored
Normal file
117
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '*--auto-release'
|
||||
- master
|
||||
- production
|
||||
name: release
|
||||
jobs:
|
||||
Test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: setup Go 1.12
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.12
|
||||
id: go
|
||||
|
||||
- name: check out
|
||||
uses: actions/checkout@master
|
||||
|
||||
- name: setup docker
|
||||
run: |
|
||||
./scripts/provision.sh
|
||||
|
||||
- name: setup k8s and kind
|
||||
run: |
|
||||
export GOBIN=$(go env GOPATH)/bin
|
||||
export PATH=$PATH:$GOBIN
|
||||
mkdir -p $GOBIN
|
||||
curl -LO https://storage.googleapis.com/kubernetes-release/release/`curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt`/bin/linux/amd64/kubectl
|
||||
chmod +x kubectl && mv kubectl $GOBIN
|
||||
wget https://github.com/kubernetes-sigs/kind/releases/download/v0.5.0/kind-linux-amd64 && chmod +x kind-linux-amd64 && mv kind-linux-amd64 $GOBIN/kind
|
||||
./scripts/setup_kind.sh
|
||||
|
||||
- name: unit test
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
run: |
|
||||
export KUBECONFIG=/home/runner/.kube/kind-config-fx-test
|
||||
DEBUG=true go test -v ./container_runtimes/... ./deploy/...
|
||||
|
||||
- name: build fx
|
||||
run: |
|
||||
make build
|
||||
|
||||
- name: lint
|
||||
run: |
|
||||
export GOBIN=$(go env GOPATH)/bin
|
||||
export PATH=$PATH:$GOBIN
|
||||
go get -u github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
golangci-lint run
|
||||
|
||||
|
||||
- name: test fx cli
|
||||
run: |
|
||||
echo $KUBECONFIG
|
||||
unset KUBECONFIG
|
||||
make cli-test
|
||||
|
||||
- name: test AKS
|
||||
env:
|
||||
AKS_KUBECONFIG: ${{ secrets.AKS_KUBECONFIG }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
run: |
|
||||
export KUBECONFIG=${HOME}/.kube/aks
|
||||
echo ${AKS_KUBECONFIG} | base64 -d > $KUBECONFIG
|
||||
DEBUG=true ./build/fx deploy -n hello -p 12345 examples/functions/JavaScript/func.js
|
||||
./build/fx destroy hello
|
||||
rm ${KUBECONFIG}
|
||||
Release:
|
||||
runs-on: ${{ matrix.os }}
|
||||
needs: [Test]
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
# - macOS-latest
|
||||
# - windows-latest
|
||||
version:
|
||||
- latest
|
||||
# - v0.117.0
|
||||
steps:
|
||||
- name: setup Go
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: '1.12'
|
||||
- name: checkout
|
||||
uses: actions/checkout@v1
|
||||
- name: release
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GORELEASER_GITHUB_TOKEN }}
|
||||
run: |
|
||||
git config --global user.email "h.minghe@gmail.com"
|
||||
git config --global user.name "Minghe Huang"
|
||||
|
||||
commit=$(git rev-parse --short HEAD)
|
||||
version=$(cat fx.go| grep 'const version' | awk -F'"' '{print $2}')
|
||||
|
||||
echo "workflow is running on branch ${GITHUB_REF}"
|
||||
|
||||
if [[ ${GITHUB_REF} == "refs/heads/master" ]];then
|
||||
version=${version}-alpha.${commit}
|
||||
echo "alpha release $version"
|
||||
elif [[ "${GITHUB_REF}" == *--auto-release ]];then
|
||||
version=${version}-alpha.${commit}
|
||||
echo "alpha release $version"
|
||||
elif [[ ${GITHUB_REF} == "refs/heads/production" ]];then
|
||||
echo "official release $version"
|
||||
else
|
||||
echo "skip release on $GITHUB_REF"
|
||||
exit 0
|
||||
fi
|
||||
git tag -a ${version} -m "auto release"
|
||||
curl -sL https://git.io/goreleaser | bash -s -- --skip-validate
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -3,4 +3,10 @@ vendor/
|
||||
dist/
|
||||
build/
|
||||
*.pyc
|
||||
fx
|
||||
*.swp
|
||||
/fx
|
||||
/tmp
|
||||
/api/google
|
||||
/api/fx.pb.gw.go
|
||||
/api/fx.pb.go
|
||||
/coverage.txt
|
||||
|
||||
30
.golangci.yml
Normal file
30
.golangci.yml
Normal file
@@ -0,0 +1,30 @@
|
||||
run:
|
||||
deadline: 10m
|
||||
timeout: 10m
|
||||
issues-exit-code: 1
|
||||
tests: true
|
||||
skip-dirs:
|
||||
- examples
|
||||
- api/images
|
||||
- test/functions
|
||||
linters:
|
||||
enable:
|
||||
- goimports
|
||||
- stylecheck
|
||||
- gosec
|
||||
- interfacer
|
||||
- unconvert
|
||||
- goconst
|
||||
- gocyclo
|
||||
- misspell
|
||||
- unparam
|
||||
|
||||
issues:
|
||||
exclude-rules:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- gocyclo
|
||||
- goconst
|
||||
- errcheck
|
||||
- dupl
|
||||
- gosec
|
||||
@@ -1,3 +1,6 @@
|
||||
---
|
||||
env:
|
||||
- GO111MODULE=on
|
||||
builds:
|
||||
- main: fx.go
|
||||
binary: fx
|
||||
@@ -8,26 +11,24 @@ builds:
|
||||
goarch:
|
||||
- amd64
|
||||
# Archive customization
|
||||
archive:
|
||||
format: tar.gz
|
||||
replacements:
|
||||
amd64: 64-bit
|
||||
darwin: macOS
|
||||
linux: Tux
|
||||
files:
|
||||
- README.md
|
||||
brew:
|
||||
github:
|
||||
owner: metrue
|
||||
name: homebrew-fx
|
||||
commit_author:
|
||||
name: metrue
|
||||
email: h.minghe@gmail.com
|
||||
folder: Formula
|
||||
caveats: ""
|
||||
homepage: "https://github.com/metrue/fx"
|
||||
|
||||
description: "fx, a simple but powerful Function as a Service build tools"
|
||||
dependencies:
|
||||
- git
|
||||
- zsh
|
||||
archives:
|
||||
-
|
||||
format: tar.gz
|
||||
replacements:
|
||||
amd64: 64-bit
|
||||
darwin: macOS
|
||||
linux: Tux
|
||||
files:
|
||||
- README.md
|
||||
brews:
|
||||
-
|
||||
github:
|
||||
owner: metrue
|
||||
name: homebrew-fx
|
||||
commit_author:
|
||||
name: metrue
|
||||
email: h.minghe@gmail.com
|
||||
folder: Formula
|
||||
caveats: ""
|
||||
homepage: "https://github.com/metrue/fx"
|
||||
description: "fx, a simple but powerful Function as a Service build tools"
|
||||
|
||||
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,46 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at H.Minghe@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
||||
81
Gopkg.lock
generated
81
Gopkg.lock
generated
@@ -1,81 +0,0 @@
|
||||
# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
|
||||
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/Microsoft/go-winio"
|
||||
packages = ["."]
|
||||
revision = "78439966b38d69bf38227fbf57ac8a6fee70f69a"
|
||||
version = "v0.4.5"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/distribution"
|
||||
packages = ["digest","reference"]
|
||||
revision = "48294d928ced5dd9b378f7fd7c6f5da3ff3f2c89"
|
||||
version = "v2.6.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/docker"
|
||||
packages = ["api/types","api/types/blkiodev","api/types/container","api/types/events","api/types/filters","api/types/mount","api/types/network","api/types/reference","api/types/registry","api/types/strslice","api/types/swarm","api/types/time","api/types/versions","api/types/volume","client","pkg/tlsconfig"]
|
||||
revision = "092cba3727bb9b4a2f0e922cd6c0f93ea270e363"
|
||||
version = "v1.13.1"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-connections"
|
||||
packages = ["nat","sockets","tlsconfig"]
|
||||
revision = "3ede32e2033de7505e6500d6c868c2b9ed9f169d"
|
||||
version = "v0.3.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/docker/go-units"
|
||||
packages = ["."]
|
||||
revision = "0dadbb0345b35ec7ef35e228dabb8de89a65bf52"
|
||||
version = "v0.3.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
packages = ["."]
|
||||
revision = "ea4d1f681babbce9545c9c5f3d5194a789c89f5b"
|
||||
version = "v1.2.0"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "github.com/jhoonb/archivex"
|
||||
packages = ["."]
|
||||
revision = "be4efa7ec0c38ab76d56037014c90d48d6b13037"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/phayes/freeport"
|
||||
packages = ["."]
|
||||
revision = "b8543db493a5ed890c5499e935e2cad7504f3a04"
|
||||
version = "1.0.2"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/pkg/errors"
|
||||
packages = ["."]
|
||||
revision = "645ef00459ed84a119197bfb8d8205042c6df63d"
|
||||
version = "v0.8.0"
|
||||
|
||||
[[projects]]
|
||||
name = "github.com/rs/xid"
|
||||
packages = ["."]
|
||||
revision = "02dd45c33376f85d1064355dc790dcc4850596b1"
|
||||
version = "v1.1"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/net"
|
||||
packages = ["context","context/ctxhttp","proxy"]
|
||||
revision = "9dfe39835686865bff950a07b394c12a98ddc811"
|
||||
|
||||
[[projects]]
|
||||
branch = "master"
|
||||
name = "golang.org/x/sys"
|
||||
packages = ["windows"]
|
||||
revision = "0ac51a24ef1c37380f98ba8b98f56e3bffd59850"
|
||||
|
||||
[solve-meta]
|
||||
analyzer-name = "dep"
|
||||
analyzer-version = 1
|
||||
inputs-digest = "f39bdc99a6e57f902cb0bbb772098222008d68464eac29614370e04d9080c8b0"
|
||||
solver-name = "gps-cdcl"
|
||||
solver-version = 1
|
||||
43
Gopkg.toml
43
Gopkg.toml
@@ -1,43 +0,0 @@
|
||||
|
||||
# Gopkg.toml example
|
||||
#
|
||||
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
|
||||
# for detailed Gopkg.toml documentation.
|
||||
#
|
||||
# required = ["github.com/user/thing/cmd/thing"]
|
||||
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project"
|
||||
# version = "1.0.0"
|
||||
#
|
||||
# [[constraint]]
|
||||
# name = "github.com/user/project2"
|
||||
# branch = "dev"
|
||||
# source = "github.com/myfork/project2"
|
||||
#
|
||||
# [[override]]
|
||||
# name = "github.com/x/y"
|
||||
# version = "2.4.0"
|
||||
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/docker"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/docker/go-connections"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/gorilla/websocket"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/jhoonb/archivex"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/metrue/fx"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/phayes/freeport"
|
||||
|
||||
[[constraint]]
|
||||
name = "github.com/rs/xid"
|
||||
31
Makefile
31
Makefile
@@ -1,15 +1,34 @@
|
||||
OUTPUT_DIR=./build
|
||||
DIST_DIR=./dist
|
||||
|
||||
install-deps:
|
||||
@dep ensure
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
generate:
|
||||
packr
|
||||
|
||||
build:
|
||||
go build -o ${OUTPUT_DIR}/fx fx.go
|
||||
cross:
|
||||
|
||||
pull:
|
||||
./scripts/pull.sh
|
||||
|
||||
cross: generate
|
||||
goreleaser --snapshot --skip-publish --skip-validate
|
||||
release:
|
||||
goreleaser --skip-validate
|
||||
|
||||
clean:
|
||||
rm -rf ${OUTPUT_DIR}
|
||||
rm -rf ${DIST_DIR}
|
||||
.PHONY: test build start list clean
|
||||
|
||||
unit-test:
|
||||
./scripts/coverage.sh
|
||||
|
||||
cli-test:
|
||||
./scripts/test_cli.sh
|
||||
|
||||
http-test:
|
||||
./scripts/http_test.sh
|
||||
|
||||
zip:
|
||||
zip -r images.zip images/
|
||||
.PHONY: test build start list clean generate
|
||||
|
||||
358
README.md
358
README.md
@@ -1,150 +1,300 @@
|
||||
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)
|
||||

|
||||
[](https://github.com/metrue/fx/releases/latest)
|
||||
|
||||
### Introduction
|
||||
## Table of Contents
|
||||
- [Introduction](#introduction)
|
||||
- [Installation](#installation)
|
||||
- [Usage](#usage)
|
||||
- [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. The most exciting thing is that you can write your functions with most programming languages.
|
||||
|
||||
| Language | Status | Contributor |
|
||||
| ------------- |:-------------:|:-------------:|
|
||||
| Go | Supported | fx |
|
||||
| Node | Supported | fx |
|
||||
| Python | Supported | fx |
|
||||
| Ruby | Supported | fx |
|
||||
| PHP | Supported | [@chlins](https://github.com/chlins)|
|
||||
| Julia | Supported | [@mbesancon](https://github.com/mbesancon)|
|
||||
| Java | No | |
|
||||
| Scala | No | |
|
||||
| Perl | Working on | |
|
||||
| .Net | Working on | |
|
||||
| R | Working on | |
|
||||
| Rust | Working on | |
|
||||
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.
|
||||
|
||||
tweet [@_metrue](https://twitter.com/_metrue) or issue is welcome.
|
||||
|
||||
### Usage
|
||||
| Language | Status | Contributor | Example |
|
||||
| ------------- |:-------------:|:-------------:| :-------------:|
|
||||
| Go | Supported | fx | [/examples/Golang](https://github.com/metrue/fx/tree/master/examples/functions/Golang) |
|
||||
| Rust | Supported | [@FrontMage](https://github.com/FrontMage)| [/examples/Rust](https://github.com/metrue/fx/tree/master/examples/functions/Rust) |
|
||||
| Node | Supported | fx | [/examples/JavaScript](https://github.com/metrue/fx/tree/master/examples/functions/JavaScript) |
|
||||
| Python | Supported | fx | [/examples/Python](https://github.com/metrue/fx/tree/master/examples/functions/Python) |
|
||||
| Ruby | Supported | fx | [/examples/Ruby](https://github.com/metrue/fx/tree/master/examples/functions/Ruby) |
|
||||
| Java | Supported | fx | [/examples/Java](https://github.com/metrue/fx/tree/master/examples/functions/Java) |
|
||||
| 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) |
|
||||
| R | Working on [need your help](https://github.com/metrue/fx/issues/31) | ||
|
||||
|
||||
##### Requirements
|
||||
* Docker: make sure [Docker](https://docs.docker.com/engine/installation/) installed and running on your server.
|
||||
* dep: fx project uses [dep](https://github.com/golang/dep) to do the golang dependency management.
|
||||
# Installation
|
||||
|
||||
##### Build and Run
|
||||
* MacOS
|
||||
|
||||
```
|
||||
$ git clone https://github.com/metrue/fx.git
|
||||
$ cd fx
|
||||
$ dep ensure
|
||||
$ go install ./
|
||||
brew tap metrue/homebrew-fx
|
||||
brew install metrue/fx/fx
|
||||
```
|
||||
|
||||
* start server
|
||||
* Linux/Unix
|
||||
|
||||
```
|
||||
fx serve
|
||||
via cURL
|
||||
|
||||
```shell
|
||||
# Install to local directory
|
||||
curl -o- https://raw.githubusercontent.com/metrue/fx/master/scripts/install.sh | bash
|
||||
|
||||
# Install to /usr/local/bin/
|
||||
curl -o- https://raw.githubusercontent.com/metrue/fx/master/scripts/install.sh | sudo bash
|
||||
```
|
||||
|
||||
now you can make a function to service in a second.
|
||||
fx will be installed into /usr/local/bin, sometimes you may need `source ~/.zshrc` or `source ~/.bashrc` to make fx available in `$PAHT`.
|
||||
|
||||
* Window
|
||||
|
||||
You can go the release page to [download](https://github.com/metrue/fx/releases) fx manually;
|
||||
|
||||
## 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.
|
||||
|
||||
```
|
||||
fx up ./examples/functions/func.js
|
||||
NAME:
|
||||
fx - makes function as a service
|
||||
|
||||
USAGE:
|
||||
fx [global options] command [command options] [arguments...]
|
||||
|
||||
VERSION:
|
||||
0.6.0
|
||||
|
||||
COMMANDS:
|
||||
infra manage infrastructure of fx
|
||||
image manage image of service
|
||||
doctor health check for fx
|
||||
up deploy a function or a group of functions
|
||||
down destroy a service
|
||||
list, ls list deployed services
|
||||
call run a function instantly
|
||||
help, h Shows a list of commands or help for one command
|
||||
|
||||
GLOBAL OPTIONS:
|
||||
--help, -h show help
|
||||
--version, -v print the version
|
||||
```
|
||||
|
||||
the function defined in *examples/functions/func.js* is quite simple, it calculates the sum of two numbers then returns:
|
||||
1. List your current machines and activate you machine
|
||||
|
||||
```shell
|
||||
$ fx infra ls # list machines
|
||||
|
||||
{
|
||||
"localhost": {
|
||||
"Host": "localhost",
|
||||
"User": "",
|
||||
"Password": "",
|
||||
"Enabled": true,
|
||||
"Provisioned": false
|
||||
}
|
||||
}
|
||||
|
||||
$ fx infra activate localhost # activate 'localhost'
|
||||
|
||||
2019/08/10 13:21:20 info Provision:pull python Docker base iamge: ✓
|
||||
2019/08/10 13:21:21 info Provision:pull d Docker base image: ✓
|
||||
2019/08/10 13:21:23 info Provision:pull java Docker base image: ✓
|
||||
2019/08/10 13:21:28 info Provision:pull julia Docker base image: ✓
|
||||
2019/08/10 13:21:31 info Provision:pull node Docker base image: ✓
|
||||
2019/08/10 13:22:09 info Provision:pull go Docker base image: ✓
|
||||
2019/08/10 13:22:09 info provision machine localhost: ✓
|
||||
2019/08/10 13:22:09 info enble machine localhost: ✓
|
||||
```
|
||||
module.exports = (input) => {
|
||||
return parseInt(input.a, 10) + parseInt(input.b, 10)
|
||||
It may take seconds since `fx` needs to download some basic resources
|
||||
|
||||
*Note* you can add a remote host as fx machine also,
|
||||
```
|
||||
$ fx infra add --name my_aws_vm --host 13.121.202.227 --user root --password yourpassword
|
||||
|
||||
$ fx infra list
|
||||
{
|
||||
"my_aws_vm": {
|
||||
"Host": "13.121.202.227",
|
||||
"User": "root",
|
||||
"Password": "yourpassword",
|
||||
"Enabled": false,
|
||||
"Provisioned": false
|
||||
},
|
||||
"localhost": {
|
||||
"Host": "localhost",
|
||||
"User": "",
|
||||
"Password": "",
|
||||
"Enabled": true,
|
||||
"Provisioned": true
|
||||
}
|
||||
}
|
||||
|
||||
$ fx infra activate my_aws_vm
|
||||
|
||||
```
|
||||
then your function will be deployed onto remote host also.
|
||||
|
||||
2. Write a function
|
||||
|
||||
You can check out [examples](https://github.com/metrue/fx/tree/master/examples/functions) for reference. Let's write a function as an example, it calculates the sum of two numbers then returns:
|
||||
|
||||
```js
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello world'
|
||||
}
|
||||
```
|
||||
Then save it to a file `func.js`.
|
||||
|
||||
3. Deploy your function as a service
|
||||
|
||||
Give your service a port with `--port`, and name with `--name`, heath checking with `--healthcheck` if you want.
|
||||
|
||||
```shell
|
||||
$ fx up -name fx_service_name -p 10001 --healthcheck func.js
|
||||
|
||||
2019/08/10 13:26:37 info Pack Service: ✓
|
||||
2019/08/10 13:26:39 info Build Service: ✓
|
||||
2019/08/10 13:26:39 info Run Service: ✓
|
||||
2019/08/10 13:26:39 info Service (fx_service_name) is running on: 0.0.0.0:10001
|
||||
2019/08/10 13:26:39 info up function fx_service_name(func.js) to machine localhost: ✓
|
||||
```
|
||||
|
||||
if you want see what the source code of your service looks like, you can export it into a dirctory,
|
||||
|
||||
```shell
|
||||
$ fx image export -o <path of dir> func.js
|
||||
2019/09/25 19:31:19 info exported to <path of dir>: ✓
|
||||
```
|
||||
|
||||
4. Test your service
|
||||
|
||||
then you can test your service:
|
||||
```
|
||||
curl -X POST <service url> -H "Content-Type: application/json" -d '{"a": 1, "b": 1}'
|
||||
|
||||
```shell
|
||||
$ curl -v 0.0.0.0:10001
|
||||
|
||||
|
||||
GET / HTTP/1.1
|
||||
Accept: */*
|
||||
Accept-Encoding: gzip, deflate
|
||||
Connection: keep-alive
|
||||
Host: 0.0.0.0:10001
|
||||
User-Agent: HTTPie/1.0.2
|
||||
|
||||
|
||||
|
||||
HTTP/1.1 200 OK
|
||||
Connection: keep-alive
|
||||
Content-Length: 11
|
||||
Content-Type: text/plain; charset=utf-8
|
||||
Date: Sat, 10 Aug 2019 05:28:03 GMT
|
||||
|
||||
hello world
|
||||
|
||||
```
|
||||
|
||||
of course you can do more.
|
||||
```
|
||||
Usage:
|
||||
$ fx serve start f(x) server
|
||||
$ fx up func1.js func2.py func3.go ... deploy a function or a group of functions
|
||||
$ fx down [service ID] ... destroy a function or a group of functions
|
||||
$ fx list list deployed services
|
||||
$ fx --version show current version of f(x)
|
||||
## Docker
|
||||
|
||||
TODO
|
||||
|
||||
## Kubernetes
|
||||
|
||||
**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.
|
||||
|
||||
```shell
|
||||
KUBECONFIG=<Your KUBECONFIG> fx deploy -n fx-service-abc_js -p 12349 examples/functions/JavaScript/func.js # function will be deploy to your Kubernetes cluster and expose a IP address of your loadbalencer
|
||||
```
|
||||
|
||||
#### How to write your function
|
||||
or
|
||||
|
||||
functions example with Go, Ruby, Python, Node, PHP.
|
||||
|
||||
* Go
|
||||
```
|
||||
package main
|
||||
|
||||
type Input struct {
|
||||
A int32
|
||||
B int32
|
||||
}
|
||||
|
||||
type Output struct {
|
||||
Sum int32
|
||||
}
|
||||
|
||||
func Fx(input *Input) (output *Output) {
|
||||
output = &Output{
|
||||
Sum: input.A + input.B,
|
||||
}
|
||||
return
|
||||
}
|
||||
```shell
|
||||
$ export KUBECONFIG=<Your KUBECONFIG>
|
||||
$ fx deploy -n fx-service-abc_js -p 12349 examples/functions/JavaScript/func.js # function will be deploy to your Kubernetes cluster and expose a IP address of your loadbalencer
|
||||
```
|
||||
|
||||
* Ruby
|
||||
```
|
||||
def fx(input)
|
||||
return input['a'] + input['b']
|
||||
end
|
||||
* Local Kubernetes Cluster
|
||||
|
||||
Docker for Mac and Docker for Windows already support Kubernetes with single node cluster, we can use it directly, and the default `KUBECONFIG` is `~/.kube/config`.
|
||||
|
||||
```shell
|
||||
$ export KUBECONFIG=~/.kube/config # then fx will take the config to deloy function
|
||||
```
|
||||
|
||||
* Python
|
||||
```
|
||||
def fx(input):
|
||||
return input['a'] + input['b']
|
||||
if you have multiple Kubernetes clusters configured, you have to set context correctly. FYI [configure-access-multiple-clusters](https://kubernetes.io/docs/tasks/access-application-cluster/configure-access-multiple-clusters/)
|
||||
|
||||
* Azure Kubernetes Service (AKS)
|
||||
|
||||
You should create a Kubernetes cluster if you don't have one on AKS, detail document can found [here](https://docs.microsoft.com/en-us/azure/aks/kubernetes-walkthrough).
|
||||
|
||||
```shell
|
||||
$ az group create --name <myResourceGroup> --location eastus
|
||||
$ az aks create --resource-group <myResourceGroup> --name myAKSCluster --node-count <count>
|
||||
$ az aks get-credentials --resource-group <myResourceGroup> --name <myAKSCluster>
|
||||
```
|
||||
|
||||
* Node
|
||||
```
|
||||
module.exports = (input) => {
|
||||
return parseInt(input.a, 10) + parseInt(input.b, 10)
|
||||
}
|
||||
Then you can verify it with `kubectl`,
|
||||
|
||||
```shell
|
||||
$ kubectl get nodes
|
||||
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
aks-nodepool1-31718369-0 Ready agent 6m44s v1.12.8
|
||||
```
|
||||
|
||||
* PHP
|
||||
```
|
||||
<?php
|
||||
function Fx($input) {
|
||||
return $input["a"]+$input["b"];
|
||||
}
|
||||
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
|
||||
```
|
||||
|
||||
* Julia
|
||||
```
|
||||
struct Input
|
||||
a::Number
|
||||
b::Number
|
||||
end
|
||||
But we would suggest you run `kubectl config current-context` to check if the current context is what you want.
|
||||
|
||||
fx = function(input::Input)
|
||||
return input.a + input.b
|
||||
end
|
||||
* Amazon Elastic Kubernetes Service (EKS)
|
||||
TODO
|
||||
|
||||
* Google Kubernetes Engine (GKET)
|
||||
TODO
|
||||
|
||||
## Contribute
|
||||
|
||||
fx uses [Project](https://github.com/metrue/fx/projects/4) to manage the development.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
Docker: make sure [Docker](https://docs.docker.com/engine/installation/) installed and running on your server.
|
||||
|
||||
|
||||
#### Build & Test
|
||||
|
||||
```
|
||||
$ git clone https://github.com/metrue/fx
|
||||
$ cd fx
|
||||
$ make build
|
||||
```
|
||||
|
||||
### Contributors
|
||||
Then you can build and test:
|
||||
|
||||
```
|
||||
$ make build
|
||||
$ ./build/fx -h
|
||||
```
|
||||
|
||||
|
||||
## Contributors
|
||||
|
||||
Thank you to all the people who already contributed to fx!
|
||||
|
||||
@@ -157,6 +307,12 @@ Thank you to all the people who already contributed to fx!
|
||||
<a href="https://github.com/pplam" target="_blank">
|
||||
<img alt="pplam" src="https://avatars2.githubusercontent.com/u/12783579?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/muka" target="_blank">
|
||||
<img alt="muka" src="https://avatars2.githubusercontent.com/u/1021269?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/xwjdsh" target="_blank">
|
||||
<img alt="xwjdsh" src="https://avatars2.githubusercontent.com/u/11025519?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/mbesancon" target="_blank">
|
||||
<img alt="mbesancon" src="https://avatars2.githubusercontent.com/u/7623090?v=4&s=50" width="50">
|
||||
</a>
|
||||
@@ -169,10 +325,12 @@ Thank you to all the people who already contributed to fx!
|
||||
<a href="https://github.com/chlins" target="_blank">
|
||||
<img alt="chlins" src="https://avatars2.githubusercontent.com/u/31262637?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/andre2007" target="_blank">
|
||||
<img alt="andre2007" src="https://avatars1.githubusercontent.com/u/1451047?s=50&v=4" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/steventhanna" target="_blank">
|
||||
<img alt="andre2007" src="https://avatars1.githubusercontent.com/u/2541678?s=50&v=4" width="50">
|
||||
</a>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
### LICENSE
|
||||
|
||||
MIT
|
||||
|
||||
5
assets/dockerfiles/base/d/Dockerfile
vendored
Normal file
5
assets/dockerfiles/base/d/Dockerfile
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y build-essential curl libcurl3 \
|
||||
&& curl -OL http://downloads.dlang.org/releases/2.x/2.077.1/dmd_2.077.1-0_amd64.deb \
|
||||
&& apt install ./dmd_2.077.1-0_amd64.deb
|
||||
12
assets/dockerfiles/base/java/Dockerfile
vendored
Normal file
12
assets/dockerfiles/base/java/Dockerfile
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
FROM java:8
|
||||
|
||||
# Install maven
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y maven
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
# Prepare by downloading dependencies
|
||||
ADD pom.xml /code/pom.xml
|
||||
RUN ["mvn", "dependency:resolve"]
|
||||
RUN ["mvn", "verify"]
|
||||
3
assets/dockerfiles/base/java/Makefile
vendored
Normal file
3
assets/dockerfiles/base/java/Makefile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t metrue/fx-java-base:latest .
|
||||
docker push metrue/fx-java-base
|
||||
51
assets/dockerfiles/base/java/pom.xml
vendored
Normal file
51
assets/dockerfiles/base/java/pom.xml
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>fx-app-java</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.1.0</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>fx.app</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.javalin</groupId>
|
||||
<artifactId>javalin</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20171018</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
3
assets/dockerfiles/base/julia/Dockerfile
vendored
Normal file
3
assets/dockerfiles/base/julia/Dockerfile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM julia:latest
|
||||
|
||||
RUN apt-get update && apt-get install -y gcc apt-utils unzip make libhttp-parser-dev
|
||||
3
assets/dockerfiles/base/julia/Makefile
vendored
Normal file
3
assets/dockerfiles/base/julia/Makefile
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t metrue/fx-julia-base:latest .
|
||||
docker push metrue/fx-julia-base
|
||||
4
assets/dockerfiles/base/node/Dockerfile
vendored
Normal file
4
assets/dockerfiles/base/node/Dockerfile
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
FROM node:latest
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
@@ -3,6 +3,3 @@ FROM python:3
|
||||
RUN pip install flask
|
||||
ENV FLASK_APP=app.py
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD flask run -h 0.0.0.0 -p 3000
|
||||
970
assets/dockerfiles/base/rust/Cargo.lock
generated
vendored
Normal file
970
assets/dockerfiles/base/rust/Cargo.lock
generated
vendored
Normal file
@@ -0,0 +1,970 @@
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise_codegen"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise_core"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isatty"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear_codegen"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_codegen 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_codegen"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_contrib"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_http"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_contrib 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "safemem"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "state"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-executor"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-io"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "traitobject"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typeable"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
|
||||
"checksum crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c55913cc2799171a550e307918c0a360e8c16004820291bf3b638969b4a01816"
|
||||
"checksum devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3"
|
||||
"checksum devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7"
|
||||
"checksum devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487"
|
||||
"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
|
||||
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
|
||||
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
|
||||
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
|
||||
"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c"
|
||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
|
||||
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
|
||||
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "873ecfd8c174964ae30f401329d140142312c8e5590719cf1199d5f1717d8078"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
|
||||
"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
|
||||
"checksum pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c26d2b92e47063ffce70d3e3b1bd097af121a9e0db07ca38a6cc1cf0cc85ff25"
|
||||
"checksum pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "336db4a192cc7f54efeb0c4e11a9245394824cc3bcbd37ba3ff51240c35d7a6e"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
|
||||
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
|
||||
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||
"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
|
||||
"checksum rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eaa997ea8de9b14112aa38b2b6a0ecf3e651ff2c08d2fdf384fa765b5f9c2c98"
|
||||
"checksum rocket_codegen 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fc68f90452ac88c6c1e02a922a0a23ef0ade08f9af899056d0c919b25fa7768c"
|
||||
"checksum rocket_contrib 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc6a37cb7a6256efe6648f2d0ab9978c49ab883909ea4fabefb81d7c685d841"
|
||||
"checksum rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d555ce896830602aedf4bce2eec8d64713d45a2492c5a3625c3faa5f719b0f"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
|
||||
"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
|
||||
"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811"
|
||||
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
|
||||
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
|
||||
"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde"
|
||||
"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21"
|
||||
"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5"
|
||||
"checksum toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "19782e145d5abefb03758958f06ea35f7b1d8421b534140e0238fd3d0bfd66e3"
|
||||
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
|
||||
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
|
||||
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48"
|
||||
"checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
|
||||
13
assets/dockerfiles/base/rust/Cargo.toml
vendored
Normal file
13
assets/dockerfiles/base/rust/Cargo.toml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rust"
|
||||
version = "0.1.0"
|
||||
authors = ["FrontMage <xbgxwh@outlook.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.4.0-rc.2"
|
||||
rocket_contrib = "0.4.0-rc.2"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0.70"
|
||||
serde = "1.0.70"
|
||||
|
||||
7
assets/dockerfiles/base/rust/Dockerfile
vendored
Normal file
7
assets/dockerfiles/base/rust/Dockerfile
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
FROM liuchong/rustup
|
||||
|
||||
WORKDIR /usr/src/myapp
|
||||
COPY . .
|
||||
RUN cp ./config ~/.cargo/ && rustup default nightly && cargo build
|
||||
EXPOSE 3000
|
||||
CMD ["cargo", "run"]
|
||||
5
assets/dockerfiles/base/rust/Rocket.toml
vendored
Normal file
5
assets/dockerfiles/base/rust/Rocket.toml
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
[development]
|
||||
address = "0.0.0.0"
|
||||
port = 3000
|
||||
log = "normal"
|
||||
|
||||
6
assets/dockerfiles/base/rust/config
vendored
Normal file
6
assets/dockerfiles/base/rust/config
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
[source.crates-io]
|
||||
registry = "https://github.com/rust-lang/crates.io-index"
|
||||
replace-with = 'ustc'
|
||||
[source.ustc]
|
||||
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
|
||||
|
||||
18
assets/dockerfiles/base/rust/src/fns/mod.rs
vendored
Normal file
18
assets/dockerfiles/base/rust/src/fns/mod.rs
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
pub mod fns {
|
||||
#[derive(Serialize)]
|
||||
pub struct Response {
|
||||
pub result: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Request {
|
||||
pub a: i32,
|
||||
pub b: i32,
|
||||
}
|
||||
|
||||
pub fn func(req: Request) -> Response {
|
||||
Response {
|
||||
result: req.a + req.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
22
assets/dockerfiles/base/rust/src/main.rs
vendored
Normal file
22
assets/dockerfiles/base/rust/src/main.rs
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
#![feature(proc_macro_hygiene, decl_macro, plugin)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
extern crate rocket_contrib;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
mod fns;
|
||||
|
||||
use rocket_contrib::json::Json;
|
||||
|
||||
#[post("/", format = "application/json", data = "<req>")]
|
||||
fn index(req: Json<fns::fns::Request>) -> Json<fns::fns::Response> {
|
||||
Json(fns::fns::func(req.0))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite().mount("/", routes![index]).launch();
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
package common
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
type argPtrs struct {
|
||||
addr *string
|
||||
help *bool
|
||||
}
|
||||
|
||||
func SetupFlags(option string) (
|
||||
args *argPtrs,
|
||||
flagSet *flag.FlagSet,
|
||||
) {
|
||||
flagSet = flag.NewFlagSet(option, flag.ExitOnError)
|
||||
args = &argPtrs{
|
||||
addr: flagSet.String(
|
||||
"addr",
|
||||
"localhost:8080",
|
||||
"Server address.",
|
||||
),
|
||||
help: flagSet.Bool(
|
||||
"help",
|
||||
false,
|
||||
"Help information.",
|
||||
),
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func ParseArgs(
|
||||
option string,
|
||||
s []string,
|
||||
ptrs *argPtrs,
|
||||
fs *flag.FlagSet,
|
||||
) (funcs []string, addr string) {
|
||||
home := os.Getenv("HOME")
|
||||
configFile := path.Join(home, ".fx")
|
||||
buf, _ := ioutil.ReadFile(configFile)
|
||||
if len(buf) > 0 {
|
||||
fs.Set("addr", string(buf))
|
||||
}
|
||||
|
||||
fs.Parse(s)
|
||||
|
||||
if *(ptrs.help) {
|
||||
FlagsAndExit(fs)
|
||||
}
|
||||
|
||||
u := url.URL{
|
||||
Scheme: "ws",
|
||||
Host: *(ptrs.addr),
|
||||
Path: "/" + option,
|
||||
}
|
||||
addr = u.String()
|
||||
|
||||
if fs.NFlag() == 0 {
|
||||
funcs = s
|
||||
} else {
|
||||
funcs = fs.Args()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func FlagsAndExit(fs *flag.FlagSet) {
|
||||
fmt.Println("Flags:")
|
||||
fs.PrintDefaults()
|
||||
os.Exit(0)
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package down
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/metrue/fx/commands/common"
|
||||
)
|
||||
|
||||
func Down() {
|
||||
option := "down"
|
||||
nArgs := len(os.Args)
|
||||
args, flagSet := common.SetupFlags(option)
|
||||
if nArgs == 2 {
|
||||
common.FlagsAndExit(flagSet)
|
||||
}
|
||||
functions, address := common.ParseArgs(
|
||||
option,
|
||||
os.Args[2:],
|
||||
args,
|
||||
flagSet,
|
||||
)
|
||||
|
||||
dialer := websocket.Dialer{}
|
||||
conn, _, err := dialer.Dial(address, nil)
|
||||
if checkErr(err) {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
err = conn.WriteMessage(
|
||||
websocket.TextMessage,
|
||||
[]byte(strings.Join(functions, " ")),
|
||||
)
|
||||
if checkErr(err) {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
_, msg, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
if websocket.IsCloseError(err, 1000) {
|
||||
return
|
||||
}
|
||||
fmt.Println(err)
|
||||
if websocket.IsUnexpectedCloseError(err, 1000) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
fmt.Println(string(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func checkErr(err error) bool {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package list
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/metrue/fx/commands/common"
|
||||
)
|
||||
|
||||
// List lists all running function services
|
||||
func List() {
|
||||
option := "list"
|
||||
nArgs := len(os.Args)
|
||||
args, flagSet := common.SetupFlags(option)
|
||||
if nArgs < 2 {
|
||||
common.FlagsAndExit(flagSet)
|
||||
}
|
||||
functions, address := common.ParseArgs(
|
||||
option,
|
||||
os.Args[2:],
|
||||
args,
|
||||
flagSet,
|
||||
)
|
||||
|
||||
dialer := websocket.Dialer{}
|
||||
conn, _, err := dialer.Dial(address, nil)
|
||||
if checkErr(err) {
|
||||
return
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
err = conn.WriteMessage(
|
||||
websocket.TextMessage,
|
||||
[]byte(strings.Join(functions, " ")),
|
||||
)
|
||||
if checkErr(err) {
|
||||
return
|
||||
}
|
||||
|
||||
for {
|
||||
_, msg, err := conn.ReadMessage()
|
||||
if err != nil {
|
||||
if websocket.IsCloseError(err, 1000) {
|
||||
return
|
||||
}
|
||||
fmt.Println(err)
|
||||
if websocket.IsUnexpectedCloseError(err, 1000) {
|
||||
return
|
||||
}
|
||||
continue
|
||||
}
|
||||
fmt.Println(string(msg))
|
||||
}
|
||||
}
|
||||
|
||||
func checkErr(err error) bool {
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package up
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// Logger is a customer wrapped logger
|
||||
type Logger struct {
|
||||
base *log.Logger
|
||||
log.Logger
|
||||
}
|
||||
|
||||
// Log outputs an object to stdout
|
||||
func (l *Logger) Log(v interface{}) {
|
||||
l.base.SetOutput(os.Stdout)
|
||||
l.base.Print(v)
|
||||
}
|
||||
|
||||
// Err outputs an object to stderr
|
||||
func (l *Logger) Err(v interface{}) {
|
||||
l.base.SetOutput(os.Stderr)
|
||||
l.base.Print(v)
|
||||
}
|
||||
|
||||
// NewLogger creates a new wrapped log.Logger with default values
|
||||
func NewLogger(prefix string) *Logger {
|
||||
return &Logger{
|
||||
base: log.New(
|
||||
os.Stdout,
|
||||
prefix,
|
||||
log.LstdFlags,
|
||||
),
|
||||
}
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
package up
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"github.com/metrue/fx/commands/common"
|
||||
"github.com/metrue/fx/config"
|
||||
)
|
||||
|
||||
// Up starts the functions specified in flags
|
||||
func Up() {
|
||||
option := "up"
|
||||
nArgs := len(os.Args)
|
||||
args, flagSet := common.SetupFlags(option)
|
||||
if nArgs == 2 {
|
||||
common.FlagsAndExit(flagSet)
|
||||
}
|
||||
functions, address := common.ParseArgs(
|
||||
option,
|
||||
os.Args[2:],
|
||||
args,
|
||||
flagSet,
|
||||
)
|
||||
|
||||
fmt.Println("Deploy starting...")
|
||||
dialer := websocket.Dialer{}
|
||||
|
||||
channel := make(chan bool)
|
||||
defer close(channel)
|
||||
|
||||
numSuccess := 0
|
||||
numFail := 0
|
||||
|
||||
for _, function := range functions {
|
||||
conn, _, err := dialer.Dial(address, nil)
|
||||
if err != nil {
|
||||
log.Print(err)
|
||||
numFail++
|
||||
continue
|
||||
}
|
||||
lang := config.ExtLangMap[filepath.Ext(function)]
|
||||
worker := NewWorker(function, lang, conn, channel)
|
||||
go worker.Work()
|
||||
}
|
||||
|
||||
// Loop until all function deploy done
|
||||
loop:
|
||||
for {
|
||||
select {
|
||||
case status := <-channel:
|
||||
if status {
|
||||
numSuccess++
|
||||
} else {
|
||||
numFail++
|
||||
}
|
||||
default:
|
||||
if numSuccess+numFail == len(functions) {
|
||||
fmt.Printf("Succed: %d\n", numSuccess)
|
||||
fmt.Printf("Failed: %d\n", numFail)
|
||||
fmt.Println("All deploy done!")
|
||||
break loop
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
package up
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"os/signal"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
// Worker handles a functional service
|
||||
type Worker struct {
|
||||
conn *websocket.Conn
|
||||
ch chan<- bool
|
||||
src string
|
||||
lang string
|
||||
logger *Logger
|
||||
dead bool
|
||||
}
|
||||
|
||||
// NewWorker creates and returns a new worker
|
||||
func NewWorker(src, lang string, conn *websocket.Conn, ch chan<- bool) *Worker {
|
||||
worker := &Worker{
|
||||
src: src,
|
||||
lang: lang,
|
||||
conn: conn,
|
||||
ch: ch,
|
||||
logger: NewLogger("[" + src + "]"),
|
||||
}
|
||||
worker.conn.SetCloseHandler(worker.closeHandler)
|
||||
return worker
|
||||
}
|
||||
|
||||
func (worker *Worker) checkErr(err error) bool {
|
||||
if err != nil {
|
||||
worker.logger.Err(err)
|
||||
if !websocket.IsCloseError(err, 1000) {
|
||||
worker.ch <- false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (worker *Worker) closeHandler(
|
||||
code int,
|
||||
msg string,
|
||||
) error {
|
||||
worker.dead = true
|
||||
if msg == "0" {
|
||||
worker.ch <- true
|
||||
worker.logger.Log(msg)
|
||||
} else {
|
||||
worker.ch <- false
|
||||
worker.logger.Err(msg)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Work starts and handles a function from Worker's information
|
||||
func (worker *Worker) Work() {
|
||||
if worker.dead {
|
||||
return
|
||||
}
|
||||
logger := worker.logger
|
||||
conn := worker.conn
|
||||
logger.Log("Deploying...")
|
||||
// Open function source file
|
||||
file, err := os.Open(worker.src)
|
||||
if worker.checkErr(err) {
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
// Send source language type
|
||||
err = conn.WriteMessage(
|
||||
websocket.TextMessage,
|
||||
[]byte(worker.lang),
|
||||
)
|
||||
if worker.checkErr(err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Get websocket connection writer
|
||||
writer, err := conn.NextWriter(
|
||||
websocket.TextMessage,
|
||||
)
|
||||
if worker.checkErr(err) {
|
||||
return
|
||||
}
|
||||
|
||||
// Send function source file
|
||||
bytesSent, err := io.Copy(
|
||||
writer,
|
||||
file,
|
||||
)
|
||||
if worker.checkErr(err) {
|
||||
return
|
||||
}
|
||||
logger.Log(
|
||||
fmt.Sprintf(
|
||||
"Sent bytes: %d",
|
||||
bytesSent,
|
||||
))
|
||||
err = writer.Close()
|
||||
if worker.checkErr(err) {
|
||||
return
|
||||
}
|
||||
|
||||
interrupt := make(chan os.Signal, 2)
|
||||
signal.Notify(interrupt, os.Interrupt, os.Kill)
|
||||
|
||||
errChan := make(chan error)
|
||||
msgChan := make(chan string)
|
||||
readReply := func(
|
||||
c *websocket.Conn,
|
||||
msgCh chan<- string,
|
||||
errCh chan<- error,
|
||||
) {
|
||||
_, msg, err := c.ReadMessage()
|
||||
if err != nil {
|
||||
errCh <- err
|
||||
return
|
||||
}
|
||||
msgCh <- string(msg)
|
||||
}
|
||||
go readReply(conn, msgChan, errChan)
|
||||
|
||||
// Wait for deploy done
|
||||
for {
|
||||
select {
|
||||
case <-interrupt:
|
||||
closeMsg := websocket.FormatCloseMessage(1000, "1")
|
||||
conn.WriteMessage(websocket.CloseMessage, closeMsg)
|
||||
case newMsg := <-msgChan:
|
||||
logger.Log(newMsg)
|
||||
if worker.dead {
|
||||
return
|
||||
}
|
||||
go readReply(conn, msgChan, errChan)
|
||||
case newErr := <-errChan:
|
||||
if worker.checkErr(newErr) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
216
config/config.go
216
config/config.go
@@ -1,27 +1,213 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
// Server contains the server configuration information
|
||||
var Server = map[string]string{
|
||||
"host": "localhost",
|
||||
"port": "8080",
|
||||
// Configer interface
|
||||
type Configer interface {
|
||||
GetMachine(name string) (Host, error)
|
||||
AddMachine(name string, host Host) error
|
||||
RemoveHost(name string) error
|
||||
ListActiveMachines() (map[string]Host, error)
|
||||
ListMachines() (map[string]Host, error)
|
||||
EnableMachine(name string) error
|
||||
DisableMachine(name string) error
|
||||
UpdateProvisionedStatus(name string, ok bool) error
|
||||
}
|
||||
|
||||
// Client contains the local and remote paths to fetch cached images
|
||||
var Client = map[string]string{
|
||||
"cache_dir": path.Join(os.Getenv("HOME"), ".fx/"),
|
||||
"remote_images_url": "https://raw.githubusercontent.com/metrue/fx/master/images.zip",
|
||||
// Config config of fx
|
||||
type Config struct {
|
||||
dir string
|
||||
}
|
||||
|
||||
var ExtLangMap = map[string]string {
|
||||
".js": "node",
|
||||
".go": "go",
|
||||
".rb": "ruby",
|
||||
".py": "python",
|
||||
".php": "php",
|
||||
".jl": "julia",
|
||||
// New create a config
|
||||
func New(dir string) *Config {
|
||||
return &Config{dir: dir}
|
||||
}
|
||||
|
||||
// Init config
|
||||
func (c *Config) Init() error {
|
||||
if err := os.MkdirAll(c.dir, os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ext := "yaml"
|
||||
name := "config"
|
||||
viper.SetConfigType(ext)
|
||||
viper.SetConfigName(name)
|
||||
viper.AddConfigPath(c.dir)
|
||||
|
||||
// detect if file exists
|
||||
configFilePath := path.Join(c.dir, name+"."+ext)
|
||||
if _, err := os.Stat(configFilePath); os.IsNotExist(err) {
|
||||
fd, err := os.Create(configFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fd.Close()
|
||||
|
||||
localhost := Host{
|
||||
Host: "localhost",
|
||||
Password: "",
|
||||
User: "",
|
||||
Enabled: true,
|
||||
Provisioned: false,
|
||||
}
|
||||
viper.Set("hosts", map[string]Host{"localhost": localhost})
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
return fmt.Errorf("fatal error config file: %s", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetMachine get host by name
|
||||
func (c *Config) GetMachine(name string) (Host, error) {
|
||||
var hosts map[string]Host
|
||||
if err := viper.UnmarshalKey("hosts", &hosts); err != nil {
|
||||
return Host{}, err
|
||||
}
|
||||
host, ok := hosts[name]
|
||||
if !ok {
|
||||
return Host{}, fmt.Errorf("no such host %v", name)
|
||||
}
|
||||
return host, nil
|
||||
}
|
||||
|
||||
// ListActiveMachines list enabled machines
|
||||
func (c *Config) ListActiveMachines() (map[string]Host, error) {
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
return map[string]Host{}, err
|
||||
}
|
||||
lst := map[string]Host{}
|
||||
for name, h := range hosts {
|
||||
if h.Enabled {
|
||||
lst[name] = h
|
||||
}
|
||||
}
|
||||
return lst, nil
|
||||
}
|
||||
|
||||
// AddMachine add host
|
||||
func (c *Config) AddMachine(name string, host Host) error {
|
||||
if !viper.IsSet("hosts") {
|
||||
viper.Set("hosts", map[string]Host{})
|
||||
}
|
||||
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hosts[name] = host
|
||||
viper.Set("hosts", hosts)
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
|
||||
// RemoveHost remote a host
|
||||
func (c *Config) RemoveHost(name string) error {
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(hosts) == 1 {
|
||||
return fmt.Errorf("only one host left now, at least one host required by fx")
|
||||
}
|
||||
|
||||
if _, ok := hosts[name]; ok {
|
||||
delete(hosts, name)
|
||||
|
||||
viper.Set("hosts", hosts)
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
return fmt.Errorf("no such host %s", name)
|
||||
}
|
||||
|
||||
// ListMachines list hosts
|
||||
func (c *Config) ListMachines() (map[string]Host, error) {
|
||||
var hosts map[string]Host
|
||||
if err := viper.UnmarshalKey("hosts", &hosts); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
// EnableMachine enable a machine, after machine enabled, function will be deployed onto it when ever `fx up` invoked
|
||||
func (c *Config) EnableMachine(name string) error {
|
||||
host, err := c.GetMachine(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.Enabled = true
|
||||
|
||||
if !viper.IsSet("hosts") {
|
||||
viper.Set("hosts", map[string]Host{})
|
||||
}
|
||||
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hosts[name] = host
|
||||
viper.Set("hosts", hosts)
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
|
||||
// DisableMachine disable a machine, after machine disabled, function will not be deployed onto it
|
||||
func (c *Config) DisableMachine(name string) error {
|
||||
host, err := c.GetMachine(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.Enabled = false
|
||||
|
||||
if !viper.IsSet("hosts") {
|
||||
viper.Set("hosts", map[string]Host{})
|
||||
}
|
||||
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hosts[name] = host
|
||||
viper.Set("hosts", hosts)
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
|
||||
// UpdateProvisionedStatus update provisioned status
|
||||
func (c *Config) UpdateProvisionedStatus(name string, ok bool) error {
|
||||
host, err := c.GetMachine(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
host.Provisioned = ok
|
||||
|
||||
if !viper.IsSet("hosts") {
|
||||
viper.Set("hosts", map[string]Host{})
|
||||
}
|
||||
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
hosts[name] = host
|
||||
viper.Set("hosts", hosts)
|
||||
return viper.WriteConfig()
|
||||
}
|
||||
|
||||
// IsMachineProvisioned check if machine provisioned
|
||||
func (c *Config) IsMachineProvisioned(name string) bool {
|
||||
host, err := c.GetMachine(name)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return host.Provisioned
|
||||
}
|
||||
|
||||
98
config/config_test.go
Normal file
98
config/config_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfig(t *testing.T) {
|
||||
configPath := "/tmp/.fx"
|
||||
defer func() {
|
||||
if err := os.RemoveAll(configPath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
c := New(configPath)
|
||||
if err := c.Init(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts, err := c.ListMachines()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(hosts) != 1 {
|
||||
t.Fatalf("should have localhost as default machine")
|
||||
}
|
||||
|
||||
host := hosts["localhost"]
|
||||
if !reflect.DeepEqual(host, Host{Host: "localhost", Enabled: true}) {
|
||||
t.Fatalf("should get %v but got %v", Host{Host: "localhost"}, host)
|
||||
}
|
||||
|
||||
name := "remote-a"
|
||||
h := Host{
|
||||
Host: "192.168.1.1",
|
||||
User: "user-a",
|
||||
Password: "password-a",
|
||||
Enabled: false,
|
||||
}
|
||||
if err := c.AddMachine(name, h); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
hosts, err = c.ListMachines()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(hosts) != 2 {
|
||||
t.Fatalf("should have %d machines now, but got %d", 2, len(hosts))
|
||||
}
|
||||
|
||||
lst, err := c.ListActiveMachines()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(lst) != 1 {
|
||||
t.Fatalf("should only have %d machine enabled, but got %d", 1, len(lst))
|
||||
}
|
||||
|
||||
if err := c.EnableMachine(name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
lst, err = c.ListActiveMachines()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(lst) != 2 {
|
||||
t.Fatalf("should only have %d machine enabled, but got %d", 2, len(lst))
|
||||
}
|
||||
|
||||
h.Enabled = true
|
||||
if !reflect.DeepEqual(lst[name], h) {
|
||||
t.Fatalf("should get %v but got %v", h, lst[name])
|
||||
}
|
||||
|
||||
if lst[name].Provisioned != false {
|
||||
t.Fatalf("should get %v but got %v", false, lst[name].Provisioned)
|
||||
}
|
||||
|
||||
if err := c.UpdateProvisionedStatus(name, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
updatedHost, err := c.GetMachine(name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if updatedHost.Provisioned != true {
|
||||
t.Fatalf("should get %v but got %v", true, updatedHost.Provisioned)
|
||||
}
|
||||
}
|
||||
40
config/host.go
Normal file
40
config/host.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package config
|
||||
|
||||
// Host host entity
|
||||
type Host struct {
|
||||
Host string
|
||||
User string
|
||||
Password string
|
||||
Enabled bool
|
||||
Provisioned bool
|
||||
}
|
||||
|
||||
// NewHost new a host
|
||||
func NewHost(addr, user, password string) Host {
|
||||
return Host{
|
||||
Host: addr,
|
||||
User: user,
|
||||
Password: password,
|
||||
Enabled: false,
|
||||
Provisioned: false,
|
||||
}
|
||||
}
|
||||
|
||||
// Valid if host is valid
|
||||
func (h Host) Valid() bool {
|
||||
// TODO stronger check
|
||||
return h.Host != ""
|
||||
}
|
||||
|
||||
// IsLocal if host is localhost
|
||||
func (h Host) IsLocal() bool {
|
||||
if !h.Valid() {
|
||||
return false
|
||||
}
|
||||
return h.Host == "127.0.0.1" || h.Host == "localhost"
|
||||
}
|
||||
|
||||
// IsRemote is host is remote
|
||||
func (h Host) IsRemote() bool {
|
||||
return !h.IsLocal()
|
||||
}
|
||||
149
config/mocks/config.go
Normal file
149
config/mocks/config.go
Normal file
@@ -0,0 +1,149 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: ./config.go
|
||||
|
||||
// Package mock_config is a generated GoMock package.
|
||||
package mock_config
|
||||
|
||||
import (
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
config "github.com/metrue/fx/config"
|
||||
reflect "reflect"
|
||||
)
|
||||
|
||||
// MockConfiger is a mock of Configer interface
|
||||
type MockConfiger struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockConfigerMockRecorder
|
||||
}
|
||||
|
||||
// MockConfigerMockRecorder is the mock recorder for MockConfiger
|
||||
type MockConfigerMockRecorder struct {
|
||||
mock *MockConfiger
|
||||
}
|
||||
|
||||
// NewMockConfiger creates a new mock instance
|
||||
func NewMockConfiger(ctrl *gomock.Controller) *MockConfiger {
|
||||
mock := &MockConfiger{ctrl: ctrl}
|
||||
mock.recorder = &MockConfigerMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use
|
||||
func (m *MockConfiger) EXPECT() *MockConfigerMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// GetMachine mocks base method
|
||||
func (m *MockConfiger) GetMachine(name string) (config.Host, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetMachine", name)
|
||||
ret0, _ := ret[0].(config.Host)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetMachine indicates an expected call of GetMachine
|
||||
func (mr *MockConfigerMockRecorder) GetMachine(name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMachine", reflect.TypeOf((*MockConfiger)(nil).GetMachine), name)
|
||||
}
|
||||
|
||||
// AddMachine mocks base method
|
||||
func (m *MockConfiger) AddMachine(name string, host config.Host) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AddMachine", name, host)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddMachine indicates an expected call of AddMachine
|
||||
func (mr *MockConfigerMockRecorder) AddMachine(name, host interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddMachine", reflect.TypeOf((*MockConfiger)(nil).AddMachine), name, host)
|
||||
}
|
||||
|
||||
// RemoveHost mocks base method
|
||||
func (m *MockConfiger) RemoveHost(name string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RemoveHost", name)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// RemoveHost indicates an expected call of RemoveHost
|
||||
func (mr *MockConfigerMockRecorder) RemoveHost(name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RemoveHost", reflect.TypeOf((*MockConfiger)(nil).RemoveHost), name)
|
||||
}
|
||||
|
||||
// ListActiveMachines mocks base method
|
||||
func (m *MockConfiger) ListActiveMachines() (map[string]config.Host, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListActiveMachines")
|
||||
ret0, _ := ret[0].(map[string]config.Host)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListActiveMachines indicates an expected call of ListActiveMachines
|
||||
func (mr *MockConfigerMockRecorder) ListActiveMachines() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListActiveMachines", reflect.TypeOf((*MockConfiger)(nil).ListActiveMachines))
|
||||
}
|
||||
|
||||
// ListMachines mocks base method
|
||||
func (m *MockConfiger) ListMachines() (map[string]config.Host, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ListMachines")
|
||||
ret0, _ := ret[0].(map[string]config.Host)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ListMachines indicates an expected call of ListMachines
|
||||
func (mr *MockConfigerMockRecorder) ListMachines() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListMachines", reflect.TypeOf((*MockConfiger)(nil).ListMachines))
|
||||
}
|
||||
|
||||
// EnableMachine mocks base method
|
||||
func (m *MockConfiger) EnableMachine(name string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "EnableMachine", name)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// EnableMachine indicates an expected call of EnableMachine
|
||||
func (mr *MockConfigerMockRecorder) EnableMachine(name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "EnableMachine", reflect.TypeOf((*MockConfiger)(nil).EnableMachine), name)
|
||||
}
|
||||
|
||||
// DisableMachine mocks base method
|
||||
func (m *MockConfiger) DisableMachine(name string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DisableMachine", name)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DisableMachine indicates an expected call of DisableMachine
|
||||
func (mr *MockConfigerMockRecorder) DisableMachine(name interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DisableMachine", reflect.TypeOf((*MockConfiger)(nil).DisableMachine), name)
|
||||
}
|
||||
|
||||
// UpdateProvisionedStatus mocks base method
|
||||
func (m *MockConfiger) UpdateProvisionedStatus(name string, ok bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UpdateProvisionedStatus", name, ok)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateProvisionedStatus indicates an expected call of UpdateProvisionedStatus
|
||||
func (mr *MockConfigerMockRecorder) UpdateProvisionedStatus(name, ok interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateProvisionedStatus", reflect.TypeOf((*MockConfiger)(nil).UpdateProvisionedStatus), name, ok)
|
||||
}
|
||||
34
constants/constants.go
Normal file
34
constants/constants.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package constants
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// AgentPort fx server agent port
|
||||
const AgentPort = "8866"
|
||||
|
||||
// BaseImages base images to build fx functions
|
||||
var BaseImages = []string{
|
||||
"metrue/fx-java-base",
|
||||
"metrue/fx-julia-base",
|
||||
"metrue/fx-python-base",
|
||||
"metrue/fx-node-base",
|
||||
"metrue/fx-d-base",
|
||||
"metrue/fx-go-base",
|
||||
}
|
||||
|
||||
// ConfigPath path to config
|
||||
var ConfigPath = path.Join(os.Getenv("HOME"), ".fx")
|
||||
|
||||
// AgentContainerName fx agent name
|
||||
const AgentContainerName = "fx-agent"
|
||||
|
||||
// CheckedSymbol check symbol ✓
|
||||
const CheckedSymbol = "\u2713"
|
||||
|
||||
// UncheckedSymbol uncheck ✗
|
||||
const UncheckedSymbol = "\u2717"
|
||||
|
||||
// FxContainerExposePort each fx container expose a default port 3000
|
||||
const FxContainerExposePort = 3000
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM node:latest
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
@@ -1,12 +1,9 @@
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
const fx = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
app.use(fx);
|
||||
|
||||
app.listen(3000);
|
||||
3
container_runtimes/docker/fixture/fx.js
Normal file
3
container_runtimes/docker/fixture/fx.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello world'
|
||||
}
|
||||
195
container_runtimes/docker/http/api.go
Normal file
195
container_runtimes/docker/http/api.go
Normal file
@@ -0,0 +1,195 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// API interact with dockerd http api
|
||||
type API struct {
|
||||
endpoint string
|
||||
version string
|
||||
}
|
||||
|
||||
// Create a API
|
||||
func Create(host string, port string) (*API, error) {
|
||||
version, err := utils.DockerVersion(host, port)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", host, port, version)
|
||||
return &API{
|
||||
endpoint: endpoint,
|
||||
version: version,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// MustCreate a api object, panic if not
|
||||
func MustCreate(host string, port string) *API {
|
||||
version, err := utils.DockerVersion(host, port)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
endpoint := fmt.Sprintf("http://%s:%s/v%s", host, port, version)
|
||||
return &API{
|
||||
endpoint: endpoint,
|
||||
version: version,
|
||||
}
|
||||
}
|
||||
|
||||
func (api *API) get(path string, qs string, v interface{}) error {
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
if !strings.HasPrefix(url, "http") {
|
||||
url = "http://" + url
|
||||
}
|
||||
if qs != "" {
|
||||
url += "?" + qs
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
return fmt.Errorf("request %s failed: %d - %s", url, resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (api *API) post(path string, body []byte, expectStatus int, v interface{}) error {
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
req.Header.Set("Accept", "application/json")
|
||||
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if resp.StatusCode != expectStatus {
|
||||
return fmt.Errorf("request %s (%s) failed: %d - %s", url, string(body), resp.StatusCode, resp.Status)
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(b, &v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// List list service
|
||||
func (api *API) list(name string) ([]types.Service, error) {
|
||||
if name != "" {
|
||||
info, err := api.inspect(name)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
port, err := strconv.Atoi(info.HostConfig.PortBindings["3000/tcp"][0].HostPort)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
return []types.Service{
|
||||
types.Service{
|
||||
Name: name,
|
||||
Image: info.Image,
|
||||
State: info.State.Status,
|
||||
ID: info.ID,
|
||||
Host: info.HostConfig.PortBindings["3000/tcp"][0].HostIP,
|
||||
Port: port,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type filterItem struct {
|
||||
Status []string `json:"url,omitempty"`
|
||||
Label []string `json:"label,omitempty"`
|
||||
Name []string `json:"name,omitempty"`
|
||||
}
|
||||
|
||||
type Filters struct {
|
||||
Items string `url:"filters"`
|
||||
}
|
||||
|
||||
filter := filterItem{
|
||||
// Status: []string{"running"},
|
||||
Label: []string{"belong-to=fx"},
|
||||
}
|
||||
|
||||
q, err := json.Marshal(filter)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
filters := Filters{Items: string(q)}
|
||||
qs, err := query.Values(filters)
|
||||
if err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
var containers []dockerTypes.Container
|
||||
if err := api.get("/containers/json", qs.Encode(), &containers); err != nil {
|
||||
return []types.Service{}, err
|
||||
}
|
||||
|
||||
svs := make(map[string]types.Service)
|
||||
for _, container := range containers {
|
||||
// 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,
|
||||
}
|
||||
}
|
||||
}
|
||||
services := []types.Service{}
|
||||
for _, s := range svs {
|
||||
services = append(services, s)
|
||||
}
|
||||
|
||||
return services, nil
|
||||
}
|
||||
89
container_runtimes/docker/http/api_test.go
Normal file
89
container_runtimes/docker/http/api_test.go
Normal file
@@ -0,0 +1,89 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/config"
|
||||
"github.com/metrue/fx/constants"
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func TestDockerHTTP(t *testing.T) {
|
||||
host := config.Host{Host: "127.0.0.1"}
|
||||
api, err := Create(host.Host, constants.AgentPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
serviceName := "a-test-service"
|
||||
project := types.Project{
|
||||
Name: serviceName,
|
||||
Language: "node",
|
||||
Files: []types.ProjectSourceFile{
|
||||
types.ProjectSourceFile{
|
||||
Path: "Dockerfile",
|
||||
Body: `
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "app.js",
|
||||
Body: `
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "fx.js",
|
||||
Body: `
|
||||
module.exports = (input) => {
|
||||
return input.a + input.b
|
||||
}
|
||||
`,
|
||||
IsHandler: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if service.Name != serviceName {
|
||||
t.Fatalf("should get %s but got %s", serviceName, service.Name)
|
||||
}
|
||||
|
||||
if err := api.Run(9999, &service); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
services, err := api.list(serviceName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(services) != 1 {
|
||||
t.Fatal("service number should be 1")
|
||||
}
|
||||
|
||||
if err := api.Stop(serviceName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM ubuntu:16.04
|
||||
|
||||
RUN apt-get update && apt-get install -y build-essential curl libcurl3 \
|
||||
&& curl -OL http://downloads.dlang.org/releases/2.x/2.077.1/dmd_2.077.1-0_amd64.deb \
|
||||
&& apt install ./dmd_2.077.1-0_amd64.deb
|
||||
@@ -0,0 +1,12 @@
|
||||
FROM golang:1.12.0-alpine3.9 AS builder
|
||||
|
||||
LABEL maintainer="h.minghe@gmail.com"
|
||||
|
||||
ENV GO111MODULE on
|
||||
ENV GOPROXY https://goproxy.io
|
||||
ENV PATH $GOPATH/bin:$PATH
|
||||
|
||||
RUN go get "github.com/gin-gonic/gin"
|
||||
|
||||
RUN apk upgrade --no-cache \
|
||||
&& apk add ca-certificates
|
||||
@@ -0,0 +1,12 @@
|
||||
FROM java:8
|
||||
|
||||
# Install maven
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y maven
|
||||
|
||||
WORKDIR /code
|
||||
|
||||
# Prepare by downloading dependencies
|
||||
ADD pom.xml /code/pom.xml
|
||||
RUN ["mvn", "dependency:resolve"]
|
||||
RUN ["mvn", "verify"]
|
||||
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t metrue/fx-java-base:latest .
|
||||
docker push metrue/fx-java-base
|
||||
@@ -0,0 +1,51 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>fx-app-java</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
<version>0.1.0</version>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-shade-plugin</artifactId>
|
||||
<version>2.1</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>shade</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<transformers>
|
||||
<transformer
|
||||
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
|
||||
<mainClass>fx.app</mainClass>
|
||||
</transformer>
|
||||
</transformers>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<properties>
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
</properties>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.javalin</groupId>
|
||||
<artifactId>javalin</artifactId>
|
||||
<version>1.1.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.json</groupId>
|
||||
<artifactId>json</artifactId>
|
||||
<version>20171018</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -0,0 +1,3 @@
|
||||
FROM julia:latest
|
||||
|
||||
RUN apt-get update && apt-get install -y gcc apt-utils unzip make libhttp-parser-dev
|
||||
@@ -0,0 +1,3 @@
|
||||
build:
|
||||
docker build -t metrue/fx-julia-base:latest .
|
||||
docker push metrue/fx-julia-base
|
||||
@@ -0,0 +1,4 @@
|
||||
FROM node:latest
|
||||
|
||||
COPY . .
|
||||
RUN npm install
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "aok",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"redis": "^2.8.0",
|
||||
"node-fetch": "^2.6.0",
|
||||
"is-generator-function": "^1.0.6",
|
||||
"koa": "^2.3.0",
|
||||
"koa-bodyparser": "^4.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"get-port-cli": "^1.1.0"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
FROM python:3
|
||||
|
||||
RUN pip install flask
|
||||
ENV FLASK_APP=app.py
|
||||
|
||||
970
container_runtimes/docker/http/asserts/dockerfiles/base/rust/Cargo.lock
generated
Normal file
970
container_runtimes/docker/http/asserts/dockerfiles/base/rust/Cargo.lock
generated
Normal file
@@ -0,0 +1,970 @@
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bytes"
|
||||
version = "0.4.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-utils"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise_codegen"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "devise_core"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsevent-sys"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "futures"
|
||||
version = "0.1.25"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.10.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "idna"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "inotify-sys"
|
||||
version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iovec"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "isatty"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "kernel32-sys"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "language-tags"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matches"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mime"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "0.6.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio-extras"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "miow"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "net2"
|
||||
version = "0.2.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "4.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "owning_ref"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot_core"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pear_codegen"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_codegen 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_codegen"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_contrib"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rocket_http"
|
||||
version = "0.4.0-rc.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rocket_contrib 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc_version"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "0.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "safemem"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver-parser"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.80"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "slab"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "0.6.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "state"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.15.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-executor"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-io"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-reactor"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.4.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "traitobject"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "typeable"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-normalization"
|
||||
version = "0.1.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "unreachable"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "untrusted"
|
||||
version = "0.6.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "1.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "void"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "walkdir"
|
||||
version = "2.2.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-build"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum base64 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "621fc7ecb8008f86d7fb9b95356cd692ce9514b80a86d85b397f32a22da7b9e2"
|
||||
"checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum byteorder 1.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94f88df23a25417badc922ab0f5716cc1330e87f71ddd9203b3a3ccd9cedf75d"
|
||||
"checksum bytes 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "40ade3d27603c2cb345eb0912aec461a6dec7e06a4ae48589904e808335c7afa"
|
||||
"checksum cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f159dfd43363c4d08055a07703eb7a3406b0dac4d0584d96965a3262db3c9d16"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum cookie 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1465f8134efa296b4c19db34d909637cb2bf0f7aaf21299e23e18fa29ac557cf"
|
||||
"checksum crossbeam-utils 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c55913cc2799171a550e307918c0a360e8c16004820291bf3b638969b4a01816"
|
||||
"checksum devise 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "74e04ba2d03c5fa0d954c061fc8c9c288badadffc272ebb87679a89846de3ed3"
|
||||
"checksum devise_codegen 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "066ceb7928ca93a9bedc6d0e612a8a0424048b0ab1f75971b203d01420c055d7"
|
||||
"checksum devise_core 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cf41c59b22b5e3ec0ea55c7847e5f358d340f3a8d6d53a5cf4f1564967f96487"
|
||||
"checksum filetime 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a2df5c1a8c4be27e7707789dc42ae65976e60b394afd293d1419ab915833e646"
|
||||
"checksum fsevent 0.2.17 (registry+https://github.com/rust-lang/crates.io-index)" = "c4bbbf71584aeed076100b5665ac14e3d85eeb31fdbb45fbd41ef9a682b5ec05"
|
||||
"checksum fsevent-sys 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1a772d36c338d07a032d5375a36f15f9a7043bf0cb8ce7cee658e037c6032874"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)" = "49e7653e374fe0d0c12de4250f0bdb60680b8c80eed558c5c7538eec9c89e21b"
|
||||
"checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83"
|
||||
"checksum hyper 0.10.15 (registry+https://github.com/rust-lang/crates.io-index)" = "df0caae6b71d266b91b4a83111a61d2b94ed2e2bea024c532b933dcff867e58c"
|
||||
"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e"
|
||||
"checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d"
|
||||
"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
|
||||
"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
|
||||
"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08"
|
||||
"checksum isatty 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e31a8281fc93ec9693494da65fbf28c0c2aa60a2eaec25dc58e2f31952e95edc"
|
||||
"checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b"
|
||||
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
|
||||
"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a"
|
||||
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
|
||||
"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum lock_api 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "62ebf1391f6acad60e5c8b43706dde4582df75c06698ab44511d15016bc2442c"
|
||||
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
|
||||
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
|
||||
"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
|
||||
"checksum memchr 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0a3eb002f0535929f1199681417029ebea04aadc0c7a4224b46be99c7f5d6a16"
|
||||
"checksum mime 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ba626b8a6de5da682e1caa06bdb42a335aee5a84db8e5046a3e8ab17ba0a3ae0"
|
||||
"checksum mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "71646331f2619b1026cc302f87a2b8b648d5c6dd6937846a16cc8ce0f347f432"
|
||||
"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
|
||||
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
|
||||
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
|
||||
"checksum notify 4.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "873ecfd8c174964ae30f401329d140142312c8e5590719cf1199d5f1717d8078"
|
||||
"checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30"
|
||||
"checksum owning_ref 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a4b8ea2179e6a2e27411d3bca09ca6dd630821cf6894c6c7c8467a8ee7ef13"
|
||||
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
|
||||
"checksum parking_lot_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad7f7e6ebdc79edff6fdcb87a55b620174f7a989e3eb31b65231f4af57f00b8c"
|
||||
"checksum pear 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c26d2b92e47063ffce70d3e3b1bd097af121a9e0db07ca38a6cc1cf0cc85ff25"
|
||||
"checksum pear_codegen 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "336db4a192cc7f54efeb0c4e11a9245394824cc3bcbd37ba3ff51240c35d7a6e"
|
||||
"checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831"
|
||||
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
|
||||
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
|
||||
"checksum redox_syscall 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "679da7508e9a6390aeaf7fbd02a800fdc64b73fe2204dd2c8ae66d22d9d5ad5d"
|
||||
"checksum ring 0.13.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2c4db68a2e35f3497146b7e4563df7d4773a2433230c5e4b448328e31740458a"
|
||||
"checksum rocket 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eaa997ea8de9b14112aa38b2b6a0ecf3e651ff2c08d2fdf384fa765b5f9c2c98"
|
||||
"checksum rocket_codegen 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fc68f90452ac88c6c1e02a922a0a23ef0ade08f9af899056d0c919b25fa7768c"
|
||||
"checksum rocket_contrib 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2cc6a37cb7a6256efe6648f2d0ab9978c49ab883909ea4fabefb81d7c685d841"
|
||||
"checksum rocket_http 0.4.0-rc.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c7d555ce896830602aedf4bce2eec8d64713d45a2492c5a3625c3faa5f719b0f"
|
||||
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
|
||||
"checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7"
|
||||
"checksum safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8dca453248a96cb0749e36ccdfe2b0b4e54a61bfef89fb97ec621eb8e0a93dd9"
|
||||
"checksum same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8f20c4be53a8a1ff4c1f1b2bd14570d2f634628709752f0702ecdd2b3f9a5267"
|
||||
"checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27"
|
||||
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
|
||||
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
|
||||
"checksum serde 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "15c141fc7027dd265a47c090bf864cf62b42c4d228bbcf4e51a0c9e2b0d3f7ef"
|
||||
"checksum serde_derive 1.0.80 (registry+https://github.com/rust-lang/crates.io-index)" = "225de307c6302bec3898c51ca302fc94a7a1697ef0845fcee6448f33c032249c"
|
||||
"checksum serde_json 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "c37ccd6be3ed1fdf419ee848f7c758eb31b054d7cd3ae3600e3bae0adf569811"
|
||||
"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d"
|
||||
"checksum smallvec 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b73ea3738b47563803ef814925e69be00799a8c07420be8b996f8e98fb2336db"
|
||||
"checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8"
|
||||
"checksum state 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7345c971d1ef21ffdbd103a75990a15eb03604fc8b8852ca8cb418ee1a099028"
|
||||
"checksum syn 0.15.22 (registry+https://github.com/rust-lang/crates.io-index)" = "ae8b29eb5210bc5cf63ed6149cbf9adfc82ac0be023d8735c176ee74a2db4da7"
|
||||
"checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b"
|
||||
"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde"
|
||||
"checksum tokio-io 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "7392fe0a70d5ce0c882c4778116c519bd5dbaa8a7c3ae3d04578b3afafdcda21"
|
||||
"checksum tokio-reactor 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "502b625acb4ee13cbb3b90b8ca80e0addd263ddacf6931666ef751e610b07fb5"
|
||||
"checksum toml 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "19782e145d5abefb03758958f06ea35f7b1d8421b534140e0238fd3d0bfd66e3"
|
||||
"checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079"
|
||||
"checksum typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1410f6f91f21d1612654e7cc69193b0334f909dcf2c790c4826254fbb86f8887"
|
||||
"checksum unicase 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7f4765f83163b74f957c797ad9253caf97f103fb064d3999aea9568d09fc8a33"
|
||||
"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
|
||||
"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||
"checksum untrusted 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "55cd1f4b4e96b46aeb8d4855db4a7a9bd96eeeb5c6a1ab54593328761642ce2f"
|
||||
"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a"
|
||||
"checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd"
|
||||
"checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||
"checksum walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9d9d7ed3431229a144296213105a390676cc49c9b6a72bd19f3176c98e129fa1"
|
||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
|
||||
"checksum yansi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d60c3b48c9cdec42fb06b3b84b5b087405e1fa1c644a1af3930e4dfafe93de48"
|
||||
"checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "rust"
|
||||
version = "0.1.0"
|
||||
authors = ["FrontMage <xbgxwh@outlook.com>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rocket = "0.4.0-rc.2"
|
||||
rocket_contrib = "0.4.0-rc.2"
|
||||
serde_json = "1.0"
|
||||
serde_derive = "1.0.70"
|
||||
serde = "1.0.70"
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
FROM liuchong/rustup
|
||||
|
||||
WORKDIR /usr/src/myapp
|
||||
COPY . .
|
||||
|
||||
RUN cp ./config ~/.cargo/
|
||||
|
||||
RUN rustup default nightly
|
||||
RUN cargo update
|
||||
RUN cargo build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["cargo", "run"]
|
||||
@@ -0,0 +1,5 @@
|
||||
[development]
|
||||
address = "0.0.0.0"
|
||||
port = 3000
|
||||
log = "normal"
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
[source.crates-io]
|
||||
registry = "https://github.com/rust-lang/crates.io-index"
|
||||
replace-with = 'ustc'
|
||||
[source.ustc]
|
||||
registry = "git://mirrors.ustc.edu.cn/crates.io-index"
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
pub mod fns {
|
||||
#[derive(Serialize)]
|
||||
pub struct Response {
|
||||
pub result: i32,
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct Request {
|
||||
pub a: i32,
|
||||
pub b: i32,
|
||||
}
|
||||
|
||||
pub fn func(req: Request) -> Response {
|
||||
Response {
|
||||
result: req.a + req.b,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#![feature(proc_macro_hygiene, decl_macro, plugin)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate rocket;
|
||||
extern crate rocket_contrib;
|
||||
extern crate serde;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
extern crate serde_json;
|
||||
|
||||
mod fns;
|
||||
|
||||
use rocket_contrib::json::Json;
|
||||
|
||||
#[post("/", format = "application/json", data = "<req>")]
|
||||
fn index(req: Json<fns::fns::Request>) -> Json<fns::fns::Response> {
|
||||
Json(fns::fns::func(req.0))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
rocket::ignite().mount("/", routes![index]).launch();
|
||||
}
|
||||
60
container_runtimes/docker/http/call.go
Normal file
60
container_runtimes/docker/http/call.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Call function directly with given params
|
||||
func (api *API) Call(file string, param string, project types.Project) error {
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
log.Fatalf("Build Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Build Service: \u2713")
|
||||
|
||||
if err := api.Run(9999, &service); err != nil {
|
||||
log.Fatalf("Run Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Run Service: \u2713")
|
||||
|
||||
params := utils.PairsToParams(strings.Fields(param))
|
||||
body, err := json.Marshal(params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait 2 seconds for service startup
|
||||
time.Sleep(time.Second * 2)
|
||||
|
||||
url := fmt.Sprintf("http://%s:%d", service.Host, service.Port)
|
||||
r, err := http.NewRequest("POST", url, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.Header.Set("Content-Type", "application/json")
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(r)
|
||||
if err != nil {
|
||||
log.Fatalf("Call Service: %v", err)
|
||||
return err
|
||||
}
|
||||
buf, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalf("Call Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Info("Call Service: \u2713")
|
||||
return utils.OutputJSON(string(buf))
|
||||
}
|
||||
26
container_runtimes/docker/http/container_inspect.go
Normal file
26
container_runtimes/docker/http/container_inspect.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
type containerInfo struct {
|
||||
ID string `json:"Id"`
|
||||
State dockerTypes.ContainerState `json:"State"`
|
||||
Image string `json:"Image"`
|
||||
HostConfig container.HostConfig `json:"HostConfig"`
|
||||
}
|
||||
|
||||
func (api *API) inspect(identify string) (containerInfo, error) {
|
||||
var info containerInfo
|
||||
|
||||
path := fmt.Sprintf("/containers/%s/json", identify)
|
||||
if err := api.get(path, "", &info); err != nil {
|
||||
return info, err
|
||||
}
|
||||
|
||||
return info, nil
|
||||
}
|
||||
1
container_runtimes/docker/http/container_inspect_test.go
Normal file
1
container_runtimes/docker/http/container_inspect_test.go
Normal file
@@ -0,0 +1 @@
|
||||
package api
|
||||
77
container_runtimes/docker/http/container_wait.go
Normal file
77
container_runtimes/docker/http/container_wait.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/api/types/container"
|
||||
)
|
||||
|
||||
// ContainerWait waits until the specified container is in a certain state
|
||||
// indicated by the given condition, either "not-running" (default),
|
||||
// "next-exit", or "removed".
|
||||
//
|
||||
// If this client's API version is before 1.30, condition is ignored and
|
||||
// ContainerWait will return immediately with the two channels, as the server
|
||||
// will wait as if the condition were "not-running".
|
||||
//
|
||||
// If this client's API version is at least 1.30, ContainerWait blocks until
|
||||
// the request has been acknowledged by the server (with a response header),
|
||||
// then returns two channels on which the caller can wait for the exit status
|
||||
// of the container or an error if there was a problem either beginning the
|
||||
// wait request or in getting the response. This allows the caller to
|
||||
// synchronize ContainerWait with other calls, such as specifying a
|
||||
// "next-exit" condition before issuing a ContainerStart request.
|
||||
func (api *API) ContainerWait(
|
||||
ctx context.Context,
|
||||
containerID string,
|
||||
condition container.WaitCondition,
|
||||
timeout time.Duration,
|
||||
) (<-chan container.ContainerWaitOKBody, <-chan error) {
|
||||
resultC := make(chan container.ContainerWaitOKBody)
|
||||
errC := make(chan error, 1)
|
||||
|
||||
query := url.Values{}
|
||||
query.Set("condition", string(condition))
|
||||
|
||||
path := fmt.Sprintf("/containers/%s/wait?%s", containerID, query.Encode())
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
request, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
return resultC, errC
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: timeout}
|
||||
if _, err = client.Do(request); err != nil {
|
||||
errC <- err
|
||||
return resultC, errC
|
||||
}
|
||||
|
||||
go func() {
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
|
||||
var res container.ContainerWaitOKBody
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
errC <- err
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(body, &res); err != nil {
|
||||
errC <- err
|
||||
}
|
||||
|
||||
resultC <- res
|
||||
}()
|
||||
return resultC, errC
|
||||
}
|
||||
28
container_runtimes/docker/http/down.go
Normal file
28
container_runtimes/docker/http/down.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/apex/log"
|
||||
)
|
||||
|
||||
// Down destroy services
|
||||
func (api *API) Down(names []string) error {
|
||||
var wg sync.WaitGroup
|
||||
|
||||
for _, name := range names {
|
||||
wg.Add(1)
|
||||
go func(s string) {
|
||||
if err := api.Stop(s); err != nil {
|
||||
log.Fatalf("Down Service %s: %v", s, err)
|
||||
} else {
|
||||
log.Infof("Down Service %s: \u2713", s)
|
||||
}
|
||||
defer wg.Done()
|
||||
}(name)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
}
|
||||
7
container_runtimes/docker/http/down_test.go
Normal file
7
container_runtimes/docker/http/down_test.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package api
|
||||
|
||||
import "testing"
|
||||
|
||||
func TestDown(t *testing.T) {
|
||||
|
||||
}
|
||||
22
container_runtimes/docker/http/list.go
Normal file
22
container_runtimes/docker/http/list.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/apex/log"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// List services
|
||||
func (api *API) List(name string) error {
|
||||
services, err := api.list(name)
|
||||
if err != nil {
|
||||
log.Fatalf("List Services: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
for _, service := range services {
|
||||
if err := utils.OutputJSON(service); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
58
container_runtimes/docker/http/network.go
Normal file
58
container_runtimes/docker/http/network.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
filters "github.com/docker/docker/api/types/filters"
|
||||
"github.com/google/go-querystring/query"
|
||||
)
|
||||
|
||||
// GetNetwork get a network
|
||||
func (api *API) GetNetwork(name string) ([]dockerTypes.NetworkResource, error) {
|
||||
path := "/networks"
|
||||
var networks []dockerTypes.NetworkResource
|
||||
arg := filters.NewArgs(filters.KeyValuePair{
|
||||
Key: "name",
|
||||
Value: name,
|
||||
})
|
||||
// opt := dockerTypes.NetworkListOptions{Filters: arg}
|
||||
|
||||
q, err := json.Marshal(arg)
|
||||
if err != nil {
|
||||
return networks, err
|
||||
}
|
||||
type Filters struct {
|
||||
Items string `url:"filters"`
|
||||
}
|
||||
filters := Filters{Items: string(q)}
|
||||
qs, err := query.Values(filters)
|
||||
if err != nil {
|
||||
return networks, err
|
||||
}
|
||||
|
||||
if err := api.get(path, qs.Encode(), &networks); err != nil {
|
||||
return networks, err
|
||||
}
|
||||
|
||||
return networks, nil
|
||||
}
|
||||
|
||||
// CreateNetwork create a network
|
||||
func (api *API) CreateNetwork(name string) error {
|
||||
path := "/networks/create"
|
||||
ncReq := dockerTypes.NetworkCreateRequest{
|
||||
Name: name,
|
||||
}
|
||||
|
||||
body, err := json.Marshal(ncReq)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var resp dockerTypes.NetworkCreateResponse
|
||||
if err := api.post(path, body, 201, resp); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
35
container_runtimes/docker/http/network_test.go
Normal file
35
container_runtimes/docker/http/network_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/metrue/fx/config"
|
||||
"github.com/metrue/fx/constants"
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestNetwork(t *testing.T) {
|
||||
defer gock.Off()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
host := config.Host{Host: "127.0.0.1"}
|
||||
api, err := Create(host.Host, constants.AgentPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
const network = "fx-net"
|
||||
if err := api.CreateNetwork(network); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
nws, err := api.GetNetwork(network)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if nws[0].Name != network {
|
||||
t.Fatalf("should get %s but got %s", network, nws[0].Name)
|
||||
}
|
||||
}
|
||||
119
container_runtimes/docker/http/service_build.go
Normal file
119
container_runtimes/docker/http/service_build.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/google/uuid"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
func makeTar(project types.Project, tarFilePath string) error {
|
||||
dir, err := ioutil.TempDir("/tmp", "fx-build-dir")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
for _, file := range project.Files {
|
||||
tmpfn := filepath.Join(dir, file.Path)
|
||||
if err := utils.EnsureFile(tmpfn); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := ioutil.WriteFile(tmpfn, []byte(file.Body), 0666); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return utils.TarDir(dir, tarFilePath)
|
||||
}
|
||||
|
||||
// Build build a project
|
||||
func (api *API) Build(project types.Project) (types.Service, error) {
|
||||
tarDir, err := ioutil.TempDir("/tmp", "fx-tar")
|
||||
if err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
defer os.RemoveAll(tarDir)
|
||||
|
||||
imageID := uuid.New().String()
|
||||
tarFilePath := filepath.Join(tarDir, fmt.Sprintf("%s.tar", imageID))
|
||||
if err := makeTar(project, tarFilePath); err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
labels := map[string]string{
|
||||
"belong-to": "fx",
|
||||
}
|
||||
if err := api.BuildImage(tarFilePath, imageID, labels); err != nil {
|
||||
return types.Service{}, err
|
||||
}
|
||||
|
||||
return types.Service{
|
||||
Name: project.Name,
|
||||
Image: imageID,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// BuildImage build docker image
|
||||
func (api *API) BuildImage(tarFile string, tag string, labels map[string]string) error {
|
||||
dockerBuildContext, err := os.Open(tarFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dockerBuildContext.Close()
|
||||
|
||||
type buildQuery struct {
|
||||
Labels string `url:"labels,omitempty"`
|
||||
Tags string `url:"t,omitempty"`
|
||||
Dockerfile string `url:"dockerfile,omitempty"`
|
||||
}
|
||||
|
||||
// Apply default labels
|
||||
labelsJSON, _ := json.Marshal(labels)
|
||||
q := buildQuery{
|
||||
Tags: tag,
|
||||
Labels: string(labelsJSON),
|
||||
Dockerfile: "Dockerfile",
|
||||
}
|
||||
qs, err := query.Values(q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
path := "/build"
|
||||
url := fmt.Sprintf("%s%s?%s", api.endpoint, path, qs.Encode())
|
||||
req, err := http.NewRequest("POST", url, dockerBuildContext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Header.Set("Content-Type", "application/x-tar")
|
||||
client := &http.Client{Timeout: 600 * time.Second}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
scanner := bufio.NewScanner(resp.Body)
|
||||
|
||||
for scanner.Scan() {
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
log.Infof(scanner.Text())
|
||||
}
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
166
container_runtimes/docker/http/service_build_test.go
Normal file
166
container_runtimes/docker/http/service_build_test.go
Normal file
@@ -0,0 +1,166 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/config"
|
||||
"github.com/metrue/fx/constants"
|
||||
"github.com/metrue/fx/types"
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestMakeTar(t *testing.T) {
|
||||
serviceName := "mock-service-abc"
|
||||
project := types.Project{
|
||||
Name: serviceName,
|
||||
Language: "node",
|
||||
Files: []types.ProjectSourceFile{
|
||||
types.ProjectSourceFile{
|
||||
Path: "Dockerfile",
|
||||
Body: `
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "app.js",
|
||||
Body: `
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "fx.js",
|
||||
Body: `
|
||||
module.exports = (input) => {
|
||||
return input.a + input.b
|
||||
}
|
||||
`,
|
||||
IsHandler: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
tarDir, err := ioutil.TempDir("/tmp", "fx-tar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tarDir)
|
||||
|
||||
tarFilePath := filepath.Join(tarDir, fmt.Sprintf("%s.tar", serviceName))
|
||||
if err := makeTar(project, tarFilePath); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
file, err := os.Open(tarFilePath)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
stat, err := file.Stat()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if stat.Name() != serviceName+".tar" {
|
||||
t.Fatalf("should get %s but got %s", serviceName+".tar", stat.Name())
|
||||
}
|
||||
if stat.Size() <= 0 {
|
||||
t.Fatalf("tarfile invalid: size %d", stat.Size())
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuild(t *testing.T) {
|
||||
defer gock.Off()
|
||||
|
||||
host := config.Host{Host: "127.0.0.1"}
|
||||
api, err := Create(host.Host, constants.AgentPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
url := "http://" + host.Host + ":" + constants.AgentPort
|
||||
gock.New(url).
|
||||
Post("/v" + api.version + "/build").
|
||||
AddMatcher(func(req *http.Request, ereq *gock.Request) (bool, error) {
|
||||
if strings.Contains(req.URL.String(), "/v"+api.version+"/build") {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}).
|
||||
Reply(200).
|
||||
JSON(map[string]string{
|
||||
"stream": "Step 1/5...",
|
||||
})
|
||||
|
||||
serviceName := "mock-service-abc"
|
||||
project := types.Project{
|
||||
Name: serviceName,
|
||||
Language: "node",
|
||||
Files: []types.ProjectSourceFile{
|
||||
types.ProjectSourceFile{
|
||||
Path: "Dockerfile",
|
||||
Body: `
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "app.js",
|
||||
Body: `
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const func = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(ctx => {
|
||||
const msg = func(ctx.request.body);
|
||||
ctx.body = msg;
|
||||
});
|
||||
|
||||
app.listen(3000);`,
|
||||
IsHandler: false,
|
||||
},
|
||||
types.ProjectSourceFile{
|
||||
Path: "fx.js",
|
||||
Body: `
|
||||
module.exports = (input) => {
|
||||
return input.a + input.b
|
||||
}
|
||||
`,
|
||||
IsHandler: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
service, err := api.Build(project)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if service.Name != serviceName {
|
||||
t.Fatalf("should get %s but got %s", serviceName, service.Name)
|
||||
}
|
||||
if service.Image == "" {
|
||||
t.Fatal("service image should not be empty")
|
||||
}
|
||||
}
|
||||
127
container_runtimes/docker/http/service_run.go
Normal file
127
container_runtimes/docker/http/service_run.go
Normal file
@@ -0,0 +1,127 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// ContainerCreateRequestPayload request paylaod
|
||||
type ContainerCreateRequestPayload struct {
|
||||
*container.Config
|
||||
HostConfig *container.HostConfig
|
||||
NetworkingConfig *network.NetworkingConfig
|
||||
}
|
||||
|
||||
const fxNetworkName = "fx-net"
|
||||
|
||||
// Run a service
|
||||
func (api *API) Run(port int, service *types.Service) error {
|
||||
networks, err := api.GetNetwork(fxNetworkName)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "get network failed: %s", err)
|
||||
}
|
||||
|
||||
if len(networks) == 0 {
|
||||
if err := api.CreateNetwork(fxNetworkName); err != nil {
|
||||
return errors.Wrapf(err, "error create network: %s", err)
|
||||
}
|
||||
}
|
||||
networks, _ = api.GetNetwork(fxNetworkName)
|
||||
config := &container.Config{
|
||||
Image: service.Image,
|
||||
ExposedPorts: nat.PortSet{
|
||||
"3000/tcp": struct{}{},
|
||||
},
|
||||
}
|
||||
|
||||
endpoint := &network.EndpointSettings{
|
||||
NetworkID: networks[0].ID,
|
||||
}
|
||||
networkConfig := &network.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||
"fx-net": endpoint,
|
||||
},
|
||||
}
|
||||
|
||||
hostConfig := &container.HostConfig{
|
||||
AutoRemove: true,
|
||||
PortBindings: nat.PortMap{
|
||||
"3000/tcp": []nat.PortBinding{
|
||||
{
|
||||
HostIP: types.DefaultHost,
|
||||
HostPort: fmt.Sprintf("%d", port),
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
req := ContainerCreateRequestPayload{
|
||||
Config: config,
|
||||
HostConfig: hostConfig,
|
||||
NetworkingConfig: networkConfig,
|
||||
}
|
||||
|
||||
body, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error mashal container create req")
|
||||
}
|
||||
|
||||
// create container
|
||||
path := fmt.Sprintf("/containers/create?name=%s", service.Name)
|
||||
var createRes container.ContainerCreateCreatedBody
|
||||
if err := api.post(path, body, 201, &createRes); err != nil {
|
||||
return errors.Wrap(err, "create container request failed")
|
||||
}
|
||||
|
||||
if createRes.ID == "" {
|
||||
return fmt.Errorf("container id is missing")
|
||||
}
|
||||
|
||||
log.Infof("container %s created", service.Name)
|
||||
|
||||
// start container
|
||||
path = fmt.Sprintf("/containers/%s/start", createRes.ID)
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
request, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error new container create request")
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
resp, err := client.Do(request)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error do start container request")
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
b, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(b) != 0 {
|
||||
msg := fmt.Sprintf("start container met issue: %s", string(b))
|
||||
return errors.New(msg)
|
||||
}
|
||||
log.Infof("container %s started", service.Name)
|
||||
|
||||
info, err := api.inspect(createRes.ID)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("inspect container %s error", service.Name)
|
||||
return errors.Wrap(err, msg)
|
||||
}
|
||||
service.ID = info.ID
|
||||
service.Host = info.HostConfig.PortBindings["3000/tcp"][0].HostIP
|
||||
service.Port = port
|
||||
service.State = info.State.Status
|
||||
|
||||
return nil
|
||||
}
|
||||
55
container_runtimes/docker/http/service_run_test.go
Normal file
55
container_runtimes/docker/http/service_run_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/metrue/fx/config"
|
||||
"github.com/metrue/fx/constants"
|
||||
"github.com/metrue/fx/types"
|
||||
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestServiceRun(t *testing.T) {
|
||||
defer gock.Off()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
host := config.Host{Host: "127.0.0.1"}
|
||||
api, err := Create(host.Host, constants.AgentPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
service := types.Service{
|
||||
Name: "a-mock-service",
|
||||
Image: "a-mock-image-id",
|
||||
}
|
||||
|
||||
mockContainerID := "mock-container-id"
|
||||
url := "http://" + host.Host + ":" + constants.AgentPort
|
||||
gock.New(url).
|
||||
Post("/v0.2.1/containers").
|
||||
AddMatcher(func(req *http.Request, ereq *gock.Request) (m bool, e error) {
|
||||
// TODO multiple matching not supported by gock
|
||||
if req.URL.String() == url+"/v0.2.1/containers/"+mockContainerID+"/start" {
|
||||
return true, nil
|
||||
} else if req.URL.String() == url+"/v0.2.1/containers/create?name="+service.Name {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}).
|
||||
Reply(201).
|
||||
JSON(map[string]interface{}{
|
||||
"Id": mockContainerID,
|
||||
"Warnings": []string{},
|
||||
})
|
||||
|
||||
// FIXME
|
||||
if err := api.Run(9999, &service); err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
24
container_runtimes/docker/http/stop.go
Normal file
24
container_runtimes/docker/http/stop.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Stop a container by name
|
||||
func (api *API) Stop(name string) error {
|
||||
path := fmt.Sprintf("/containers/%s/stop", name)
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
request, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := &http.Client{Timeout: 20 * time.Second}
|
||||
_, err = client.Do(request)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
39
container_runtimes/docker/http/stop_test.go
Normal file
39
container_runtimes/docker/http/stop_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/metrue/fx/config"
|
||||
"github.com/metrue/fx/constants"
|
||||
gock "gopkg.in/h2non/gock.v1"
|
||||
)
|
||||
|
||||
func TestStop(t *testing.T) {
|
||||
defer gock.Off()
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
host := config.Host{Host: "127.0.0.1"}
|
||||
api, err := Create(host.Host, constants.AgentPort)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
mockServiceName := "mock-service-name"
|
||||
url := "http://" + host.Host + ":" + constants.AgentPort
|
||||
gock.New(url).
|
||||
Post("/v" + api.version + "/containers/" + mockServiceName + "/stop").
|
||||
AddMatcher(func(req *http.Request, ereq *gock.Request) (m bool, e error) {
|
||||
if strings.Contains(req.URL.String(), "/v"+api.version+"/containers/"+mockServiceName+"/stop") {
|
||||
return true, nil
|
||||
}
|
||||
return false, nil
|
||||
}).
|
||||
Reply(204)
|
||||
if err := api.Stop(mockServiceName); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
81
container_runtimes/docker/http/up.go
Normal file
81
container_runtimes/docker/http/up.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/metrue/fx/constants"
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
// UpOptions options for up
|
||||
type UpOptions struct {
|
||||
Body []byte
|
||||
Lang string
|
||||
Name string
|
||||
Port int
|
||||
HealtCheck bool
|
||||
Project types.Project
|
||||
}
|
||||
|
||||
// Up up a source code of function to be a service
|
||||
func (api *API) Up(opt UpOptions) error {
|
||||
service, err := api.Build(opt.Project)
|
||||
if err != nil {
|
||||
log.Fatalf("Build Service %s: %v", opt.Name, err)
|
||||
return err
|
||||
}
|
||||
log.Infof("Build Service %s: %s", opt.Name, constants.CheckedSymbol)
|
||||
|
||||
if err := api.Run(opt.Port, &service); err != nil {
|
||||
log.Fatalf("Run Service: %v", err)
|
||||
return err
|
||||
}
|
||||
log.Infof("Run Service: %s", constants.CheckedSymbol)
|
||||
log.Infof("Service (%s) is running on: %s:%d", service.Name, service.Host, service.Port)
|
||||
|
||||
if opt.HealtCheck {
|
||||
go func() {
|
||||
resultC, errC := api.ContainerWait(
|
||||
context.Background(),
|
||||
service.ID,
|
||||
container.WaitConditionNextExit,
|
||||
20*time.Second,
|
||||
)
|
||||
for {
|
||||
select {
|
||||
case res := <-resultC:
|
||||
var msg string
|
||||
if res.Error != nil {
|
||||
msg = res.Error.Message
|
||||
}
|
||||
log.Warnf("container exited: Code(%d) %s %s", res.StatusCode, msg, constants.UncheckedSymbol)
|
||||
case err := <-errC:
|
||||
log.Fatalf("wait container status exit: %s, %v", constants.UncheckedSymbol, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
trys := 0
|
||||
for {
|
||||
if trys > 2 {
|
||||
break
|
||||
}
|
||||
info, err := api.inspect(service.ID)
|
||||
if err != nil {
|
||||
log.Fatalf("healt checking failed: %v", err)
|
||||
}
|
||||
if info.State.Running {
|
||||
log.Info("service is running")
|
||||
} else {
|
||||
log.Warnf("service is %s", info.State.Status)
|
||||
}
|
||||
time.Sleep(1 * time.Second)
|
||||
trys++
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
191
container_runtimes/docker/sdk/docker.go
Normal file
191
container_runtimes/docker/sdk/docker.go
Normal file
@@ -0,0 +1,191 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/apex/log"
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
dockerTypesContainer "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/client"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/google/uuid"
|
||||
containerruntimes "github.com/metrue/fx/container_runtimes"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Docker docker as image builder
|
||||
type Docker struct {
|
||||
*client.Client
|
||||
}
|
||||
|
||||
// CreateClient create a docker instance
|
||||
func CreateClient(ctx context.Context) (*Docker, error) {
|
||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cli.NegotiateAPIVersion(ctx)
|
||||
return &Docker{cli}, nil
|
||||
}
|
||||
|
||||
// BuildImage a directory to be a image
|
||||
func (d *Docker) BuildImage(ctx context.Context, workdir string, name string) error {
|
||||
tarDir, err := ioutil.TempDir("/tmp", "fx-tar")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.RemoveAll(tarDir)
|
||||
|
||||
imageID := uuid.New().String()
|
||||
tarFilePath := filepath.Join(tarDir, fmt.Sprintf("%s.tar", imageID))
|
||||
|
||||
if err := utils.TarDir(workdir, tarFilePath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dockerBuildContext, err := os.Open(tarFilePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dockerBuildContext.Close()
|
||||
|
||||
options := dockerTypes.ImageBuildOptions{
|
||||
Dockerfile: "Dockerfile",
|
||||
Tags: []string{imageID, name},
|
||||
Labels: map[string]string{
|
||||
"belong-to": "fx",
|
||||
},
|
||||
}
|
||||
|
||||
resp, err := d.ImageBuild(ctx, dockerBuildContext, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info(string(body))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// PushImage push image to hub.docker.com
|
||||
func (d *Docker) PushImage(ctx context.Context, name string) (string, error) {
|
||||
username := os.Getenv("DOCKER_USERNAME")
|
||||
password := os.Getenv("DOCKER_PASSWORD")
|
||||
if username == "" || password == "" {
|
||||
return "", fmt.Errorf("DOCKER_USERNAME and DOCKER_PASSWORD required for push image to registry")
|
||||
}
|
||||
|
||||
// TODO support private registry, like Azure Container registry
|
||||
authConfig := dockerTypes.AuthConfig{
|
||||
Username: username,
|
||||
Password: password,
|
||||
}
|
||||
encodedJSON, err := json.Marshal(authConfig)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
nameWithTag := username + "/" + name
|
||||
if err := d.ImageTag(ctx, name, nameWithTag); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
options := dockerTypes.ImagePushOptions{
|
||||
RegistryAuth: base64.URLEncoding.EncodeToString(encodedJSON),
|
||||
}
|
||||
resp, err := d.ImagePush(ctx, nameWithTag, options)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Close()
|
||||
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
body, err := ioutil.ReadAll(resp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Info(string(body))
|
||||
}
|
||||
return nameWithTag, nil
|
||||
}
|
||||
|
||||
// InspectImage inspect a image
|
||||
func (d *Docker) InspectImage(ctx context.Context, name string, img interface{}) error {
|
||||
_, body, err := d.ImageInspectWithRaw(ctx, name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rdr := bytes.NewReader(body)
|
||||
return json.NewDecoder(rdr).Decode(&img)
|
||||
}
|
||||
|
||||
// StartContainer create and start a container from given image
|
||||
func (d *Docker) StartContainer(ctx context.Context, name string, image string, ports []types.PortBinding) error {
|
||||
portSet := nat.PortSet{}
|
||||
portMap := nat.PortMap{}
|
||||
for _, binding := range ports {
|
||||
bindings := []nat.PortBinding{
|
||||
nat.PortBinding{
|
||||
HostIP: types.DefaultHost,
|
||||
HostPort: fmt.Sprintf("%d", binding.ServiceBindingPort),
|
||||
},
|
||||
}
|
||||
port := nat.Port(fmt.Sprintf("%d/tcp", binding.ContainerExposePort))
|
||||
portSet[port] = struct{}{}
|
||||
portMap[port] = bindings
|
||||
}
|
||||
config := &dockerTypesContainer.Config{
|
||||
Image: image,
|
||||
ExposedPorts: portSet,
|
||||
}
|
||||
|
||||
hostConfig := &dockerTypesContainer.HostConfig{
|
||||
AutoRemove: true,
|
||||
PortBindings: portMap,
|
||||
}
|
||||
resp, err := d.ContainerCreate(ctx, config, hostConfig, nil, name)
|
||||
if os.Getenv("DEBUG") != "" {
|
||||
body, err := json.Marshal(resp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info(string(body))
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.ContainerStart(ctx, resp.ID, dockerTypes.ContainerStartOptions{}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopContainer stop and remove container
|
||||
func (d *Docker) StopContainer(ctx context.Context, name string) error {
|
||||
return d.ContainerStop(ctx, name, nil)
|
||||
}
|
||||
|
||||
// InspectContainer inspect a container
|
||||
func (d *Docker) InspectContainer(ctx context.Context, name string, container interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ containerruntimes.ContainerRuntime = &Docker{}
|
||||
)
|
||||
59
container_runtimes/docker/sdk/docker_test.go
Normal file
59
container_runtimes/docker/sdk/docker_test.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
)
|
||||
|
||||
func TestDocker(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cli, err := CreateClient(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
workdir := "../fixture"
|
||||
name := "fx-test-docker-image"
|
||||
if err := cli.BuildImage(ctx, workdir, name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// wait a while for image to be tagged successfully after build
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
var imgInfo dockerTypes.ImageInspect
|
||||
if err := cli.InspectImage(ctx, name, &imgInfo); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
found := false
|
||||
for _, t := range imgInfo.RepoTags {
|
||||
slice := strings.Split(t, ":")
|
||||
if slice[0] == name {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
t.Fatalf("should have built image with tag %s", name)
|
||||
}
|
||||
|
||||
username := os.Getenv("DOCKER_USERNAME")
|
||||
password := os.Getenv("DOCKER_PASSWORD")
|
||||
if username == "" || password == "" {
|
||||
t.Skip("Skip push image test since DOCKER_USERNAME and DOCKER_PASSWORD not set in environment variable")
|
||||
}
|
||||
|
||||
img, err := cli.PushImage(ctx, name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expect := username + "/" + name
|
||||
if img != expect {
|
||||
t.Fatalf("should get %s but got %s", expect, img)
|
||||
}
|
||||
}
|
||||
17
container_runtimes/runtimes.go
Normal file
17
container_runtimes/runtimes.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package containerruntimes
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
// ContainerRuntime interface
|
||||
type ContainerRuntime interface {
|
||||
BuildImage(ctx context.Context, workdir string, name string) error
|
||||
PushImage(ctx context.Context, name string) (string, error)
|
||||
InspectImage(ct context.Context, name string, img interface{}) error
|
||||
StartContainer(ctx context.Context, name string, image string, bindings []types.PortBinding) error
|
||||
StopContainer(ctx context.Context, name string) error
|
||||
InspectContainer(ctx context.Context, name string, container interface{}) error
|
||||
}
|
||||
3
contrib/docker_packer/Dockerfile
Normal file
3
contrib/docker_packer/Dockerfile
Normal file
@@ -0,0 +1,3 @@
|
||||
FROM docker
|
||||
|
||||
ADD ./build/docker_packer /usr/bin/docker_packer
|
||||
21
contrib/docker_packer/Makefile
Normal file
21
contrib/docker_packer/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
GOBIN ?= ./build
|
||||
GIT_VERSION := $(shell git describe --tags)
|
||||
VERSION ?= $(GIT_VERSION)
|
||||
|
||||
REPO ?= "metrue/fx-docker"
|
||||
TAG ?= "latest"
|
||||
|
||||
build:
|
||||
CGO_ENABLED=0 go build -ldflags "-X main.Version=$(VERSION)" -v -o $(GOBIN)/docker_packer main.go
|
||||
linux-build:
|
||||
CGO_ENABLED=0 GOOS=linux go build -ldflags "-X main.Version=$(VERSION)" -v -o $(GOBIN)/docker_packer main.go
|
||||
docker-build:
|
||||
docker build -t ${REPO}:${TAG} .
|
||||
docker-publish:
|
||||
docker push ${REPO}:${TAG}
|
||||
test:
|
||||
docker run -v /var/run/docker.sock:/var/run/docker.sock ${REPO}:${TAG} docker_packer 'eyJEb2NrZXJmaWxlIjoiRlJPTSBtZXRydWUvZngtbm9kZS1iYXNlXG5cbkNPUFkgLiAuXG5FWFBPU0UgMzAwMFxuQ01EIFtcIm5vZGVcIiwgXCJhcHAuanNcIl1cbiIsImFwcC5qcyI6ImNvbnN0IEtvYSA9IHJlcXVpcmUoJ2tvYScpO1xuY29uc3QgYm9keVBhcnNlciA9IHJlcXVpcmUoJ2tvYS1ib2R5cGFyc2VyJyk7XG5jb25zdCBmeCA9IHJlcXVpcmUoJy4vZngnKTtcblxuY29uc3QgYXBwID0gbmV3IEtvYSgpO1xuYXBwLnVzZShib2R5UGFyc2VyKCkpO1xuYXBwLnVzZShmeCk7XG5cbmFwcC5saXN0ZW4oMzAwMCk7XG4iLCJmeC5qcyI6IlxubW9kdWxlLmV4cG9ydHMgPSAoY3R4KSA9XHUwMDNlIHtcblx0Y3R4LmJvZHkgPSAnaGVsbG8gd29ybGQnXG59XG4ifQ==' app-hello
|
||||
docker run --rm -d -p 3000:3000 --name test-app-hello-container app-hello
|
||||
sleep 2
|
||||
curl 127.0.0.1:3000
|
||||
docker stop test-app-hello-container
|
||||
80
contrib/docker_packer/main.go
Normal file
80
contrib/docker_packer/main.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
runtime "github.com/metrue/fx/container_runtimes/docker/sdk"
|
||||
"github.com/metrue/fx/packer"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Version binary version
|
||||
var Version = "0.0.1"
|
||||
|
||||
func init() {
|
||||
// TODO clean it up
|
||||
os.Setenv("DEBUG", "true")
|
||||
}
|
||||
|
||||
func main() {
|
||||
args := os.Args
|
||||
|
||||
if len(args) != 3 {
|
||||
fmt.Println(`Usage:
|
||||
docker_packer <encrypt_docker_project_source_tree> <image_name>
|
||||
`)
|
||||
return
|
||||
}
|
||||
|
||||
meta := args[1]
|
||||
name := args[2]
|
||||
|
||||
str, err := base64.StdEncoding.WithPadding(base64.StdPadding).DecodeString(meta)
|
||||
if err != nil {
|
||||
log.Fatalf("could decode meta: %s, %v", meta, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
var tree map[string]string
|
||||
if err := json.Unmarshal([]byte(str), &tree); err != nil {
|
||||
log.Fatalf("could not unmarshal meta: %s", meta)
|
||||
os.Exit(1)
|
||||
}
|
||||
workdir := "/tmp/fx"
|
||||
if err := packer.TreeToDir(tree, workdir); err != nil {
|
||||
log.Fatalf("could not restore to dir: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
defer os.RemoveAll(workdir)
|
||||
|
||||
ctx := context.Background()
|
||||
dockerClient, err := runtime.CreateClient(ctx)
|
||||
if err != nil {
|
||||
log.Fatalf("could not create a docker client: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
if err := dockerClient.BuildImage(ctx, workdir, name); err != nil {
|
||||
log.Fatalf("could not build image: %s", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
nameWithTag := name + ":latest"
|
||||
if err := dockerClient.ImageTag(ctx, name, nameWithTag); err != nil {
|
||||
log.Fatalf("could tag image: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
var imgInfo dockerTypes.ImageInspect
|
||||
if err := utils.RunWithRetry(func() error {
|
||||
return dockerClient.InspectImage(context.Background(), name, &imgInfo)
|
||||
}, time.Second*1, 5); err != nil {
|
||||
fmt.Printf("inspect image failed: %s", err)
|
||||
}
|
||||
fmt.Println("image built succcessfully")
|
||||
}
|
||||
15
deploy/deployer.go
Normal file
15
deploy/deployer.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
types "github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
// Deployer make a image a service
|
||||
type Deployer interface {
|
||||
Deploy(ctx context.Context, fn types.Func, name string, bindings []types.PortBinding) error
|
||||
Destroy(ctx context.Context, name string) error
|
||||
Update(ctx context.Context, name string) error
|
||||
GetStatus(ctx context.Context, name string) error
|
||||
}
|
||||
82
deploy/docker/docker.go
Normal file
82
deploy/docker/docker.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
runtime "github.com/metrue/fx/container_runtimes/docker/sdk"
|
||||
"github.com/metrue/fx/deploy"
|
||||
"github.com/metrue/fx/packer"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
)
|
||||
|
||||
// Docker manage container
|
||||
type Docker struct {
|
||||
client *runtime.Docker
|
||||
}
|
||||
|
||||
// CreateClient create a docker instance
|
||||
func CreateClient(ctx context.Context) (*Docker, error) {
|
||||
cli, err := runtime.CreateClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Docker{client: cli}, nil
|
||||
}
|
||||
|
||||
// Deploy create a Docker container from given image, and bind the constants.FxContainerExposePort to given port
|
||||
func (d *Docker) Deploy(ctx context.Context, fn types.Func, name string, ports []types.PortBinding) error {
|
||||
workdir := fmt.Sprintf("/tmp/fx-%d", time.Now().Unix())
|
||||
defer os.RemoveAll(workdir)
|
||||
|
||||
if err := packer.PackIntoDir(fn, workdir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.client.BuildImage(ctx, workdir, name); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nameWithTag := name + ":latest"
|
||||
if err := d.client.ImageTag(ctx, name, nameWithTag); err != nil {
|
||||
log.Fatalf("could tag image: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
// when deploy a function on a bare Docker running without Kubernetes,
|
||||
// image would be built on-demand on host locally, so there is no need to
|
||||
// pull image from remote.
|
||||
// But it takes some times waiting image ready after image built, we retry to make sure it ready here
|
||||
var imgInfo dockerTypes.ImageInspect
|
||||
if err := utils.RunWithRetry(func() error {
|
||||
return d.client.InspectImage(ctx, name, &imgInfo)
|
||||
}, time.Second*1, 5); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.client.StartContainer(ctx, name, name, ports)
|
||||
}
|
||||
|
||||
// Update a container
|
||||
func (d *Docker) Update(ctx context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy stop and remove container
|
||||
func (d *Docker) Destroy(ctx context.Context, name string) error {
|
||||
return d.client.ContainerStop(ctx, name, nil)
|
||||
}
|
||||
|
||||
// GetStatus get status of container
|
||||
func (d *Docker) GetStatus(ctx context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ deploy.Deployer = &Docker{}
|
||||
)
|
||||
47
deploy/docker/docker_test.go
Normal file
47
deploy/docker/docker_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func TestDocker(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
cli, err := CreateClient(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
name := "helloworld"
|
||||
bindings := []types.PortBinding{
|
||||
types.PortBinding{
|
||||
ServiceBindingPort: 80,
|
||||
ContainerExposePort: 3000,
|
||||
},
|
||||
types.PortBinding{
|
||||
ServiceBindingPort: 443,
|
||||
ContainerExposePort: 3000,
|
||||
},
|
||||
}
|
||||
|
||||
fn := types.Func{
|
||||
Language: "node",
|
||||
Source: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello world'
|
||||
}
|
||||
`,
|
||||
}
|
||||
if err := cli.Deploy(ctx, fn, name, bindings); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
if err := cli.Destroy(ctx, name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
5
deploy/docker/fixture/Dockerfile
Normal file
5
deploy/docker/fixture/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]
|
||||
9
deploy/docker/fixture/app.js
Normal file
9
deploy/docker/fixture/app.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const fx = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(fx);
|
||||
|
||||
app.listen(3000);
|
||||
3
deploy/docker/fixture/fx.js
Normal file
3
deploy/docker/fixture/fx.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello world'
|
||||
}
|
||||
47
deploy/kubernetes/configmap.go
Normal file
47
deploy/kubernetes/configmap.go
Normal file
@@ -0,0 +1,47 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// CreateConfigMap create a config map with data
|
||||
func (k *K8S) CreateConfigMap(namespace string, name string, data map[string]string) (*apiv1.ConfigMap, error) {
|
||||
cm := &apiv1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
return k.CoreV1().ConfigMaps(namespace).Create(cm)
|
||||
}
|
||||
|
||||
// DeleteConfigMap delete a config map
|
||||
func (k *K8S) DeleteConfigMap(namespace string, name string) error {
|
||||
return k.CoreV1().ConfigMaps(namespace).Delete(name, &metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
// UpdateConfigMap update a config map
|
||||
func (k *K8S) UpdateConfigMap(namespace string, name string, data map[string]string) (*apiv1.ConfigMap, error) {
|
||||
cm := &apiv1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Data: data,
|
||||
}
|
||||
return k.CoreV1().ConfigMaps(namespace).Update(cm)
|
||||
}
|
||||
|
||||
// GetConfigMap get a config map
|
||||
func (k *K8S) GetConfigMap(namespace string, name string) (*apiv1.ConfigMap, error) {
|
||||
return k.CoreV1().ConfigMaps(namespace).Get(name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// CreateOrUpdateConfigMap create or update a config map
|
||||
func (k *K8S) CreateOrUpdateConfigMap(namespace string, name string, data map[string]string) (*apiv1.ConfigMap, error) {
|
||||
_, err := k.GetConfigMap(namespace, name)
|
||||
if err != nil {
|
||||
return k.CreateConfigMap(namespace, name, data)
|
||||
}
|
||||
return k.UpdateConfigMap(namespace, name, data)
|
||||
}
|
||||
35
deploy/kubernetes/configmap_test.go
Normal file
35
deploy/kubernetes/configmap_test.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestConfigMap(t *testing.T) {
|
||||
kubeconfig := os.Getenv("KUBECONFIG")
|
||||
if kubeconfig == "" {
|
||||
t.Skip("skip test since no KUBECONFIG given in environment variable")
|
||||
}
|
||||
|
||||
k8s, err := Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
namespace := "default"
|
||||
name := "test-configmap"
|
||||
data := map[string]string{
|
||||
"message": "hello world",
|
||||
}
|
||||
cm, err := k8s.CreateConfigMap(namespace, name, data)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cm.Name != name {
|
||||
t.Fatalf("should get %s but got %s", name, cm.Name)
|
||||
}
|
||||
|
||||
if err != k8s.DeleteConfigMap(namespace, name) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
8
deploy/kubernetes/constants.go
Normal file
8
deploy/kubernetes/constants.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package kubernetes
|
||||
|
||||
// ConfigMap is the key to function docker project source code in configmap
|
||||
var ConfigMap = struct {
|
||||
AppMetaEnvName string
|
||||
}{
|
||||
AppMetaEnvName: "APP_META",
|
||||
}
|
||||
103
deploy/kubernetes/deployment.go
Normal file
103
deploy/kubernetes/deployment.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
func generateDeploymentSpec(
|
||||
name string,
|
||||
image string,
|
||||
bindPorts []types.PortBinding,
|
||||
replicas int32,
|
||||
selector map[string]string,
|
||||
) *appsv1.Deployment {
|
||||
ports := []apiv1.ContainerPort{}
|
||||
for index, binding := range bindPorts {
|
||||
ports = append(ports, apiv1.ContainerPort{
|
||||
Name: fmt.Sprintf("fx-container-%d", index),
|
||||
ContainerPort: binding.ContainerExposePort,
|
||||
})
|
||||
}
|
||||
|
||||
container := apiv1.Container{
|
||||
Name: "fx-placeholder-container-name",
|
||||
Image: image,
|
||||
Ports: ports,
|
||||
ImagePullPolicy: v1.PullNever,
|
||||
}
|
||||
return &appsv1.Deployment{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
},
|
||||
Spec: appsv1.DeploymentSpec{
|
||||
Replicas: &replicas,
|
||||
Selector: &metav1.LabelSelector{
|
||||
MatchLabels: selector,
|
||||
},
|
||||
Template: apiv1.PodTemplateSpec{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Labels: selector,
|
||||
},
|
||||
Spec: apiv1.PodSpec{
|
||||
Containers: []apiv1.Container{container},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetDeployment get a deployment
|
||||
func (k *K8S) GetDeployment(namespace string, name string) (*appsv1.Deployment, error) {
|
||||
return k.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{})
|
||||
}
|
||||
|
||||
// CreateDeployment create a deployment
|
||||
func (k *K8S) CreateDeployment(
|
||||
namespace string,
|
||||
name string,
|
||||
image string,
|
||||
ports []types.PortBinding,
|
||||
replicas int32,
|
||||
selector map[string]string,
|
||||
) (*appsv1.Deployment, error) {
|
||||
deployment := generateDeploymentSpec(name, image, ports, replicas, selector)
|
||||
return k.AppsV1().Deployments(namespace).Create(deployment)
|
||||
}
|
||||
|
||||
// UpdateDeployment update a deployment
|
||||
func (k *K8S) UpdateDeployment(
|
||||
namespace string,
|
||||
name string,
|
||||
image string,
|
||||
ports []types.PortBinding,
|
||||
replicas int32,
|
||||
selector map[string]string,
|
||||
) (*appsv1.Deployment, error) {
|
||||
deployment := generateDeploymentSpec(name, image, ports, replicas, selector)
|
||||
return k.AppsV1().Deployments(namespace).Update(deployment)
|
||||
}
|
||||
|
||||
// DeleteDeployment delete a deployment
|
||||
func (k *K8S) DeleteDeployment(namespace string, name string) error {
|
||||
return k.AppsV1().Deployments(namespace).Delete(name, &metav1.DeleteOptions{})
|
||||
}
|
||||
|
||||
// CreateDeploymentWithInitContainer create a deployment which will wait InitContainer to do the image build before function container start
|
||||
func (k *K8S) CreateDeploymentWithInitContainer(
|
||||
namespace string,
|
||||
name string,
|
||||
ports []types.PortBinding,
|
||||
replicas int32,
|
||||
selector map[string]string,
|
||||
) (*appsv1.Deployment, error) {
|
||||
deployment := generateDeploymentSpec(name, name, ports, replicas, selector)
|
||||
updatedDeployment := injectInitContainer(name, deployment)
|
||||
fmt.Println(updatedDeployment)
|
||||
return k.AppsV1().Deployments(namespace).Create(updatedDeployment)
|
||||
}
|
||||
61
deploy/kubernetes/deployment_test.go
Normal file
61
deploy/kubernetes/deployment_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func TestDeployment(t *testing.T) {
|
||||
namespace := "default"
|
||||
name := "fx-hello-world"
|
||||
image := "metrue/kube-hello"
|
||||
selector := map[string]string{
|
||||
"app": "fx-app",
|
||||
}
|
||||
|
||||
kubeconfig := os.Getenv("KUBECONFIG")
|
||||
if kubeconfig == "" {
|
||||
t.Skip("skip test since no KUBECONFIG given in environment variable")
|
||||
}
|
||||
|
||||
k8s, err := Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := k8s.GetDeployment(namespace, name); err == nil {
|
||||
t.Fatalf("should get not found error")
|
||||
}
|
||||
|
||||
replicas := int32(2)
|
||||
bindings := []types.PortBinding{
|
||||
types.PortBinding{
|
||||
ServiceBindingPort: 80,
|
||||
ContainerExposePort: 3000,
|
||||
},
|
||||
types.PortBinding{
|
||||
ServiceBindingPort: 443,
|
||||
ContainerExposePort: 3000,
|
||||
},
|
||||
}
|
||||
deployment, err := k8s.CreateDeployment(namespace, name, image, bindings, replicas, selector)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if deployment == nil {
|
||||
t.Fatalf("deploymetn should not be %v", nil)
|
||||
}
|
||||
|
||||
if deployment.Name != name {
|
||||
t.Fatalf("should get %s but got %s", name, deployment.Name)
|
||||
}
|
||||
|
||||
if *deployment.Spec.Replicas != replicas {
|
||||
t.Fatalf("should get %v but got %v", replicas, deployment.Spec.Replicas)
|
||||
}
|
||||
|
||||
if err := k8s.DeleteDeployment(namespace, name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
5
deploy/kubernetes/fixture/Dockerfile
Normal file
5
deploy/kubernetes/fixture/Dockerfile
Normal file
@@ -0,0 +1,5 @@
|
||||
FROM metrue/fx-node-base
|
||||
|
||||
COPY . .
|
||||
EXPOSE 3000
|
||||
CMD ["node", "app.js"]
|
||||
9
deploy/kubernetes/fixture/app.js
Normal file
9
deploy/kubernetes/fixture/app.js
Normal file
@@ -0,0 +1,9 @@
|
||||
const Koa = require('koa');
|
||||
const bodyParser = require('koa-bodyparser');
|
||||
const fx = require('./fx');
|
||||
|
||||
const app = new Koa();
|
||||
app.use(bodyParser());
|
||||
app.use(fx);
|
||||
|
||||
app.listen(3000);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user