Compare commits
380 Commits
support-R
...
0.8.0-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
294131b48f | ||
|
|
48413abaa1 | ||
|
|
d36b2b935b | ||
|
|
f493749689 | ||
|
|
9de10bc885 | ||
|
|
2d5446686a | ||
|
|
0d7d4f4a6a | ||
|
|
23c4171ece | ||
|
|
d8a1868fce | ||
|
|
d91a9959a8 | ||
|
|
87e7c7d6ae | ||
|
|
89c94daebc | ||
|
|
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,56 +0,0 @@
|
||||
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
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
|
||||
- setup_remote_docker
|
||||
|
||||
- run:
|
||||
name: Install tools
|
||||
command: |
|
||||
go get github.com/golang/dep
|
||||
cd $GOPATH/src/github.com/golang/dep
|
||||
go install ./...
|
||||
|
||||
- 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
|
||||
fx up examples/functions/func.R >> deploy.log
|
||||
cat server_output.log
|
||||
cat deploy.log;
|
||||
cat deploy.log | grep 'Succed: 1' | wc -l | grep 7
|
||||
|
||||
deployment:
|
||||
production:
|
||||
branch: master
|
||||
commands:
|
||||
- echo "Not Ready Yet"
|
||||
@@ -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
|
||||
109
.github/workflows/ci.yml
vendored
Normal file
109
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
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: lint
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint \
|
||||
golangci-lint run -v
|
||||
|
||||
- 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 ./...
|
||||
- name: code cov
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
./scripts/coverage.sh
|
||||
bash <(curl -s https://codecov.io/bash) -t ${CODECOV_TOKEN}
|
||||
|
||||
- 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: test fx cli
|
||||
env:
|
||||
REMOTE_HOST_ADDR: ${{secrets.DOCKER_REMOTE_HOST_ADDR}}
|
||||
REMOTE_HOST_USER: ${{secrets.DOCKER_REMOTE_HOST_USER}}
|
||||
REMOTE_HOST_PASSWORD: ${{secrets.DOCKER_REMOTE_HOST_PASSWORD}}
|
||||
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 up -n hello -p 12345 examples/functions/JavaScript/func.js
|
||||
./build/fx down 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
|
||||
70
.github/workflows/docker.yml
vendored
Normal file
70
.github/workflows/docker.yml
vendored
Normal file
@@ -0,0 +1,70 @@
|
||||
on: [push]
|
||||
# schedule:
|
||||
# - cron: '0 12 * * *'
|
||||
name: docker
|
||||
jobs:
|
||||
Docker:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
docker_version:
|
||||
- 18.09
|
||||
# - 19.03
|
||||
# - 19.09
|
||||
docker_channel:
|
||||
- stable
|
||||
# - test
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: setup docker
|
||||
uses: docker-practice/actions-setup-docker@master
|
||||
with:
|
||||
docker_version: ${{ matrix.docker_version }}
|
||||
docker_channel: ${{ matrix.docker_channel }}
|
||||
|
||||
- name: login docker hub
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
run: |
|
||||
docker login --username $DOCKER_USERNAME --password $DOCKER_PASSWORD
|
||||
|
||||
- name: build and publish fx d image
|
||||
if: always()
|
||||
run: |
|
||||
docker build -t metrue/fx-d-base:latest -f ./assets/dockerfiles/base/d/Dockerfile ./assets/dockerfiles/base/d
|
||||
docker push metrue/fx-d-base:latest
|
||||
|
||||
# - name: build and publish fx java image
|
||||
# run: |
|
||||
# docker build -t metrue/fx-go-base:latest -f ./assets/dockerfiles/base/java/Dockerfile ./assets/dockerfiles/base/java
|
||||
# docker push metrue/fx-java-base:latest
|
||||
|
||||
- name: build and publish fx node image
|
||||
if: always()
|
||||
run: |
|
||||
docker build -t metrue/fx-node-base:latest -f ./assets/dockerfiles/base/node/Dockerfile ./assets/dockerfiles/base/node
|
||||
docker push metrue/fx-node-base:latest
|
||||
|
||||
- name: build and publish fx python image
|
||||
if: always()
|
||||
run: |
|
||||
docker build -t metrue/fx-python-base:latest -f ./assets/dockerfiles/base/python/Dockerfile ./assets/dockerfiles/base/python
|
||||
- name: publish fx python image
|
||||
env:
|
||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
|
||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
|
||||
run: |
|
||||
docker push metrue/fx-python-base:latest
|
||||
|
||||
# - name: build and publish fx rust image
|
||||
# if: always()
|
||||
# run: |
|
||||
# docker build -t metrue/fx-rust-base:latest -f ./assets/dockerfiles/base/rust/Dockerfile ./assets/dockerfiles/base/python
|
||||
# docker push metrue/fx-rust-base:latest
|
||||
|
||||
- name: build and publish fx julia image
|
||||
if: always()
|
||||
run: |
|
||||
docker build -t metrue/fx-julia-base:latest -f ./assets/dockerfiles/base/julia/Dockerfile ./assets/dockerfiles/base/julia
|
||||
docker push metrue/fx-julia-base:latest
|
||||
114
.github/workflows/release.yml
vendored
Normal file
114
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
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: lint
|
||||
run: |
|
||||
docker run --rm -v $(pwd):/app -w /app golangci/golangci-lint \
|
||||
golangci-lint run -v
|
||||
|
||||
- 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 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 up -n hello -p 12345 examples/functions/JavaScript/func.js
|
||||
./build/fx down 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"
|
||||
38
Makefile
38
Makefile
@@ -1,15 +1,41 @@
|
||||
OUTPUT_DIR=./build
|
||||
DIST_DIR=./dist
|
||||
|
||||
install-deps:
|
||||
@dep ensure
|
||||
lint:
|
||||
golangci-lint run
|
||||
|
||||
generate:
|
||||
packr
|
||||
|
||||
b:
|
||||
go build -o ${OUTPUT_DIR}/fx fx.go
|
||||
|
||||
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:
|
||||
echo 'run testing on localhost'
|
||||
./scripts/test_cli.sh
|
||||
# TODO enable remote test
|
||||
echo 'run testing on remote host'
|
||||
DOCKER_REMOTE_HOST_ADDR=${REMOTE_HOST_ADDR} DOCKER_REMOTE_HOST_USER=${REMOTE_HOST_USER} DOCKER_REMOTE_HOST_PASSWORD=${REMOTE_HOST_PASSWORD} ./scripts/test_cli.sh
|
||||
|
||||
http-test:
|
||||
./scripts/http_test.sh
|
||||
|
||||
zip:
|
||||
zip -r images.zip images/
|
||||
.PHONY: test build start list clean generate
|
||||
|
||||
396
README.md
396
README.md
@@ -1,150 +1,301 @@
|
||||
fx
|
||||
------
|
||||
|
||||
Poor man's function as a service.
|
||||
<br/>
|
||||

|
||||

|
||||
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fmetrue%2Ffx?ref=badge_shield)
|
||||
[](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!
|
||||
|
||||
@@ -154,25 +305,54 @@ Thank you to all the people who already contributed to fx!
|
||||
<a href="https://github.com/metrue" target="_blank">
|
||||
<img alt="metrue" src="https://avatars2.githubusercontent.com/u/1001246?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/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/mbesancon" target="_blank">
|
||||
<img alt="mbesancon" src="https://avatars2.githubusercontent.com/u/7623090?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/avelino" target="_blank">
|
||||
<img alt="avelino" src="https://avatars2.githubusercontent.com/u/31996?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/DaidoujiChen" target="_blank">
|
||||
<img alt="DaidoujiChen" src="https://avatars0.githubusercontent.com/u/670441?v=4&s=50" width="50">
|
||||
<a href="https://github.com/matbesancon" target="_blank">
|
||||
<img alt="mbesancon" src="https://avatars2.githubusercontent.com/u/7623090?s=60&v=4" width="50">
|
||||
</a>
|
||||
<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/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/DaidoujiChen" target="_blank">
|
||||
<img alt="DaidoujiChen" src="https://avatars0.githubusercontent.com/u/670441?v=4&s=50" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/avelino" target="_blank">
|
||||
<img alt="avelino" src="https://avatars2.githubusercontent.com/u/31996?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/polyrabbit" target="_blank">
|
||||
<img alt="polyrabbit" src="https://avatars0.githubusercontent.com/u/2657334?s=60&v=4" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/johnlunney" target="_blank">
|
||||
<img alt="johnlunney" src="https://avatars3.githubusercontent.com/u/536947?s=60&v=4" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/tbrand" target="_blank">
|
||||
<img alt="tbrand" src="https://avatars0.githubusercontent.com/u/3483230?s=60&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>
|
||||
<a href="https://github.com/border-radius" target="_blank">
|
||||
<img alt="border-radius" src="https://avatars0.githubusercontent.com/u/3204785?s=60&v=4" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/Russtopia" target="_blank">
|
||||
<img alt="Russtopia" src="https://avatars1.githubusercontent.com/u/2966177?s=60&v=4<Paste>" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/FrontMage" target="_blank">
|
||||
<img alt="FrontMage" src="https://avatars2.githubusercontent.com/u/17007026?s=60&v=4" width="50">
|
||||
</a>
|
||||
<a href="https://github.com/DropNib" target="_blank">
|
||||
<img alt="DropNib" src="https://avatars0.githubusercontent.com/u/32019589?s=60&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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path"
|
||||
)
|
||||
|
||||
// Server contains the server configuration information
|
||||
var Server = map[string]string{
|
||||
"host": "localhost",
|
||||
"port": "8080",
|
||||
}
|
||||
|
||||
// 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",
|
||||
}
|
||||
|
||||
var ExtLangMap = map[string]string {
|
||||
".js": "node",
|
||||
".go": "go",
|
||||
".rb": "ruby",
|
||||
".py": "python",
|
||||
".php": "php",
|
||||
".jl": "julia",
|
||||
}
|
||||
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'
|
||||
}
|
||||
427
container_runtimes/docker/http/api.go
Normal file
427
container_runtimes/docker/http/api.go
Normal file
@@ -0,0 +1,427 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/apex/log"
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
dockerTypesContainer "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/api/types/network"
|
||||
"github.com/docker/go-connections/nat"
|
||||
"github.com/google/go-querystring/query"
|
||||
"github.com/google/uuid"
|
||||
containerruntimes "github.com/metrue/fx/container_runtimes"
|
||||
"github.com/metrue/fx/types"
|
||||
"github.com/metrue/fx/utils"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// ListContainer list service
|
||||
func (api *API) ListContainer(ctx context.Context, 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:"status,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
|
||||
}
|
||||
|
||||
// BuildImage build image
|
||||
func (api *API) 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()
|
||||
|
||||
type buildQuery struct {
|
||||
Labels string `url:"labels,omitempty"`
|
||||
Tags string `url:"t,omitempty"`
|
||||
Dockerfile string `url:"dockerfile,omitempty"`
|
||||
}
|
||||
|
||||
// Apply default labels
|
||||
labelsJSON, _ := json.Marshal(map[string]string{
|
||||
"belong-to": "fx",
|
||||
})
|
||||
q := buildQuery{
|
||||
Labels: string(labelsJSON),
|
||||
Dockerfile: "Dockerfile",
|
||||
}
|
||||
|
||||
qs, err := query.Values(q)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
qs.Add("t", name)
|
||||
qs.Add("t", imageID)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// PushImage push a image
|
||||
func (api *API) PushImage(ctx context.Context, name string) (string, error) {
|
||||
return "", nil
|
||||
}
|
||||
|
||||
// InspectImage inspect image
|
||||
func (api *API) InspectImage(ctx context.Context, name string, image interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// TagImage tag image
|
||||
func (api *API) TagImage(ctx context.Context, name string, tag string) error {
|
||||
query := url.Values{}
|
||||
query.Set("repo", name)
|
||||
query.Set("tag", tag)
|
||||
path := fmt.Sprintf("/images/%s/tag?%s", name, query.Encode())
|
||||
|
||||
url := fmt.Sprintf("%s%s", api.endpoint, path)
|
||||
req, err := http.NewRequest("POST", url, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
client := &http.Client{Timeout: 10 * time.Second}
|
||||
if _, err = client.Do(req); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StartContainer start container
|
||||
func (api *API) StartContainer(ctx context.Context, name string, image string, bindings []types.PortBinding) 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)
|
||||
|
||||
endpoint := &network.EndpointSettings{
|
||||
NetworkID: networks[0].ID,
|
||||
}
|
||||
networkConfig := &network.NetworkingConfig{
|
||||
EndpointsConfig: map[string]*network.EndpointSettings{
|
||||
"fx-net": endpoint,
|
||||
},
|
||||
}
|
||||
|
||||
portSet := nat.PortSet{}
|
||||
portMap := nat.PortMap{}
|
||||
for _, binding := range bindings {
|
||||
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,
|
||||
}
|
||||
|
||||
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", 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", 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", name)
|
||||
|
||||
if _, err = api.inspect(createRes.ID); err != nil {
|
||||
msg := fmt.Sprintf("inspect container %s error", name)
|
||||
return errors.Wrap(err, msg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// StopContainer stop a container
|
||||
func (api *API) StopContainer(ctx context.Context, name string) error {
|
||||
return api.Stop(name)
|
||||
}
|
||||
|
||||
// InspectContainer inspect container
|
||||
func (api *API) InspectContainer(ctx context.Context, name string, container interface{}) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ containerruntimes.ContainerRuntime = &API{}
|
||||
)
|
||||
111
container_runtimes/docker/http/api_test.go
Normal file
111
container_runtimes/docker/http/api_test.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package api
|
||||
|
||||
// func TestDockerHTTP(t *testing.T) {
|
||||
// const addr = "127.0.0.1"
|
||||
// const user = ""
|
||||
// const passord = ""
|
||||
// provisioner := provision.NewWithHost(addr, user, passord)
|
||||
// if err := utils.RunWithRetry(func() error {
|
||||
// if !provisioner.IsFxAgentRunning() {
|
||||
// if err := provisioner.StartFxAgent(); err != nil {
|
||||
// log.Infof("could not start fx agent on host: %s", err)
|
||||
// return err
|
||||
// }
|
||||
// log.Infof("fx agent started")
|
||||
// } else {
|
||||
// log.Infof("fx agent is running")
|
||||
// }
|
||||
// return nil
|
||||
// }, 2*time.Second, 10); err != nil {
|
||||
// t.Fatal(err)
|
||||
// } else {
|
||||
// defer provisioner.StopFxAgent()
|
||||
// }
|
||||
//
|
||||
// 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 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.ListContainer(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)
|
||||
// }
|
||||
//
|
||||
// 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)
|
||||
// }
|
||||
// }
|
||||
@@ -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();
|
||||
}
|
||||
51
container_runtimes/docker/http/call.go
Normal file
51
container_runtimes/docker/http/call.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
// Call function directly with given params
|
||||
func (api *API) Call(file string, param string, project types.Project) error {
|
||||
return nil
|
||||
// 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) {
|
||||
|
||||
}
|
||||
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
|
||||
}
|
||||
59
container_runtimes/docker/http/service_build.go
Normal file
59
container_runtimes/docker/http/service_build.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package api
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "io/ioutil"
|
||||
// "os"
|
||||
// "path/filepath"
|
||||
//
|
||||
// "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
|
||||
// }
|
||||
82
container_runtimes/docker/http/service_build_test.go
Normal file
82
container_runtimes/docker/http/service_build_test.go
Normal file
@@ -0,0 +1,82 @@
|
||||
package api
|
||||
|
||||
// import (
|
||||
// "fmt"
|
||||
// "io/ioutil"
|
||||
// "os"
|
||||
// "path/filepath"
|
||||
// "testing"
|
||||
//
|
||||
// "github.com/metrue/fx/types"
|
||||
// )
|
||||
//
|
||||
// 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())
|
||||
// }
|
||||
// }
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
71
container_runtimes/docker/http/up.go
Normal file
71
container_runtimes/docker/http/up.go
Normal file
@@ -0,0 +1,71 @@
|
||||
package api
|
||||
|
||||
// // 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
|
||||
// }
|
||||
229
container_runtimes/docker/sdk/docker.go
Normal file
229
container_runtimes/docker/sdk/docker.go
Normal file
@@ -0,0 +1,229 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/apex/log"
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
dockerTypesContainer "github.com/docker/docker/api/types/container"
|
||||
dockerFilters "github.com/docker/docker/api/types/filters"
|
||||
"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()
|
||||
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)
|
||||
}
|
||||
|
||||
// TagImage tag image
|
||||
func (d *Docker) TagImage(ctx context.Context, name string, tag string) error {
|
||||
return d.ImageTag(ctx, name, tag)
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
// ListContainer list containers
|
||||
func (d *Docker) ListContainer(ctx context.Context, name string) ([]types.Service, error) {
|
||||
args := dockerFilters.NewArgs(
|
||||
dockerFilters.Arg("label", "belong-to=fx"),
|
||||
)
|
||||
containers, err := d.ContainerList(ctx, dockerTypes.ContainerListOptions{
|
||||
Filters: args,
|
||||
})
|
||||
if 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
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
19
container_runtimes/runtimes.go
Normal file
19
container_runtimes/runtimes.go
Normal file
@@ -0,0 +1,19 @@
|
||||
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(ctx context.Context, name string, img interface{}) error
|
||||
TagImage(ctx context.Context, name string, tag string) 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
|
||||
ListContainer(ctx context.Context, filter string) ([]types.Service, error)
|
||||
}
|
||||
58
context/context.go
Normal file
58
context/context.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
type key string
|
||||
|
||||
const (
|
||||
keyCliCtx = key("cmd_cli")
|
||||
)
|
||||
|
||||
// Context fx context
|
||||
type Context struct {
|
||||
context.Context
|
||||
}
|
||||
|
||||
// NewContext new a context
|
||||
func NewContext() *Context {
|
||||
ctx := context.Background()
|
||||
return &Context{ctx}
|
||||
}
|
||||
|
||||
// FromCliContext create context from cli.Context
|
||||
func FromCliContext(c *cli.Context) *Context {
|
||||
ctx := NewContext()
|
||||
ctx.WithCliContext(c)
|
||||
return ctx
|
||||
}
|
||||
|
||||
// WithCliContext set cli.Context
|
||||
func (ctx *Context) WithCliContext(c *cli.Context) {
|
||||
newCtx := context.WithValue(ctx.Context, keyCliCtx, c)
|
||||
ctx.Context = newCtx
|
||||
}
|
||||
|
||||
// GetCliContext get cli.Context
|
||||
func (ctx *Context) GetCliContext() *cli.Context {
|
||||
return ctx.Value(keyCliCtx).(*cli.Context)
|
||||
}
|
||||
|
||||
// Set a value with name
|
||||
func (ctx *Context) Set(name string, value interface{}) {
|
||||
newCtx := context.WithValue(ctx.Context, name, value)
|
||||
ctx.Context = newCtx
|
||||
}
|
||||
|
||||
// Get a value
|
||||
func (ctx *Context) Get(name string) interface{} {
|
||||
return ctx.Context.Value(name)
|
||||
}
|
||||
|
||||
// Use invole a middle
|
||||
func (ctx *Context) Use(fn func(ctx *Context) error) error {
|
||||
return fn(ctx)
|
||||
}
|
||||
25
context/context_test.go
Normal file
25
context/context_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package context
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
func TestContext(t *testing.T) {
|
||||
ctx := NewContext()
|
||||
cli := cli.NewContext(nil, nil, nil)
|
||||
ctx.WithCliContext(cli)
|
||||
c := ctx.GetCliContext()
|
||||
if c != cli {
|
||||
t.Fatalf("should get %v but got %v", cli, c)
|
||||
}
|
||||
|
||||
key := "k_1"
|
||||
value := "hello"
|
||||
ctx.Set(key, "hello")
|
||||
v := ctx.Get(key).(string)
|
||||
if v != value {
|
||||
t.Fatalf("should get %v but %v", value, v)
|
||||
}
|
||||
}
|
||||
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
|
||||
78
contrib/docker_packer/main.go
Normal file
78
contrib/docker_packer/main.go
Normal file
@@ -0,0 +1,78 @@
|
||||
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"
|
||||
)
|
||||
|
||||
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
|
||||
//nolint
|
||||
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")
|
||||
}
|
||||
16
deploy/deployer.go
Normal file
16
deploy/deployer.go
Normal file
@@ -0,0 +1,16 @@
|
||||
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
|
||||
List(ctx context.Context, name string) ([]types.Service, error)
|
||||
}
|
||||
104
deploy/docker/docker.go
Normal file
104
deploy/docker/docker.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
dockerTypes "github.com/docker/docker/api/types"
|
||||
"github.com/metrue/fx/constants"
|
||||
containerruntimes "github.com/metrue/fx/container_runtimes"
|
||||
dockerHTTP "github.com/metrue/fx/container_runtimes/docker/http"
|
||||
dockerSDK "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 {
|
||||
cli containerruntimes.ContainerRuntime
|
||||
}
|
||||
|
||||
// CreateClient create a docker instance
|
||||
func CreateClient(ctx context.Context) (d *Docker, err error) {
|
||||
var cli containerruntimes.ContainerRuntime
|
||||
host := os.Getenv("DOCKER_REMOTE_HOST_ADDR")
|
||||
user := os.Getenv("DOCKER_REMOTE_HOST_USER")
|
||||
if host != "" && user != "" {
|
||||
cli, err = dockerHTTP.Create(host, constants.AgentPort)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
cli, err = dockerSDK.CreateClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &Docker{cli: 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 {
|
||||
log.Fatalf("could not pack function %v: %v", fn, err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := d.cli.BuildImage(ctx, workdir, name); err != nil {
|
||||
log.Fatalf("could not build image: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
nameWithTag := name + ":latest"
|
||||
if err := d.cli.TagImage(ctx, name, nameWithTag); err != nil {
|
||||
log.Fatalf("could not 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.cli.InspectImage(ctx, name, &imgInfo)
|
||||
}, time.Second*1, 5); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return d.cli.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.cli.StopContainer(ctx, name)
|
||||
}
|
||||
|
||||
// GetStatus get status of container
|
||||
func (d *Docker) GetStatus(ctx context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// List services
|
||||
func (d *Docker) List(ctx context.Context, name string) ([]types.Service, error) {
|
||||
// FIXME support remote host
|
||||
return d.cli.ListContainer(ctx, name)
|
||||
}
|
||||
|
||||
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);
|
||||
3
deploy/kubernetes/fixture/fx.js
Normal file
3
deploy/kubernetes/fixture/fx.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello world'
|
||||
}
|
||||
70
deploy/kubernetes/init_container.go
Normal file
70
deploy/kubernetes/init_container.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
apiv1 "k8s.io/api/core/v1"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
)
|
||||
|
||||
// This is docker image provided by fx/contrib/docker_packer
|
||||
// it can build a Docker image with give Docker project source codes encoded with base64
|
||||
// check the detail fx/contrib/docker_packer/main.go
|
||||
const image = "metrue/fx-docker"
|
||||
|
||||
func injectInitContainer(name string, deployment *appsv1.Deployment) *appsv1.Deployment {
|
||||
configMapHasToBeReady := true
|
||||
valueInConfigMapHasToBeReady := true
|
||||
initContainer := v1.Container{
|
||||
Name: "fx-docker-build-c",
|
||||
Image: image,
|
||||
ImagePullPolicy: v1.PullAlways,
|
||||
Command: []string{
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"/usr/bin/docker_packer $(APP_META) " + name,
|
||||
}, // Maybe it can be passed by Binary data from config map
|
||||
// Args: []string{"${APP_META}"}, // function source codes and name
|
||||
VolumeMounts: []v1.VolumeMount{
|
||||
v1.VolumeMount{
|
||||
Name: "dockersock",
|
||||
MountPath: "/var/run/docker.sock",
|
||||
},
|
||||
},
|
||||
Env: []v1.EnvVar{
|
||||
v1.EnvVar{
|
||||
Name: ConfigMap.AppMetaEnvName,
|
||||
ValueFrom: &v1.EnvVarSource{
|
||||
ConfigMapKeyRef: &v1.ConfigMapKeySelector{
|
||||
LocalObjectReference: v1.LocalObjectReference{Name: name},
|
||||
Key: ConfigMap.AppMetaEnvName,
|
||||
Optional: &valueInConfigMapHasToBeReady,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
EnvFrom: []v1.EnvFromSource{
|
||||
v1.EnvFromSource{
|
||||
ConfigMapRef: &v1.ConfigMapEnvSource{
|
||||
LocalObjectReference: v1.LocalObjectReference{
|
||||
Name: name,
|
||||
},
|
||||
Optional: &configMapHasToBeReady,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
volumes := []v1.Volume{
|
||||
v1.Volume{
|
||||
Name: "dockersock",
|
||||
VolumeSource: v1.VolumeSource{
|
||||
HostPath: &v1.HostPathVolumeSource{
|
||||
Path: "/var/run/docker.sock",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
deployment.Spec.Template.Spec.InitContainers = []apiv1.Container{initContainer}
|
||||
deployment.Spec.Template.Spec.Volumes = volumes
|
||||
return deployment
|
||||
}
|
||||
141
deploy/kubernetes/kubernetes.go
Normal file
141
deploy/kubernetes/kubernetes.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/metrue/fx/deploy"
|
||||
"github.com/metrue/fx/packer"
|
||||
"github.com/metrue/fx/types"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/tools/clientcmd"
|
||||
)
|
||||
|
||||
// K8S client
|
||||
type K8S struct {
|
||||
*kubernetes.Clientset
|
||||
}
|
||||
|
||||
const namespace = "default"
|
||||
|
||||
// Create a k8s cluster client
|
||||
func Create() (*K8S, error) {
|
||||
config, err := clientcmd.BuildConfigFromKubeconfigGetter("", clientcmd.NewDefaultClientConfigLoadingRules().Load)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &K8S{clientset}, nil
|
||||
}
|
||||
|
||||
// Deploy a image to be a service
|
||||
func (k *K8S) Deploy(
|
||||
ctx context.Context,
|
||||
fn types.Func,
|
||||
name string,
|
||||
ports []types.PortBinding,
|
||||
) error {
|
||||
// put source code of function docker project into k8s config map
|
||||
tree, err := packer.PackIntoK8SConfigMapFile(fn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data := map[string]string{}
|
||||
data[ConfigMap.AppMetaEnvName] = tree
|
||||
if _, err := k.CreateOrUpdateConfigMap(namespace, name, data); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
selector := map[string]string{
|
||||
"app": "fx-app-" + name,
|
||||
}
|
||||
|
||||
const replicas = int32(3)
|
||||
if _, err := k.GetDeployment(namespace, name); err != nil {
|
||||
// TODO enable passing replica from fx CLI
|
||||
if _, err := k.CreateDeploymentWithInitContainer(
|
||||
namespace,
|
||||
name,
|
||||
ports,
|
||||
replicas,
|
||||
selector,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := k.UpdateDeployment(
|
||||
namespace,
|
||||
name,
|
||||
name,
|
||||
ports,
|
||||
replicas,
|
||||
selector,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO fx should be able to know what's the target Kubernetes service platform
|
||||
// it's going to deploy to
|
||||
const isOnPublicCloud = true
|
||||
typ := "LoadBalancer"
|
||||
if !isOnPublicCloud {
|
||||
typ = "NodePort"
|
||||
}
|
||||
|
||||
if _, err := k.GetService(namespace, name); err != nil {
|
||||
if _, err := k.CreateService(
|
||||
namespace,
|
||||
name,
|
||||
typ,
|
||||
ports,
|
||||
selector,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := k.UpdateService(
|
||||
namespace,
|
||||
name,
|
||||
typ,
|
||||
ports,
|
||||
selector,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update a service
|
||||
func (k *K8S) Update(ctx context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Destroy a service
|
||||
func (k *K8S) Destroy(ctx context.Context, name string) error {
|
||||
if err := k.DeleteService(namespace, name); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.DeleteDeployment(namespace, name); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetStatus get status of a service
|
||||
func (k *K8S) GetStatus(ctx context.Context, name string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// List services
|
||||
func (k *K8S) List(ctx context.Context, name string) ([]types.Service, error) {
|
||||
return []types.Service{}, nil
|
||||
}
|
||||
|
||||
var (
|
||||
_ deploy.Deployer = &K8S{}
|
||||
)
|
||||
50
deploy/kubernetes/kubernetes_test.go
Normal file
50
deploy/kubernetes/kubernetes_test.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/metrue/fx/types"
|
||||
)
|
||||
|
||||
func TestK8SDeployer(t *testing.T) {
|
||||
name := "hellohello"
|
||||
bindings := []types.PortBinding{
|
||||
types.PortBinding{
|
||||
ServiceBindingPort: 80,
|
||||
ContainerExposePort: 3000,
|
||||
},
|
||||
types.PortBinding{
|
||||
ServiceBindingPort: 443,
|
||||
ContainerExposePort: 3000,
|
||||
},
|
||||
}
|
||||
kubeconfig := os.Getenv("KUBECONFIG")
|
||||
username := os.Getenv("DOCKER_USERNAME")
|
||||
password := os.Getenv("DOCKER_PASSWORD")
|
||||
if kubeconfig == "" || username == "" || password == "" {
|
||||
t.Skip("skip test since no KUBECONFIG, DOCKER_USERNAME and DOCKER_PASSWORD given in environment variable")
|
||||
}
|
||||
k8s, err := Create()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
fn := types.Func{
|
||||
Language: "node",
|
||||
Source: `
|
||||
module.exports = (ctx) => {
|
||||
ctx.body = 'hello world'
|
||||
}
|
||||
`,
|
||||
}
|
||||
ctx := context.Background()
|
||||
if err := k8s.Deploy(ctx, fn, name, bindings); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := k8s.Destroy(ctx, name); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
68
deploy/kubernetes/pod.go
Normal file
68
deploy/kubernetes/pod.go
Normal file
@@ -0,0 +1,68 @@
|
||||
package kubernetes
|
||||
|
||||
import (
|
||||
"github.com/metrue/fx/constants"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
)
|
||||
|
||||
// GetPod get a pod
|
||||
func (k *K8S) GetPod(namespace string, name string) (*v1.Pod, error) {
|
||||
pod, err := k.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pod, nil
|
||||
}
|
||||
|
||||
// ListPods list pods
|
||||
func (k *K8S) ListPods() (*v1.PodList, error) {
|
||||
pods, err := k.CoreV1().Pods("").List(metav1.ListOptions{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return pods, nil
|
||||
}
|
||||
|
||||
// CreatePod create a pod
|
||||
func (k *K8S) CreatePod(
|
||||
namespace string,
|
||||
name string,
|
||||
image string,
|
||||
labels map[string]string,
|
||||
) (*v1.Pod, error) {
|
||||
container := v1.Container{
|
||||
Name: "fx-placeholder-container-name",
|
||||
Image: image,
|
||||
Ports: []v1.ContainerPort{
|
||||
v1.ContainerPort{
|
||||
Name: "fx-container",
|
||||
HostPort: constants.FxContainerExposePort,
|
||||
ContainerPort: constants.FxContainerExposePort,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
pod := &v1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: name,
|
||||
Labels: labels,
|
||||
},
|
||||
Spec: v1.PodSpec{
|
||||
Containers: []v1.Container{container},
|
||||
},
|
||||
}
|
||||
|
||||
createdPod, err := k.CoreV1().Pods(namespace).Create(pod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return createdPod, nil
|
||||
}
|
||||
|
||||
// DeletePod delete a pod
|
||||
func (k *K8S) DeletePod(namespace string, name string) error {
|
||||
// TODO figure how to delete a pod in a elegant way
|
||||
options := metav1.DeleteOptions{}
|
||||
return k.CoreV1().Pods(namespace).Delete(name, &options)
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user