adjust the steps of karmadactl init and update examples
Signed-off-by: prodan <pengshihaoren@gmail.com>
This commit is contained in:
parent
abf08e476d
commit
e38e3cb2e0
1
go.mod
1
go.mod
|
|
@ -8,7 +8,6 @@ require (
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/google/uuid v1.1.2
|
github.com/google/uuid v1.1.2
|
||||||
github.com/kr/pretty v0.3.0
|
github.com/kr/pretty v0.3.0
|
||||||
github.com/lithammer/dedent v1.1.0
|
|
||||||
github.com/onsi/ginkgo v1.16.4
|
github.com/onsi/ginkgo v1.16.4
|
||||||
github.com/onsi/gomega v1.16.0
|
github.com/onsi/gomega v1.16.0
|
||||||
github.com/prometheus/client_golang v1.11.0
|
github.com/prometheus/client_golang v1.11.0
|
||||||
|
|
|
||||||
1
go.sum
1
go.sum
|
|
@ -508,7 +508,6 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||||
github.com/lithammer/dedent v1.1.0 h1:VNzHMVCBNG1j0fh3OrsFRkVUwStdDArbgBWoPAffktY=
|
|
||||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
|
|
|
||||||
|
|
@ -87,7 +87,7 @@ func NewCmdInit(cmdOut io.Writer) *cobra.Command {
|
||||||
// karmada
|
// karmada
|
||||||
crdURL := fmt.Sprintf("https://github.com/karmada-io/karmada/releases/download/%s/crds.tar.gz", version.Get().GitVersion)
|
crdURL := fmt.Sprintf("https://github.com/karmada-io/karmada/releases/download/%s/crds.tar.gz", version.Get().GitVersion)
|
||||||
flags.StringVar(&opts.CRDs, "crds", crdURL, "Karmada crds resource.(local file e.g. --crds /root/crds.tar.gz)")
|
flags.StringVar(&opts.CRDs, "crds", crdURL, "Karmada crds resource.(local file e.g. --crds /root/crds.tar.gz)")
|
||||||
flags.Int32VarP(&opts.KarmadaAPIServerNodePort, "port", "p", 5443, "Karmada apiserver service node port")
|
flags.Int32VarP(&opts.KarmadaAPIServerNodePort, "port", "p", 32443, "Karmada apiserver service node port")
|
||||||
flags.StringVarP(&opts.KarmadaDataPath, "karmada-data", "d", "/etc/karmada", "karmada data path. kubeconfig cert and crds files")
|
flags.StringVarP(&opts.KarmadaDataPath, "karmada-data", "d", "/etc/karmada", "karmada data path. kubeconfig cert and crds files")
|
||||||
flags.StringVarP(&opts.KarmadaAPIServerImage, "karmada-apiserver-image", "", "k8s.gcr.io/kube-apiserver:v1.21.7", "Kubernetes apiserver image")
|
flags.StringVarP(&opts.KarmadaAPIServerImage, "karmada-apiserver-image", "", "k8s.gcr.io/kube-apiserver:v1.21.7", "Kubernetes apiserver image")
|
||||||
flags.Int32VarP(&opts.KarmadaAPIServerReplicas, "karmada-apiserver-replicas", "", 1, "karmada apiserver replica set")
|
flags.Int32VarP(&opts.KarmadaAPIServerReplicas, "karmada-apiserver-replicas", "", 1, "karmada apiserver replica set")
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,10 @@ func (i *CommandInitOption) Complete() error {
|
||||||
}
|
}
|
||||||
i.KubeClientSet = clientSet
|
i.KubeClientSet = clientSet
|
||||||
|
|
||||||
|
if !i.isNodePortExist() {
|
||||||
|
return fmt.Errorf("nodePort %v already exist", i.KarmadaAPIServerNodePort)
|
||||||
|
}
|
||||||
|
|
||||||
if i.EtcdStorageMode == "hostPath" && i.EtcdNodeSelectorLabels == "" {
|
if i.EtcdStorageMode == "hostPath" && i.EtcdNodeSelectorLabels == "" {
|
||||||
if err := i.AddNodeSelectorLabels(); err != nil {
|
if err := i.AddNodeSelectorLabels(); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -274,7 +278,6 @@ func (i *CommandInitOption) initKarmadaAPIServer() error {
|
||||||
if err := i.CreateService(i.makeKarmadaAPIServerService()); err != nil {
|
if err := i.CreateService(i.makeKarmadaAPIServerService()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := i.KubeClientSet.AppsV1().Deployments(i.Namespace).Create(context.TODO(), i.makeKarmadaAPIServerDeployment(), metav1.CreateOptions{}); err != nil {
|
if _, err := i.KubeClientSet.AppsV1().Deployments(i.Namespace).Create(context.TODO(), i.makeKarmadaAPIServerDeployment(), metav1.CreateOptions{}); err != nil {
|
||||||
klog.Warning(err)
|
klog.Warning(err)
|
||||||
}
|
}
|
||||||
|
|
@ -386,7 +389,7 @@ func (i *CommandInitOption) RunInit(_ io.Writer) error {
|
||||||
}
|
}
|
||||||
klog.Info("Create karmada kubeconfig success.")
|
klog.Info("Create karmada kubeconfig success.")
|
||||||
|
|
||||||
// create ns
|
// create ns
|
||||||
if err := i.CreateNamespace(); err != nil {
|
if err := i.CreateNamespace(); err != nil {
|
||||||
return fmt.Errorf("create namespace %s failed: %v", i.Namespace, err)
|
return fmt.Errorf("create namespace %s failed: %v", i.Namespace, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,3 +222,28 @@ func (i *CommandInitOption) karmadaAggregatedAPIServerService() *corev1.Service
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (i CommandInitOption) isNodePortExist() bool {
|
||||||
|
svc, err := i.KubeClientSet.CoreV1().Services("").List(context.TODO(), metav1.ListOptions{})
|
||||||
|
if err != nil {
|
||||||
|
klog.Exit(err)
|
||||||
|
}
|
||||||
|
for _, v := range svc.Items {
|
||||||
|
if v.Spec.Type != corev1.ServiceTypeNodePort {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !nodePort(i.KarmadaAPIServerNodePort, v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodePort(nodePort int32, service corev1.Service) bool {
|
||||||
|
for _, v := range service.Spec.Ports {
|
||||||
|
if v.NodePort == nodePort {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,17 @@ package utils
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/lithammer/dedent"
|
|
||||||
|
|
||||||
"k8s.io/klog/v2"
|
"k8s.io/klog/v2"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
// https://github.com/karmada-io/karmada/blob/master/artifacts/agent
|
||||||
karmadaAgent = `---
|
karmadaAgent = `---
|
||||||
|
apiVersion: v1
|
||||||
|
kind: Namespace
|
||||||
|
metadata:
|
||||||
|
name: karmada-system
|
||||||
|
---
|
||||||
apiVersion: rbac.authorization.k8s.io/v1
|
apiVersion: rbac.authorization.k8s.io/v1
|
||||||
kind: ClusterRole
|
kind: ClusterRole
|
||||||
metadata:
|
metadata:
|
||||||
|
|
@ -17,7 +21,7 @@ metadata:
|
||||||
rules:
|
rules:
|
||||||
- apiGroups: ['*']
|
- apiGroups: ['*']
|
||||||
resources: ['*']
|
resources: ['*']
|
||||||
verbs: ["get", "watch", "list", "create", "update", "delete"]
|
verbs: ['*']
|
||||||
- nonResourceURLs: ['*']
|
- nonResourceURLs: ['*']
|
||||||
verbs: ["get"]
|
verbs: ["get"]
|
||||||
---
|
---
|
||||||
|
|
@ -143,51 +147,35 @@ func GenExamples(path string) {
|
||||||
klog.Warning(err)
|
klog.Warning(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println(dedent.Dedent(`┌──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
|
fmt.Printf(`
|
||||||
| Push mode |
|
Register Kubernetes cluster to Karmada control plane.
|
||||||
| |
|
|
||||||
| Step 1: Member kubernetes join karmada control plane |
|
Register cluster with 'Push' mode
|
||||||
| |
|
|
||||||
| (In karmada)~# cat ~/.kube/config | grep current-context | sed 's/: /\n/g'| sed '1d' #MEMBER_CLUSTER_NAME |
|
Step 1: Use kubectl-karmada join to register the cluster to Karmada control panel. --cluster-kubeconfig is members kubeconfig.
|
||||||
| (In karmada)~# kubectl-karmada --kubeconfig /etc/karmada/karmada-apiserver.config join ${MEMBER_CLUSTER_NAME} --cluster-kubeconfig=$HOME/.kube/config |
|
(In karmada)~# MEMBER_CLUSTER_NAME=%scat ~/.kube/config | grep current-context | sed 's/: /\n/g'| sed '1d'%s
|
||||||
| |
|
(In karmada)~# kubectl-karmada --kubeconfig %s/karmada-apiserver.config join ${MEMBER_CLUSTER_NAME} --cluster-kubeconfig=$HOME/.kube/config
|
||||||
| Step 2: Create member kubernetes kubeconfig secret |
|
|
||||||
| |
|
Step 2: Show members of karmada
|
||||||
| (In member kubernetes)~# kubectl create ns karmada-system |
|
(In karmada)~# kubectl --kubeconfig %s/karmada-apiserver.config get clusters
|
||||||
| (In member kubernetes)~# kubectl create secret generic ${MEMBER_CLUSTER_NAME}-kubeconfig --from-file=${MEMBER_CLUSTER_NAME}-kubeconfig=$HOME/.kube/config -n karmada-system |
|
|
||||||
| |
|
Register cluster with 'Pull' mode
|
||||||
| Step 3: Create karmada scheduler estimator |
|
|
||||||
| |
|
Step 1: Send karmada kubeconfig and karmada-agent.yaml to member kubernetes
|
||||||
| (In member kubernetes)~# sed -i "s/{{member_cluster_name}}/${MEMBER_CLUSTER_NAME}/g" /etc/karmada/karmada-scheduler-estimator.yaml |
|
(In karmada)~# scp %s/karmada-apiserver.config %s/karmada-agent.yaml {member kubernetes}:~
|
||||||
| (In member kubernetes)~# kubectl create -f /etc/karmada/karmada-scheduler-estimator.yaml |
|
|
||||||
| |
|
Step 2: Create karmada kubeconfig secret
|
||||||
| Step 4: Show members of karmada |
|
Notice:
|
||||||
| |
|
Cross-network, need to change the config server address.
|
||||||
| (In karmada)~# kubectl --kubeconfig /etc/karmada/karmada-apiserver.config get clusters |
|
(In member kubernetes)~# kubectl create ns karmada-system
|
||||||
| |
|
(In member kubernetes)~# kubectl create secret generic karmada-kubeconfig --from-file=karmada-kubeconfig=/root/karmada-apiserver.config -n karmada-system
|
||||||
├── —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— —— ┤
|
|
||||||
| Pull mode |
|
Step 3: Create karmada agent
|
||||||
| |
|
(In member kubernetes)~# MEMBER_CLUSTER_NAME="demo"
|
||||||
| Step 1: Send karmada kubeconfig and karmada-agent.yaml to member kubernetes |
|
(In member kubernetes)~# sed -i "s/{member_cluster_name}/${MEMBER_CLUSTER_NAME}/g" karmada-agent.yaml
|
||||||
| |
|
(In member kubernetes)~# kubectl create -f karmada-agent.yaml
|
||||||
| (In karmada)~# scp /etc/karmada/karmada-apiserver.config /etc/karmada/karmada-agent.yaml {member kubernetes}:~ |
|
|
||||||
| |
|
Step 4: Show members of karmada
|
||||||
| Step 2: Create karmada kubeconfig secret |
|
(In karmada)~# kubectl --kubeconfig %s/karmada-apiserver.config get clusters
|
||||||
| Notice: |
|
`, "`", "`", path, path, path, path, path)
|
||||||
| Cross-network, need to change the config server address. |
|
|
||||||
| |
|
|
||||||
| (In member kubernetes)~# kubectl create ns karmada-system |
|
|
||||||
| (In member kubernetes)~# kubectl create secret generic karmada-kubeconfig --from-file=karmada-kubeconfig=/root/karmada-apiserver.config -n karmada-system |
|
|
||||||
| |
|
|
||||||
| Step 3: Create karmada agent |
|
|
||||||
| |
|
|
||||||
| (In member kubernetes)~# MEMBER_CLUSTER_NAME="demo" |
|
|
||||||
| (In member kubernetes)~# sed -i "s/{member_cluster_name}/${MEMBER_CLUSTER_NAME}/g" karmada-agent.yaml |
|
|
||||||
| (In member kubernetes)~# kubectl create -f karmada-agent.yaml |
|
|
||||||
| |
|
|
||||||
| Step 4: Show members of karmada |
|
|
||||||
| |
|
|
||||||
| (In karmada)~# kubectl --kubeconfig /etc/karmada/karmada-apiserver.config get clusters |
|
|
||||||
└──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
`))
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ package utils
|
||||||
import "testing"
|
import "testing"
|
||||||
|
|
||||||
func TestGenExamples(t *testing.T) {
|
func TestGenExamples(t *testing.T) {
|
||||||
GenExamples("/tmp/test")
|
GenExamples("/tmp")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
language: go
|
|
||||||
|
|
||||||
go:
|
|
||||||
- "1.6"
|
|
||||||
- "1.7"
|
|
||||||
- "1.8"
|
|
||||||
- "1.9"
|
|
||||||
- "1.10"
|
|
||||||
- "1.11"
|
|
||||||
|
|
||||||
sudo: false
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2018 Peter Lithammer
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
|
||||||
in the Software without restriction, including without limitation the rights
|
|
||||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
||||||
copies of the Software, and to permit persons to whom the Software is
|
|
||||||
furnished to do so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in
|
|
||||||
all copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
||||||
THE SOFTWARE.
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
# Dedent
|
|
||||||
|
|
||||||
[](https://travis-ci.org/lithammer/dedent)
|
|
||||||
[](https://godoc.org/github.com/lithammer/dedent)
|
|
||||||
|
|
||||||
Removes common leading whitespace from multiline strings. Inspired by [`textwrap.dedent`](https://docs.python.org/3/library/textwrap.html#textwrap.dedent) in Python.
|
|
||||||
|
|
||||||
## Usage / example
|
|
||||||
|
|
||||||
Imagine the following snippet that prints a multiline string. You want the indentation to both look nice in the code as well as in the actual output.
|
|
||||||
|
|
||||||
```go
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/lithammer/dedent"
|
|
||||||
)
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
s := `
|
|
||||||
Lorem ipsum dolor sit amet,
|
|
||||||
consectetur adipiscing elit.
|
|
||||||
Curabitur justo tellus, facilisis nec efficitur dictum,
|
|
||||||
fermentum vitae ligula. Sed eu convallis sapien.`
|
|
||||||
fmt.Println(Dedent(s))
|
|
||||||
fmt.Println("-------------")
|
|
||||||
fmt.Println(s)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
To illustrate the difference, here's the output:
|
|
||||||
|
|
||||||
|
|
||||||
```bash
|
|
||||||
$ go run main.go
|
|
||||||
Lorem ipsum dolor sit amet,
|
|
||||||
consectetur adipiscing elit.
|
|
||||||
Curabitur justo tellus, facilisis nec efficitur dictum,
|
|
||||||
fermentum vitae ligula. Sed eu convallis sapien.
|
|
||||||
-------------
|
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet,
|
|
||||||
consectetur adipiscing elit.
|
|
||||||
Curabitur justo tellus, facilisis nec efficitur dictum,
|
|
||||||
fermentum vitae ligula. Sed eu convallis sapien.
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
package dedent
|
|
||||||
|
|
||||||
import (
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
whitespaceOnly = regexp.MustCompile("(?m)^[ \t]+$")
|
|
||||||
leadingWhitespace = regexp.MustCompile("(?m)(^[ \t]*)(?:[^ \t\n])")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Dedent removes any common leading whitespace from every line in text.
|
|
||||||
//
|
|
||||||
// This can be used to make multiline strings to line up with the left edge of
|
|
||||||
// the display, while still presenting them in the source code in indented
|
|
||||||
// form.
|
|
||||||
func Dedent(text string) string {
|
|
||||||
var margin string
|
|
||||||
|
|
||||||
text = whitespaceOnly.ReplaceAllString(text, "")
|
|
||||||
indents := leadingWhitespace.FindAllStringSubmatch(text, -1)
|
|
||||||
|
|
||||||
// Look for the longest leading string of spaces and tabs common to all
|
|
||||||
// lines.
|
|
||||||
for i, indent := range indents {
|
|
||||||
if i == 0 {
|
|
||||||
margin = indent[1]
|
|
||||||
} else if strings.HasPrefix(indent[1], margin) {
|
|
||||||
// Current line more deeply indented than previous winner:
|
|
||||||
// no change (previous winner is still on top).
|
|
||||||
continue
|
|
||||||
} else if strings.HasPrefix(margin, indent[1]) {
|
|
||||||
// Current line consistent with and no deeper than previous winner:
|
|
||||||
// it's the new winner.
|
|
||||||
margin = indent[1]
|
|
||||||
} else {
|
|
||||||
// Current line and previous winner have no common whitespace:
|
|
||||||
// there is no margin.
|
|
||||||
margin = ""
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if margin != "" {
|
|
||||||
text = regexp.MustCompile("(?m)^"+margin).ReplaceAllString(text, "")
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
module github.com/lithammer/dedent
|
|
||||||
|
|
@ -149,9 +149,6 @@ github.com/kr/pretty
|
||||||
github.com/kr/text
|
github.com/kr/text
|
||||||
# github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
|
# github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de
|
||||||
github.com/liggitt/tabwriter
|
github.com/liggitt/tabwriter
|
||||||
# github.com/lithammer/dedent v1.1.0
|
|
||||||
## explicit
|
|
||||||
github.com/lithammer/dedent
|
|
||||||
# github.com/mailru/easyjson v0.7.6
|
# github.com/mailru/easyjson v0.7.6
|
||||||
github.com/mailru/easyjson/buffer
|
github.com/mailru/easyjson/buffer
|
||||||
github.com/mailru/easyjson/jlexer
|
github.com/mailru/easyjson/jlexer
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue