diff --git a/tools/imctl/cmd/imctl/imctl.go b/tools/imctl/cmd/imctl/imctl.go index fea2023a9..d72fee927 100644 --- a/tools/imctl/cmd/imctl/imctl.go +++ b/tools/imctl/cmd/imctl/imctl.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -// iamctl is the command line tool for iam platform. +// iactl is the command line tool for openim platform. package main import ( diff --git a/tools/imctl/internal/imctl/cmd/color/color.go b/tools/imctl/internal/imctl/cmd/color/color.go index 6a33da52c..bbdd439cc 100644 --- a/tools/imctl/internal/imctl/cmd/color/color.go +++ b/tools/imctl/internal/imctl/cmd/color/color.go @@ -21,12 +21,12 @@ import ( "github.com/fatih/color" "github.com/olekukonko/tablewriter" - "github.com/openim-sigs/component-base/pkg/util/stringutil" + "github.com/openim-sigs/component-base/util/stringutil" "github.com/spf13/cobra" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" + "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" ) // ColorOptions is an options struct to support color subcommands. diff --git a/tools/imctl/internal/imctl/cmd/completion/completion.go b/tools/imctl/internal/imctl/cmd/completion/completion.go index c9605a22d..f0bfd5bd9 100644 --- a/tools/imctl/internal/imctl/cmd/completion/completion.go +++ b/tools/imctl/internal/imctl/cmd/completion/completion.go @@ -21,8 +21,8 @@ import ( "github.com/spf13/cobra" + "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util/templates" cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" ) const defaultBoilerPlate = ` @@ -45,11 +45,11 @@ var ( completionLong = templates.LongDesc(` Output shell completion code for the specified shell (bash or zsh). The shell code must be evaluated to provide interactive - completion of iamctl commands. This can be done by sourcing it from + completion of imctl commands. This can be done by sourcing it from the .bash_profile. Detailed instructions on how to do this are available here: - http://github.com/marmotedu/iam/docs/installation/iamctl.md#enabling-shell-autocompletion + http://github.com/marmotedu/iam/docs/installation/imctl.md#enabling-shell-autocompletion Note for zsh users: [1] zsh completions are only supported in versions of zsh >= 5.2`) @@ -59,28 +59,28 @@ var ( brew install bash-completion ## or, if running Bash 4.1+ brew install bash-completion@2 - ## If iamctl is installed via homebrew, this should start working immediately. + ## If imctl is installed via homebrew, this should start working immediately. ## If you've installed via other means, you may need add the completion to your completion directory - iamctl completion bash > $(brew --prefix)/etc/bash_completion.d/iamctl + imctl completion bash > $(brew --prefix)/etc/bash_completion.d/imctl # Installing bash completion on Linux ## If bash-completion is not installed on Linux, please install the 'bash-completion' package ## via your distribution's package manager. - ## Load the iamctl completion code for bash into the current shell - source <(iamctl completion bash) + ## Load the imctl completion code for bash into the current shell + source <(imctl completion bash) ## Write bash completion code to a file and source if from .bash_profile - iamctl completion bash > ~/.iam/completion.bash.inc + imctl completion bash > ~/.iam/completion.bash.inc printf " # IAM shell completion source '$HOME/.iam/completion.bash.inc' " >> $HOME/.bash_profile source $HOME/.bash_profile - # Load the iamctl completion code for zsh[1] into the current shell - source <(iamctl completion zsh) - # Set the iamctl completion code for zsh[1] to autoload on startup - iamctl completion zsh > "${fpath[1]}/_iamctl"`) + # Load the imctl completion code for zsh[1] into the current shell + source <(imctl completion zsh) + # Set the imctl completion code for zsh[1] to autoload on startup + imctl completion zsh > "${fpath[1]}/_imctl"`) ) var completionShells = map[string]func(out io.Writer, boilerPlate string, cmd *cobra.Command) error{ @@ -129,7 +129,7 @@ func RunCompletion(out io.Writer, boilerPlate string, cmd *cobra.Command, args [ return run(out, boilerPlate, cmd.Parent()) } -func runCompletionBash(out io.Writer, boilerPlate string, iamctl *cobra.Command) error { +func runCompletionBash(out io.Writer, boilerPlate string, imctl *cobra.Command) error { if len(boilerPlate) == 0 { boilerPlate = defaultBoilerPlate } @@ -138,11 +138,11 @@ func runCompletionBash(out io.Writer, boilerPlate string, iamctl *cobra.Command) return err } - return iamctl.GenBashCompletion(out) + return imctl.GenBashCompletion(out) } -func runCompletionZsh(out io.Writer, boilerPlate string, iamctl *cobra.Command) error { - zshHead := "#compdef iamctl\n" +func runCompletionZsh(out io.Writer, boilerPlate string, imctl *cobra.Command) error { + zshHead := "#compdef imctl\n" if _, err := out.Write([]byte(zshHead)); err != nil { return err @@ -157,7 +157,7 @@ func runCompletionZsh(out io.Writer, boilerPlate string, iamctl *cobra.Command) } zshInitialization := ` -__iamctl_bash_source() { +__imctl_bash_source() { alias shopt=':' emulate -L sh setopt kshglob noshglob braceexpand @@ -165,7 +165,7 @@ __iamctl_bash_source() { source "$@" } -__iamctl_type() { +__imctl_type() { # -t is not supported by zsh if [ "$1" == "-t" ]; then shift @@ -174,7 +174,7 @@ __iamctl_type() { # "compopt +-o nospace" is used in the code to toggle trailing # spaces. We don't support that, but leave trailing spaces on # all the time - if [ "$1" = "__iamctl_compopt" ]; then + if [ "$1" = "__imctl_compopt" ]; then echo builtin return 0 fi @@ -182,7 +182,7 @@ __iamctl_type() { type "$@" } -__iamctl_compgen() { +__imctl_compgen() { local completions w completions=( $(compgen "$@") ) || return $? @@ -201,11 +201,11 @@ __iamctl_compgen() { done } -__iamctl_compopt() { +__imctl_compopt() { true # don't do anything. Not supported by bashcompinit in zsh } -__iamctl_ltrim_colon_completions() +__imctl_ltrim_colon_completions() { if [[ "$1" == *:* && "$COMP_WORDBREAKS" == *:* ]]; then # Remove colon-word prefix from COMPREPLY items @@ -217,14 +217,14 @@ __iamctl_ltrim_colon_completions() fi } -__iamctl_get_comp_words_by_ref() { +__imctl_get_comp_words_by_ref() { cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[${COMP_CWORD}-1]}" words=("${COMP_WORDS[@]}") cword=("${COMP_CWORD[@]}") } -__iamctl_filedir() { +__imctl_filedir() { # Don't need to do anything here. # Otherwise we will get trailing space without "compopt -o nospace" true @@ -240,20 +240,20 @@ if sed --help 2>&1 | grep -q 'GNU\|BusyBox'; then RWORD='\>' fi -__iamctl_convert_bash_to_zsh() { +__imctl_convert_bash_to_zsh() { sed \ -e 's/declare -F/whence -w/' \ -e 's/_get_comp_words_by_ref "\$@"/_get_comp_words_by_ref "\$*"/' \ -e 's/local \([a-zA-Z0-9_]*\)=/local \1; \1=/' \ -e 's/flags+=("\(--.*\)=")/flags+=("\1"); two_word_flags+=("\1")/' \ -e 's/must_have_one_flag+=("\(--.*\)=")/must_have_one_flag+=("\1")/' \ - -e "s/${LWORD}_filedir${RWORD}/__iamctl_filedir/g" \ - -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__iamctl_get_comp_words_by_ref/g" \ - -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__iamctl_ltrim_colon_completions/g" \ - -e "s/${LWORD}compgen${RWORD}/__iamctl_compgen/g" \ - -e "s/${LWORD}compopt${RWORD}/__iamctl_compopt/g" \ + -e "s/${LWORD}_filedir${RWORD}/__imctl_filedir/g" \ + -e "s/${LWORD}_get_comp_words_by_ref${RWORD}/__imctl_get_comp_words_by_ref/g" \ + -e "s/${LWORD}__ltrim_colon_completions${RWORD}/__imctl_ltrim_colon_completions/g" \ + -e "s/${LWORD}compgen${RWORD}/__imctl_compgen/g" \ + -e "s/${LWORD}compopt${RWORD}/__imctl_compopt/g" \ -e "s/${LWORD}declare${RWORD}/builtin declare/g" \ - -e "s/\\\$(type${RWORD}/\$(__iamctl_type/g" \ + -e "s/\\\$(type${RWORD}/\$(__imctl_type/g" \ <<'BASH_COMPLETION_EOF' ` if _, err := out.Write([]byte(zshInitialization)); err != nil { @@ -261,7 +261,7 @@ __iamctl_convert_bash_to_zsh() { } buf := new(bytes.Buffer) - if err := iamctl.GenBashCompletion(buf); err != nil { + if err := imctl.GenBashCompletion(buf); err != nil { return err } @@ -273,7 +273,7 @@ __iamctl_convert_bash_to_zsh() { BASH_COMPLETION_EOF } -__iamctl_bash_source <(__iamctl_convert_bash_to_zsh) +__imctl_bash_source <(__imctl_convert_bash_to_zsh) ` if _, err := out.Write([]byte(zshTail)); err != nil { return err diff --git a/tools/imctl/internal/imctl/cmd/info/info.go b/tools/imctl/internal/imctl/cmd/info/info.go index 5baa7e3eb..928d12bbb 100644 --- a/tools/imctl/internal/imctl/cmd/info/info.go +++ b/tools/imctl/internal/imctl/cmd/info/info.go @@ -21,12 +21,12 @@ import ( "strconv" hoststat "github.com/likexian/host-stat-go" - "github.com/openim-sigs/component-base/pkg/util/iputil" + "github.com/openim-sigs/component-base/util/iputil" "github.com/spf13/cobra" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" + "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" ) // Info defines the host information struct. @@ -46,7 +46,7 @@ type InfoOptions struct { var infoExample = templates.Examples(` # Print the host information - iamctl info`) + imctl info`) // NewInfoOptions returns an initialized InfoOptions instance. func NewInfoOptions(ioStreams genericclioptions.IOStreams) *InfoOptions { diff --git a/tools/imctl/internal/imctl/cmd/jwt/args.go b/tools/imctl/internal/imctl/cmd/jwt/args.go deleted file mode 100644 index 58a22a4f0..000000000 --- a/tools/imctl/internal/imctl/cmd/jwt/args.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jwt - -import ( - "fmt" - "strings" - - "github.com/openim-sigs/component-base/pkg/json" -) - -// ArgList defines a new pflag Value. -type ArgList map[string]string - -// String return value of ArgList in string format. -func (l ArgList) String() string { - data, _ := json.Marshal(l) - - return string(data) -} - -// Set sets the value of ArgList. -func (l ArgList) Set(arg string) error { - parts := strings.SplitN(arg, "=", 2) - if len(parts) != 2 { - return fmt.Errorf("invalid argument '%v'. Must use format 'key=value'. %v", arg, parts) - } - l[parts[0]] = parts[1] - - return nil -} - -// Type returns the type name of ArgList. -func (l ArgList) Type() string { - return "map" -} diff --git a/tools/imctl/internal/imctl/cmd/jwt/jwt.go b/tools/imctl/internal/imctl/cmd/jwt/jwt.go deleted file mode 100644 index 2304be92f..000000000 --- a/tools/imctl/internal/imctl/cmd/jwt/jwt.go +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package jwt can be used to sign/show/verify jwt token with given secretID and secretKey. -package jwt - -import ( - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -var jwtLong = templates.LongDesc(` - JWT command. - - This commands is used to sigin/show/verify jwt token.`) - -// NewCmdJWT returns new initialized instance of 'jwt' sub command. -func NewCmdJWT(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "jwt SUBCOMMAND", - DisableFlagsInUseLine: true, - Short: "JWT command-line tool", - Long: jwtLong, - Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), - } - - // add subcommands - cmd.AddCommand(NewCmdSign(f, ioStreams)) - cmd.AddCommand(NewCmdShow(f, ioStreams)) - cmd.AddCommand(NewCmdVerify(f, ioStreams)) - - return cmd -} diff --git a/tools/imctl/internal/imctl/cmd/jwt/jwt_show.go b/tools/imctl/internal/imctl/cmd/jwt/jwt_show.go deleted file mode 100644 index d03e911fd..000000000 --- a/tools/imctl/internal/imctl/cmd/jwt/jwt_show.go +++ /dev/null @@ -1,144 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jwt - -import ( - "fmt" - "regexp" - - "github.com/golang-jwt/jwt/v4" - "github.com/openim-sigs/component-base/pkg/json" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - showUsageStr = "show TOKEN" -) - -// ShowOptions is an options struct to support show subcommands. -type ShowOptions struct { - Compact bool - - genericclioptions.IOStreams -} - -var ( - showExample = templates.Examples(` - # Show header and Claims for a JWT token - iamctl jwt show XXX.XXX.XXX`) - - showUsageErrStr = fmt.Sprintf("expected '%s'.\nTOKEN is required arguments for the show command", showUsageStr) -) - -// NewShowOptions returns an initialized ShowOptions instance. -func NewShowOptions(ioStreams genericclioptions.IOStreams) *ShowOptions { - return &ShowOptions{ - Compact: false, - - IOStreams: ioStreams, - } -} - -// NewCmdShow returns new initialized instance of show sub command. -func NewCmdShow(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewShowOptions(ioStreams) - - cmd := &cobra.Command{ - Use: showUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Show header and claims for a JWT token", - Long: "Show header and claims for a JWT token", - TraverseChildren: true, - Example: showExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) != 1 { - return cmdutil.UsageErrorf(cmd, showUsageErrStr) - } - - return nil - }, - } - - // mark flag as deprecated - cmd.Flags().BoolVar(&o.Compact, "compact", o.Compact, "output compact JSON.") - - return cmd -} - -// Complete completes all the required options. -func (o *ShowOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *ShowOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a show subcommand using the specified options. -func (o *ShowOptions) Run(args []string) error { - // get the token - tokenData := []byte(args[0]) - - // trim possible whitespace from token - tokenData = regexp.MustCompile(`\s*$`).ReplaceAll(tokenData, []byte{}) - - token, err := jwt.Parse(string(tokenData), nil) - if token == nil { - return fmt.Errorf("malformed token: %w", err) - } - - // Print the token details - fmt.Println("Header:") - if err := printJSON(o.Compact, token.Header); err != nil { - return fmt.Errorf("failed to output header: %w", err) - } - - fmt.Println("Claims:") - if err := printJSON(o.Compact, token.Claims); err != nil { - return fmt.Errorf("failed to output claims: %w", err) - } - - return nil -} - -// printJSON print a json object in accordance with the prophecy (or the command line options). -func printJSON(compact bool, j interface{}) error { - var out []byte - var err error - - if !compact { - out, err = json.MarshalIndent(j, "", " ") - } else { - out, err = json.Marshal(j) - } - - if err == nil { - fmt.Println(string(out)) - } - - return err -} diff --git a/tools/imctl/internal/imctl/cmd/jwt/jwt_sign.go b/tools/imctl/internal/imctl/cmd/jwt/jwt_sign.go deleted file mode 100644 index 85b0f724f..000000000 --- a/tools/imctl/internal/imctl/cmd/jwt/jwt_sign.go +++ /dev/null @@ -1,186 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jwt - -import ( - "errors" - "fmt" - "time" - - "github.com/golang-jwt/jwt/v4" - "github.com/spf13/cobra" - - "github.com/marmotedu/iam/internal/pkg/middleware/auth" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - signUsageStr = "sign SECRETID SECRETKEY" -) - -// ErrSigningMethod defines invalid signing method error. -var ErrSigningMethod = errors.New("invalid signing method") - -// SignOptions is an options struct to support sign subcommands. -type SignOptions struct { - Timeout time.Duration - NotBefore time.Duration - Algorithm string - Audience string - Issuer string - Claims ArgList - Head ArgList - - genericclioptions.IOStreams -} - -var ( - signExample = templates.Examples(` - # Sign a token with secretID and secretKey - iamctl sign tgydj8d9EQSnFqKf iBdEdFNBLN1nR3fV - - # Sign a token with expires and sign method - iamctl sign tgydj8d9EQSnFqKf iBdEdFNBLN1nR3fV --timeout=2h --algorithm=HS256`) - - signUsageErrStr = fmt.Sprintf( - "expected '%s'.\nSECRETID and SECRETKEY are required arguments for the sign command", - signUsageStr, - ) -) - -// NewSignOptions returns an initialized SignOptions instance. -func NewSignOptions(ioStreams genericclioptions.IOStreams) *SignOptions { - return &SignOptions{ - Timeout: 2 * time.Hour, - Algorithm: "HS256", - Audience: auth.AuthzAudience, - Issuer: "iamctl", - Claims: make(ArgList), - Head: make(ArgList), - - IOStreams: ioStreams, - } -} - -// NewCmdSign returns new initialized instance of sign sub command. -func NewCmdSign(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewSignOptions(ioStreams) - - cmd := &cobra.Command{ - Use: signUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Sign a jwt token with given secretID and secretKey", - Long: "Sign a jwt token with given secretID and secretKey", - TraverseChildren: true, - Example: signExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) != 2 { - return cmdutil.UsageErrorf(cmd, signUsageErrStr) - } - - return nil - }, - } - - // mark flag as deprecated - cmd.Flags().DurationVar(&o.Timeout, "timeout", o.Timeout, "JWT token expires time.") - cmd.Flags().DurationVar( - &o.NotBefore, - "not-before", - o.NotBefore, - "Identifies the time before which the JWT MUST NOT be accepted for processing.", - ) - cmd.Flags().StringVar( - &o.Algorithm, - "algorithm", - o.Algorithm, - "Signing algorithm - possible values are HS256, HS384, HS512.", - ) - cmd.Flags().StringVar( - &o.Audience, - "audience", - o.Audience, - "Identifies the recipients that the JWT is intended for.", - ) - cmd.Flags().StringVar(&o.Issuer, "issuer", o.Issuer, "Identifies the principal that issued the JWT.") - cmd.Flags().Var(&o.Claims, "claim", "Add additional claims. may be used more than once.") - cmd.Flags().Var(&o.Head, "header", "Add additional header params. may be used more than once.") - - return cmd -} - -// Complete completes all the required options. -func (o *SignOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *SignOptions) Validate(cmd *cobra.Command, args []string) error { - switch o.Algorithm { - case "HS256", "HS384", "HS512": - default: - return ErrSigningMethod - } - - return nil -} - -// Run executes a sign subcommand using the specified options. -func (o *SignOptions) Run(args []string) error { - claims := jwt.MapClaims{ - "exp": time.Now().Add(o.Timeout).Unix(), - "iat": time.Now().Unix(), - "nbf": time.Now().Add(o.NotBefore).Unix(), - "aud": o.Audience, - "iss": o.Issuer, - } - - // add command line claims - if len(o.Claims) > 0 { - for k, v := range o.Claims { - claims[k] = v - } - } - - // create a new token - token := jwt.NewWithClaims(jwt.GetSigningMethod(o.Algorithm), claims) - - // add command line headers - if len(o.Head) > 0 { - for k, v := range o.Head { - token.Header[k] = v - } - } - token.Header["kid"] = args[0] - - tokenString, err := token.SignedString([]byte(args[1])) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, tokenString+"\n") - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/jwt/jwt_verify.go b/tools/imctl/internal/imctl/cmd/jwt/jwt_verify.go deleted file mode 100644 index d685bb4a0..000000000 --- a/tools/imctl/internal/imctl/cmd/jwt/jwt_verify.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package jwt - -import ( - "fmt" - "regexp" - - "github.com/golang-jwt/jwt/v4" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - veirfyUsageStr = "veirfy SECRETKEY TOKEN" -) - -// VerifyOptions is an options struct to support verify subcommands. -type VerifyOptions struct { - Compact bool - Debug bool - - genericclioptions.IOStreams -} - -var ( - verifyExample = templates.Examples(` - # Verify a JWT token - iamctl jwt verify XXX xxxxx.yyyyy.zzzzz`) - - verifyUsageErrStr = fmt.Sprintf( - "expected '%s'.\nSECRETKEY and TOKEN are required arguments for the subcmd1 command", - veirfyUsageStr, - ) -) - -// NewVerifyOptions returns an initialized VerifyOptions instance. -func NewVerifyOptions(ioStreams genericclioptions.IOStreams) *VerifyOptions { - return &VerifyOptions{ - Compact: false, - Debug: false, - - IOStreams: ioStreams, - } -} - -// NewCmdVerify returns new initialized instance of verify sub command. -func NewCmdVerify(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewVerifyOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "verify", - DisableFlagsInUseLine: true, - Aliases: []string{"sub2"}, - Short: "Verify a JWT token", - Long: "Verify a JWT token", - TraverseChildren: true, - Example: verifyExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - Args: func(cmd *cobra.Command, args []string) error { - if len(args) != 2 { - return cmdutil.UsageErrorf(cmd, verifyUsageErrStr) - } - - return nil - }, - } - - // mark flag as deprecated - cmd.Flags().BoolVar(&o.Compact, "compact", o.Compact, "Output compact JSON.") - cmd.Flags().BoolVar(&o.Debug, "debug", o.Debug, "Print out all kinds of debug data.") - - return cmd -} - -// Complete completes all the required options. -func (o *VerifyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *VerifyOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a verify subcommand using the specified options. -func (o *VerifyOptions) Run(args []string) error { - // get the token - tokenData := []byte(args[1]) - - // trim possible whitespace from token - tokenData = regexp.MustCompile(`\s*$`).ReplaceAll(tokenData, []byte{}) - - // Parse the token. Load the key from command line option - token, err := jwt.Parse(string(tokenData), func(t *jwt.Token) (interface{}, error) { - return []byte(args[0]), nil - }) - - // Print some debug data - if o.Debug && token != nil { - fmt.Println("Header:") - if pErr := printJSON(o.Compact, token.Header); pErr != nil { - return fmt.Errorf("failed to output header: %w", pErr) - } - - fmt.Println("Claims:") - if pErr := printJSON(o.Compact, token.Claims); pErr != nil { - return fmt.Errorf("failed to output claims: %w", pErr) - } - } - - // Print an error if we can't parse for some reason - if err != nil { - return fmt.Errorf("couldn't parse token: %w", err) - } - - // Is token invalid? - if !token.Valid { - return fmt.Errorf("token is invalid") - } - - if !o.Debug { - // Print the token details - if err := printJSON(o.Compact, token.Claims); err != nil { - return fmt.Errorf("failed to output claims: %w", err) - } - } - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/new/new.go b/tools/imctl/internal/imctl/cmd/new/new.go index 24d6dfca9..6ac0667fc 100644 --- a/tools/imctl/internal/imctl/cmd/new/new.go +++ b/tools/imctl/internal/imctl/cmd/new/new.go @@ -28,9 +28,9 @@ import ( "golang.org/x/text/cases" "golang.org/x/text/language" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util" ) const ( @@ -45,16 +45,16 @@ This can improve your R&D efficiency.`) newExample = templates.Examples(` # Create a default 'test' command file without a description - iamctl new test + imctl new test # Create a default 'test' command file in /tmp/ - iamctl new test -d /tmp/ + imctl new test -d /tmp/ # Create a default 'test' command file with a description - iamctl new test "This is a test command" + imctl new test "This is a test command" # Create command 'test' with two subcommands - iamctl new -g test "This is a test command with two subcommands"`) + imctl new -g test "This is a test command with two subcommands"`) newUsageErrStr = fmt.Sprintf( "expected '%s'.\nat least CMD_NAME is a required argument for the new command", @@ -68,7 +68,7 @@ import ( "github.com/spf13/cobra" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" ) @@ -103,7 +103,7 @@ to quickly create a Cobra application.{{.Dot}}) {{.CommandName}}Example = templates.Examples({{.Dot}} # Print all option values for {{.CommandName}} - iamctl {{.CommandName}} marmotedu marmotedupass{{.Dot}}) + imctl {{.CommandName}} marmotedu marmotedupass{{.Dot}}) {{.CommandName}}UsageErrStr = fmt.Sprintf("expected '%s'.\nUSERNAME and PASSWORD are required arguments for the {{.CommandName}} command", {{.CommandName}}UsageStr) ) @@ -205,7 +205,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" ) @@ -253,7 +253,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/viper" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" ) @@ -288,10 +288,10 @@ to quickly create a Cobra application.{{.Dot}}) subcmd1Example = templates.Examples({{.Dot}} # Print all option values for subcmd1 - iamctl {{.CommandName}} subcmd1 marmotedu marmotedupass + imctl {{.CommandName}} subcmd1 marmotedu marmotedupass # Print all option values for subcmd1 with --persistent specified - iamctl {{.CommandName}} subcmd1 marmotedu marmotedupass --persistent="specified persistent option in command line"{{.Dot}}) + imctl {{.CommandName}} subcmd1 marmotedu marmotedupass --persistent="specified persistent option in command line"{{.Dot}}) subcmd1UsageErrStr = fmt.Sprintf("expected '%s'.\nUSERNAME and PASSWORD are required arguments for the subcmd1 command", subcmd1UsageStr) ) @@ -386,7 +386,7 @@ import ( "github.com/spf13/cobra" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" ) @@ -411,7 +411,7 @@ to quickly create a Cobra application.{{.Dot}}) subcmd2Example = templates.Examples({{.Dot}} # Print all option values for subcmd2 - iamctl {{.CommandName}} subcmd2{{.Dot}}) + imctl {{.CommandName}} subcmd2{{.Dot}}) ) // NewSubCmd2Options returns an initialized SubCmd2Options instance. diff --git a/tools/imctl/internal/imctl/cmd/options/options.go b/tools/imctl/internal/imctl/cmd/options/options.go index 7f1dcfa9d..9dfee06c9 100644 --- a/tools/imctl/internal/imctl/cmd/options/options.go +++ b/tools/imctl/internal/imctl/cmd/options/options.go @@ -20,7 +20,7 @@ import ( "github.com/spf13/cobra" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" + "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util/templates" ) var optionsExample = templates.Examples(` diff --git a/tools/imctl/internal/imctl/cmd/policy/policy.go b/tools/imctl/internal/imctl/cmd/policy/policy.go deleted file mode 100644 index 6135e246c..000000000 --- a/tools/imctl/internal/imctl/cmd/policy/policy.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package policy provides functions to manage authorization policies on iam platform. -package policy - -import ( - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -var policyLong = templates.LongDesc(` - Authorization policy management commands. - - This commands allow you to manage your authorization policy on iam platform.`) - -// NewCmdPolicy returns new initialized instance of 'policy' sub command. -func NewCmdPolicy(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "policy SUBCOMMAND", - DisableFlagsInUseLine: true, - Short: "Manage authorization policies on iam platform", - Long: policyLong, - Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), - } - - cmd.AddCommand(NewCmdCreate(f, ioStreams)) - cmd.AddCommand(NewCmdGet(f, ioStreams)) - cmd.AddCommand(NewCmdList(f, ioStreams)) - cmd.AddCommand(NewCmdDelete(f, ioStreams)) - cmd.AddCommand(NewCmdUpdate(f, ioStreams)) - - return cmd -} diff --git a/tools/imctl/internal/imctl/cmd/policy/policy_create.go b/tools/imctl/internal/imctl/cmd/policy/policy_create.go deleted file mode 100644 index 221782c0a..000000000 --- a/tools/imctl/internal/imctl/cmd/policy/policy_create.go +++ /dev/null @@ -1,137 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package policy - -import ( - "context" - "fmt" - - v1 "github.com/marmotedu/api/apiserver/v1" - apiclientv1 "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam/apiserver/v1" - "github.com/openim-sigs/component-base/pkg/json" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/ory/ladon" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - createUsageStr = "create POLICY_NAME POLICY" -) - -// CreateOptions is an options struct to support create subcommands. -type CreateOptions struct { - Policy *v1.Policy - - Client apiclientv1.APIV1Interface - genericclioptions.IOStreams -} - -var ( - createExample = templates.Examples(` - # Create a authorization policy - iamctl policy create foo '{"description":"This is a updated policy","subjects":["users:","users:maria","groups:admins"],"actions":["delete",""],"effect":"allow","resources":["resources:articles:<.*>","resources:printer"],"conditions":{"remoteIPAddress":{"type":"CIDRCondition","options":{"cidr":"192.168.0.1/16"}}}}'`) - - createUsageErrStr = fmt.Sprintf( - "expected '%s'.\nPOLICY_NAME and POLICY are required arguments for the create command", - createUsageStr, - ) -) - -// NewCreateOptions returns an initialized CreateOptions instance. -func NewCreateOptions(ioStreams genericclioptions.IOStreams) *CreateOptions { - return &CreateOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdCreate returns new initialized instance of create sub command. -func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewCreateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: createUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Create a authorization policy resource", - TraverseChildren: true, - Long: "Create a authorization policy resource.", - Example: createExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - if len(args) < 2 { - return cmdutil.UsageErrorf(cmd, createUsageErrStr) - } - - var pol ladon.DefaultPolicy - if err := json.Unmarshal([]byte(args[1]), &pol); err != nil { - return err - } - - o.Policy = &v1.Policy{ - ObjectMeta: metav1.ObjectMeta{ - Name: args[0], - }, - Policy: v1.AuthzPolicy{ - DefaultPolicy: pol, - }, - } - - clientConfig, err := f.ToRESTConfig() - if err != nil { - return err - } - o.Client, err = apiclientv1.NewForConfig(clientConfig) - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *CreateOptions) Validate(cmd *cobra.Command, args []string) error { - if errs := o.Policy.Validate(); len(errs) != 0 { - return errs.ToAggregate() - } - - return nil -} - -// Run executes a create subcommand using the specified options. -func (o *CreateOptions) Run(args []string) error { - ret, err := o.Client.Policies().Create(context.TODO(), o.Policy, metav1.CreateOptions{}) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "policy/%s created\n", ret.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/policy/policy_delete.go b/tools/imctl/internal/imctl/cmd/policy/policy_delete.go deleted file mode 100644 index 4cf50726e..000000000 --- a/tools/imctl/internal/imctl/cmd/policy/policy_delete.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package policy - -import ( - "context" - "fmt" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - deleteUsageStr = "delete POLICY_NAME" -) - -// DeleteOptions is an options struct to support delete subcommands. -type DeleteOptions struct { - Name string - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - deleteExample = templates.Examples(` - # Delete a policy resource - iamctl policy delete foo`) - - deleteUsageErrStr = fmt.Sprintf( - "expected '%s'.\nPOLICY_NAME is required arguments for the delete command", - deleteUsageStr, - ) -) - -// NewDeleteOptions returns an initialized DeleteOptions instance. -func NewDeleteOptions(ioStreams genericclioptions.IOStreams) *DeleteOptions { - return &DeleteOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdDelete returns new initialized instance of delete sub command. -func NewCmdDelete(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewDeleteOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "delete", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Delete a authorization policy resource", - TraverseChildren: true, - Long: "Delete a authorization policy resource.", - Example: deleteExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run()) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *DeleteOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, deleteUsageErrStr) - } - - o.Name = args[0] - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *DeleteOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a delete subcommand using the specified options. -func (o *DeleteOptions) Run() error { - if err := o.iamclient.APIV1().Policies().Delete(context.TODO(), o.Name, metav1.DeleteOptions{}); err != nil { - return err - } - - fmt.Fprintf(o.Out, "policy/%s deleted\n", o.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/policy/policy_get.go b/tools/imctl/internal/imctl/cmd/policy/policy_get.go deleted file mode 100644 index 52b049107..000000000 --- a/tools/imctl/internal/imctl/cmd/policy/policy_get.go +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package policy - -import ( - "bytes" - "context" - "fmt" - - "github.com/fatih/color" - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/openim-sigs/component-base/pkg/json" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - getUsageStr = "get POLICY_NAME" -) - -// GetOptions is an options struct to support get subcommands. -type GetOptions struct { - Name string - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - getExample = templates.Examples(` - # Display a policy resource - iamctl policy get foo`) - - getUsageErrStr = fmt.Sprintf("expected '%s'.\nPOLICY_NAME is required arguments for the get command", getUsageStr) -) - -// NewGetOptions returns an initialized GetOptions instance. -func NewGetOptions(ioStreams genericclioptions.IOStreams) *GetOptions { - return &GetOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdGet returns new initialized instance of get sub command. -func NewCmdGet(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewGetOptions(ioStreams) - - cmd := &cobra.Command{ - Use: getUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Display a authorization policy resource", - TraverseChildren: true, - Long: "Display a authorization policy resource.", - Example: getExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, getUsageErrStr) - } - - o.Name = args[0] - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *GetOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a get subcommand using the specified options. -func (o *GetOptions) Run(args []string) error { - policy, err := o.iamclient.APIV1().Policies().Get(context.TODO(), o.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - bf := bytes.NewBuffer([]byte{}) - jsonEncoder := json.NewEncoder(bf) - jsonEncoder.SetEscapeHTML(false) - if err := jsonEncoder.Encode(policy.Policy); err != nil { - return err - } - - fmt.Fprintf(o.Out, "%12s %s\n", color.RedString(policy.Name+":"), bf.String()) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/policy/policy_list.go b/tools/imctl/internal/imctl/cmd/policy/policy_list.go deleted file mode 100644 index dc5b26187..000000000 --- a/tools/imctl/internal/imctl/cmd/policy/policy_list.go +++ /dev/null @@ -1,127 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package policy - -import ( - "bytes" - "context" - "fmt" - - "github.com/fatih/color" - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/openim-sigs/component-base/pkg/json" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - defaultLimit = 1000 -) - -// ListOptions is an options struct to support list subcommands. -type ListOptions struct { - Offset int64 - Limit int64 - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var listExample = templates.Examples(` - # Display all policy resources - iamctl poicy list - - # Display all policy resources with offset and limit - iamctl policy list --offset=0 --limit=10`) - -// NewListOptions returns an initialized ListOptions instance. -func NewListOptions(ioStreams genericclioptions.IOStreams) *ListOptions { - return &ListOptions{ - Offset: 0, - Limit: defaultLimit, - IOStreams: ioStreams, - } -} - -// NewCmdList returns new initialized instance of list sub command. -func NewCmdList(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewListOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "list", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Display all authorization policy resources", - TraverseChildren: true, - Long: "Display all authorization policy resources.", - Example: listExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - cmd.Flags().Int64VarP(&o.Offset, "offset", "o", o.Offset, "Specify the offset of the first row to be returned.") - cmd.Flags().Int64VarP(&o.Limit, "limit", "l", o.Limit, "Specify the amount records to be returned.") - - return cmd -} - -// Complete completes all the required options. -func (o *ListOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *ListOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a list subcommand using the specified options. -func (o *ListOptions) Run(args []string) error { - policies, err := o.iamclient.APIV1().Policies().List(context.TODO(), metav1.ListOptions{ - Offset: &o.Offset, - Limit: &o.Limit, - }) - if err != nil { - return err - } - - for _, pol := range policies.Items { - bf := bytes.NewBuffer([]byte{}) - jsonEncoder := json.NewEncoder(bf) - jsonEncoder.SetEscapeHTML(false) - if err := jsonEncoder.Encode(pol.Policy); err != nil { - return err - } - - fmt.Fprintf(o.Out, "%12s %s\n", color.RedString(pol.Name+":"), bf.String()) - } - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/policy/policy_update.go b/tools/imctl/internal/imctl/cmd/policy/policy_update.go deleted file mode 100644 index 2e0bafd33..000000000 --- a/tools/imctl/internal/imctl/cmd/policy/policy_update.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package policy - -import ( - "context" - "fmt" - - v1 "github.com/marmotedu/api/apiserver/v1" - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/openim-sigs/component-base/pkg/json" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/ory/ladon" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - updateUsageStr = "update POLICY_NAME POLICY" -) - -// UpdateOptions is an options struct to support update subcommands. -type UpdateOptions struct { - Policy *v1.Policy - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - updateExample = templates.Examples(` - # Update a authorization policy with new policy. - iamctl policy update foo "{"description":"This is a updated policy","subjects":["users:","users:maria","groups:admins"],"actions":["delete",""],"effect":"allow","resources":["resources:articles:<.*>","resources:printer"],"conditions":{"remoteIPAddress":{"type":"CIDRCondition","options":{"cidr":"192.168.0.1/16"}}}}"`) - - updateUsageErrStr = fmt.Sprintf( - "expected '%s'.\nPOLICY_NAME and POLICY is required arguments for the update command", - updateUsageStr, - ) -) - -// NewUpdateOptions returns an initialized UpdateOptions instance. -func NewUpdateOptions(ioStreams genericclioptions.IOStreams) *UpdateOptions { - return &UpdateOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdUpdate returns new initialized instance of update sub command. -func NewCmdUpdate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewUpdateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: updateUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Update a authorization policy resource", - TraverseChildren: true, - Long: "Update a authorization policy resource.", - Example: updateExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *UpdateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - - if len(args) < 2 { - return cmdutil.UsageErrorf(cmd, updateUsageErrStr) - } - - var pol ladon.DefaultPolicy - if err = json.Unmarshal([]byte(args[1]), &pol); err != nil { - return err - } - - o.Policy = &v1.Policy{ - ObjectMeta: metav1.ObjectMeta{ - Name: args[0], - }, - Policy: v1.AuthzPolicy{ - DefaultPolicy: pol, - }, - } - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *UpdateOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a update subcommand using the specified options. -func (o *UpdateOptions) Run(args []string) error { - ret, err := o.iamclient.APIV1().Policies().Update(context.TODO(), o.Policy, metav1.UpdateOptions{}) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "policy/%s updated\n", ret.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/secret/secret.go b/tools/imctl/internal/imctl/cmd/secret/secret.go deleted file mode 100644 index 215d6d186..000000000 --- a/tools/imctl/internal/imctl/cmd/secret/secret.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package secret provides functions to manage secrets on iam platform. -package secret - -import ( - "github.com/olekukonko/tablewriter" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -var secretLong = templates.LongDesc(` - Secret management commands. - - This commands allow you to manage your secret on iam platform.`) - -// NewCmdSecret returns new initialized instance of 'secret' sub command. -func NewCmdSecret(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "secret SUBCOMMAND", - DisableFlagsInUseLine: true, - Short: "Manage secrets on iam platform", - Long: secretLong, - Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), - } - - cmd.AddCommand(NewCmdCreate(f, ioStreams)) - cmd.AddCommand(NewCmdGet(f, ioStreams)) - cmd.AddCommand(NewCmdList(f, ioStreams)) - cmd.AddCommand(NewCmdDelete(f, ioStreams)) - cmd.AddCommand(NewCmdUpdate(f, ioStreams)) - - return cmd -} - -// setHeader set headers for secret commands. -func setHeader(table *tablewriter.Table) *tablewriter.Table { - table.SetHeader([]string{"Name", "SecretID", "SecretKey", "Expires", "Created"}) - table.SetHeaderColor(tablewriter.Colors{tablewriter.FgGreenColor}, - tablewriter.Colors{tablewriter.FgRedColor}, - tablewriter.Colors{tablewriter.FgCyanColor}, - tablewriter.Colors{tablewriter.FgMagentaColor}, - tablewriter.Colors{tablewriter.FgGreenColor}) - - return table -} diff --git a/tools/imctl/internal/imctl/cmd/secret/secret_create.go b/tools/imctl/internal/imctl/cmd/secret/secret_create.go deleted file mode 100644 index 2e93413d3..000000000 --- a/tools/imctl/internal/imctl/cmd/secret/secret_create.go +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package secret - -import ( - "context" - "fmt" - "time" - - v1 "github.com/marmotedu/api/apiserver/v1" - apiclientv1 "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam/apiserver/v1" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - createUsageStr = "create SECRET_NAME" -) - -// CreateOptions is an options struct to support create subcommands. -type CreateOptions struct { - Description string - Expires int64 - - Secret *v1.Secret - - Client apiclientv1.APIV1Interface - - genericclioptions.IOStreams -} - -var ( - createLong = templates.LongDesc(`Create secret resource. - -This will generate secretID and secretKey which can be used to sign JWT token.`) - - createExample = templates.Examples(` - # Create secret which will expired after 2 hours - iamctl secret create foo - - # Create secret with a specified expire time and description - iamctl secret create foo --expires=1988121600 --description="secret for iam"`) - - createUsageErrStr = fmt.Sprintf( - "expected '%s'.\nSECRET_NAME is required arguments for the create command", - createUsageStr, - ) -) - -// NewCreateOptions returns an initialized CreateOptions instance. -func NewCreateOptions(ioStreams genericclioptions.IOStreams) *CreateOptions { - return &CreateOptions{ - Expires: time.Now().Add(144 * time.Hour).Unix(), - IOStreams: ioStreams, - } -} - -// NewCmdCreate returns new initialized instance of create sub command. -func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewCreateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: createUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Create secret resource", - TraverseChildren: true, - Long: createLong, - Example: createExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - cmd.Flags().StringVar(&o.Description, "description", o.Description, "The descriptin of the secret.") - cmd.Flags().Int64Var(&o.Expires, "expires", o.Expires, "The expire time of the secret.") - - return cmd -} - -// Complete completes all the required options. -func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, createUsageErrStr) - } - - o.Secret = &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: args[0], - }, - Expires: o.Expires, - Description: o.Description, - } - - clientConfig, err := f.ToRESTConfig() - if err != nil { - return err - } - o.Client, err = apiclientv1.NewForConfig(clientConfig) - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *CreateOptions) Validate(cmd *cobra.Command, args []string) error { - if errs := o.Secret.Validate(); len(errs) != 0 { - return errs.ToAggregate() - } - - return nil -} - -// Run executes a create subcommand using the specified options. -func (o *CreateOptions) Run(args []string) error { - secret, err := o.Client.Secrets().Create(context.TODO(), o.Secret, metav1.CreateOptions{}) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "secret/%s created\n", secret.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/secret/secret_delete.go b/tools/imctl/internal/imctl/cmd/secret/secret_delete.go deleted file mode 100644 index f5a546525..000000000 --- a/tools/imctl/internal/imctl/cmd/secret/secret_delete.go +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package secret - -import ( - "context" - "fmt" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - deleteUsageStr = "delete SECRET_NAME" -) - -// DeleteOptions is an options struct to support delete subcommands. -type DeleteOptions struct { - Name string - - genericclioptions.IOStreams - - iamclient iam.IamInterface -} - -var ( - deleteExample = templates.Examples(` - # Delete secret foo - iamctl secret delete foo`) - - deleteUsageErrStr = fmt.Sprintf( - "expected '%s'.\nSECRET_NAME is required arguments for the delete command", - deleteUsageStr, - ) -) - -// NewDeleteOptions returns an initialized DeleteOptions instance. -func NewDeleteOptions(ioStreams genericclioptions.IOStreams) *DeleteOptions { - return &DeleteOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdDelete returns new initialized instance of delete sub command. -func NewCmdDelete(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewDeleteOptions(ioStreams) - - cmd := &cobra.Command{ - Use: deleteUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Delete a secret resource", - TraverseChildren: true, - Long: "Delete a secret resource.", - Example: deleteExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run()) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *DeleteOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, deleteUsageErrStr) - } - - o.Name = args[0] - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *DeleteOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a delete subcommand using the specified options. -func (o *DeleteOptions) Run() error { - if err := o.iamclient.APIV1().Secrets().Delete(context.TODO(), o.Name, metav1.DeleteOptions{}); err != nil { - return err - } - - fmt.Fprintf(o.Out, "secret/%s deleted\n", o.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/secret/secret_get.go b/tools/imctl/internal/imctl/cmd/secret/secret_get.go deleted file mode 100644 index 4d81ebc34..000000000 --- a/tools/imctl/internal/imctl/cmd/secret/secret_get.go +++ /dev/null @@ -1,130 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package secret - -import ( - "context" - "fmt" - "time" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/olekukonko/tablewriter" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - getUsageStr = "get SECRET_NAME" -) - -// GetOptions is an options struct to support get subcommands. -type GetOptions struct { - Name string - - iamclient iam.IamInterface - - genericclioptions.IOStreams -} - -var ( - getExample = templates.Examples(` - # Get a specified secret information - iamctl secret get foo`) - - getUsageErrStr = fmt.Sprintf("expected '%s'.\nSECRET_NAME is required arguments for the get command", getUsageStr) -) - -// NewGetOptions returns an initialized GetOptions instance. -func NewGetOptions(ioStreams genericclioptions.IOStreams) *GetOptions { - return &GetOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdGet returns new initialized instance of get sub command. -func NewCmdGet(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewGetOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "get SECRET_NAME", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Display a secret resource", - TraverseChildren: true, - Long: "Display a secret resource.", - Example: getExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, getUsageErrStr) - } - - o.Name = args[0] - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *GetOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a get subcommand using the specified options. -func (o *GetOptions) Run(args []string) error { - secret, err := o.iamclient.APIV1().Secrets().Get(context.TODO(), o.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - table := tablewriter.NewWriter(o.Out) - - data := [][]string{ - { - secret.Name, - secret.SecretID, - secret.SecretKey, - time.Unix(secret.Expires, 0).Format("2006-01-02 15:04:05"), - secret.CreatedAt.Format("2006-01-02 15:04:05"), - }, - } - - table = setHeader(table) - table = cmdutil.TableWriterDefaultConfig(table) - table.AppendBulk(data) - table.Render() - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/secret/secret_list.go b/tools/imctl/internal/imctl/cmd/secret/secret_list.go deleted file mode 100644 index 43b9895d7..000000000 --- a/tools/imctl/internal/imctl/cmd/secret/secret_list.go +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package secret - -import ( - "context" - "time" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/olekukonko/tablewriter" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - defaltLimit = 1000 -) - -// ListOptions is an options struct to support list subcommands. -type ListOptions struct { - Offset int64 - Limit int64 - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var listExample = templates.Examples(` - # List all secrets - iamctl secret list - - # List secrets with limit and offset - iamctl secret list --offset=0 --limit=5`) - -// NewListOptions returns an initialized ListOptions instance. -func NewListOptions(ioStreams genericclioptions.IOStreams) *ListOptions { - return &ListOptions{ - IOStreams: ioStreams, - Offset: 0, - Limit: defaltLimit, - } -} - -// NewCmdList returns new initialized instance of list sub command. -func NewCmdList(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewListOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "list", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Display all secret resources", - TraverseChildren: true, - Long: "Display all secret resources.", - Example: listExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - cmd.Flags().Int64VarP(&o.Offset, "offset", "o", o.Offset, "Specify the offset of the first row to be returned.") - cmd.Flags().Int64VarP(&o.Limit, "limit", "l", o.Limit, "Specify the amount records to be returned.") - - return cmd -} - -// Complete completes all the required options. -func (o *ListOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *ListOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a list subcommand using the specified options. -func (o *ListOptions) Run(args []string) error { - secrets, err := o.iamclient.APIV1().Secrets().List(context.TODO(), metav1.ListOptions{ - Offset: &o.Offset, - Limit: &o.Limit, - }) - if err != nil { - return err - } - - data := make([][]string, 0, len(secrets.Items)) - table := tablewriter.NewWriter(o.Out) - - for _, secret := range secrets.Items { - data = append(data, []string{ - secret.Name, - secret.SecretID, - secret.SecretKey, - time.Unix(secret.Expires, 0).Format("2006-01-02 15:04:05"), - secret.CreatedAt.Format("2006-01-02 15:04:05"), - }) - } - - table = setHeader(table) - table = cmdutil.TableWriterDefaultConfig(table) - table.AppendBulk(data) - table.Render() - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/secret/secret_update.go b/tools/imctl/internal/imctl/cmd/secret/secret_update.go deleted file mode 100644 index cf3b7ff25..000000000 --- a/tools/imctl/internal/imctl/cmd/secret/secret_update.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package secret - -import ( - "context" - "fmt" - - v1 "github.com/marmotedu/api/apiserver/v1" - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - updateUsageStr = "update SECRET_NAME" -) - -// UpdateOptions is an options struct to support update subcommands. -type UpdateOptions struct { - Description string - Expires int64 - - Secret *v1.Secret - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - updateExample = templates.Examples(` - # Update a secret resource - iamctl secret update foo --expires=4h --description="new description"`) - - updateUsageErrStr = fmt.Sprintf( - "expected '%s'.\nSECRET_NAME is required arguments for the update command", - updateUsageStr, - ) -) - -// NewUpdateOptions returns an initialized UpdateOptions instance. -func NewUpdateOptions(ioStreams genericclioptions.IOStreams) *UpdateOptions { - return &UpdateOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdUpdate returns new initialized instance of update sub command. -func NewCmdUpdate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewUpdateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "update SECRET_NAME", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Update a secret resource", - TraverseChildren: true, - Long: "Update a secret resource.", - Example: updateExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - cmd.Flags().StringVar(&o.Description, "description", o.Description, "The description of the secret.") - cmd.Flags().Int64Var(&o.Expires, "expires", o.Expires, "The expires of the secret.") - - return cmd -} - -// Complete completes all the required options. -func (o *UpdateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, updateUsageErrStr) - } - - o.Secret = &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: args[0], - }, - Description: o.Description, - Expires: o.Expires, - } - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *UpdateOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a update subcommand using the specified options. -func (o *UpdateOptions) Run(args []string) error { - secret, err := o.iamclient.APIV1().Secrets().Update(context.TODO(), o.Secret, metav1.UpdateOptions{}) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "secret/%s updated\n", secret.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/set/set.go b/tools/imctl/internal/imctl/cmd/set/set.go deleted file mode 100644 index 24267347e..000000000 --- a/tools/imctl/internal/imctl/cmd/set/set.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package set used to set specific features on objects. -package set - -import ( - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -var setLong = templates.LongDesc(` - Configure objects. - - These commands help you make changes to existing objects.`) - -// NewCmdSet returns an initialized Command instance for 'set' sub command. -func NewCmdSet(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "set SUBCOMMAND", - DisableFlagsInUseLine: true, - Short: "Set specific features on objects", - Long: setLong, - Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), - } - - // add subcommands - // cmd.AddCommand(NewCmdDB(f, ioStreams)) - - return cmd -} diff --git a/tools/imctl/internal/imctl/cmd/set/set_db.go b/tools/imctl/internal/imctl/cmd/set/set_db.go deleted file mode 100644 index 34f4526c3..000000000 --- a/tools/imctl/internal/imctl/cmd/set/set_db.go +++ /dev/null @@ -1,213 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package set - -import ( - "fmt" - - "github.com/jinzhu/gorm" - // import mysql driver. - _ "github.com/jinzhu/gorm/dialects/mysql" - v1 "github.com/marmotedu/api/apiserver/v1" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -// DBOptions is an options struct to support 'db' sub command. -type DBOptions struct { - host string - username string - password string - Database string - - drop bool - admin bool - - genericclioptions.IOStreams -} - -var setExample = templates.Examples(` - # Create new iam platform database and tables - iamctl set db --mysql.host=127.0.0.1:3306 --mysql.username=iam --mysql.password=iamxxxx --mysql.database=iam - - # Create new iam platform database and tables with a administrator inserted - iamctl set db --admin --mysql.host=127.0.0.1:3306 --mysql.username=iam --mysql.password=iamxxxx --mysql.database=iam - - # drop and create iam platform database and tables - iamctl set db -d --mysql.host=127.0.0.1:3306 --mysql.username=iam --mysql.password=iamxxxx --mysql.database=iam`) - -// NewDBOptions returns an initialized DBOptions instance. -func NewDBOptions(ioStreams genericclioptions.IOStreams) *DBOptions { - return &DBOptions{ - host: "127.0.0.1:3306", - username: "root", - password: "root", - Database: "iam", - - drop: false, - admin: false, - IOStreams: ioStreams, - } -} - -// NewCmdDB returns new initialized instance of 'db' sub command. -func NewCmdDB(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewDBOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "db", - DisableFlagsInUseLine: true, - Short: "Initialize the iam database", - Long: "Initialize the iam database.", - Example: setExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete()) - cmdutil.CheckErr(o.Validate()) - cmdutil.CheckErr(o.Run()) - }, - Aliases: []string{}, - SuggestFor: []string{}, - } - - cmd.Flags().StringVar(&o.host, "host", o.host, "MySQL service host address.") - cmd.Flags().StringVar(&o.username, "username", o.username, "username for access to mysql service.") - cmd.Flags().StringVar(&o.password, "password", o.password, - "password for access to mysql, should be used pair with password.") - cmd.Flags().StringVar(&o.Database, "database", o.Database, "Database name for the server to use.") - cmd.Flags().BoolVarP(&o.drop, "drop", "d", o.drop, "drop database if exists, pls double check the db name!") - cmd.Flags().BoolVar(&o.admin, "admin", o.drop, "Insert a administrator user to the database.") - - _ = viper.BindPFlags(cmd.Flags()) - - return cmd -} - -// Complete completes all the required options. -func (o *DBOptions) Complete() error { - // o.host = viper.GetString("host") - // o.username = viper.GetString("username") - // o.password = viper.GetString("password") - // o.Database = viper.GetString("database") - // o.drop = viper.GetBool("drop") - // o.admin = viper.GetBool("admin") - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *DBOptions) Validate() error { - return nil -} - -// Run executes a db sub command using the specified options. -func (o *DBOptions) Run() error { - if err := o.ensureSchema(); err != nil { - return err - } - - dsn := fmt.Sprintf("%s:%s@tcp(%s)/%s?charset=utf8&parseTime=%t&loc=%s", - o.username, o.password, o.host, o.Database, true, "Local") - - db, err := gorm.Open("mysql", dsn) - if err != nil { - return err - } - defer db.Close() - - if db.HasTable(&v1.User{}) { - db.AutoMigrate(&v1.User{}) - } else { - db.Debug().CreateTable(&v1.User{}) - } - - if db.HasTable(&v1.Secret{}) { - db.AutoMigrate(&v1.Secret{}) - } else { - db.CreateTable(&v1.Secret{}) - } - - if db.HasTable(&v1.Policy{}) { - db.AutoMigrate(&v1.Policy{}) - } else { - db.CreateTable(&v1.Policy{}) - } - fmt.Fprintf(o.Out, "update table success\n") - - if o.admin { - if err := o.insertAdministrator(db); err != nil { - return err - } - } - - return nil -} - -func (o *DBOptions) ensureSchema() error { - dsn := fmt.Sprintf("%s:%s@tcp(%s)/?charset=utf8", o.username, o.password, o.host) - - db, err := gorm.Open("mysql", dsn) - if err != nil { - return err - } - defer db.Close() - - if o.drop { - dropSQL := fmt.Sprintf("DROP DATABASE IF EXISTS %s", o.Database) - if err := db.Exec(dropSQL).Error; err != nil { - return err - } - fmt.Fprintf(o.Out, "drop database %s success\n", o.Database) - } - - createSQL := fmt.Sprintf("CREATE DATABASE if not exists %s CHARSET utf8 COLLATE utf8_general_ci", o.Database) - if err := db.Exec(createSQL).Error; err != nil { - return err - } - - fmt.Fprintf(o.Out, "create database %s success\n", o.Database) - - return nil -} - -func (o *DBOptions) insertAdministrator(db *gorm.DB) error { - if !o.drop { - return nil - } - - // insert administrator user - user := v1.User{ - ObjectMeta: metav1.ObjectMeta{ - Name: "admin", - }, - Nickname: "admin", - Password: "Admin@2020", - Email: "colin404@foxmail.com", - Phone: "1812884xxxx", - IsAdmin: 1, - } - - if err := db.Create(&user).Error; err != nil { - return err - } - - fmt.Fprintf(o.Out, "insert administrator success\n") - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/user/user.go b/tools/imctl/internal/imctl/cmd/user/user.go deleted file mode 100644 index b8d05da19..000000000 --- a/tools/imctl/internal/imctl/cmd/user/user.go +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package user provides functions to manage users on iam platform. -package user - -import ( - "github.com/olekukonko/tablewriter" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -var userLong = templates.LongDesc(` - User management commands. - -Administrator can use all subcommands, non-administrator only allow to use create/get/upate. When call get/update non-administrator only allow to operate their own resources, if permission not allowed, will return an 'Permission denied' error.`) - -// NewCmdUser returns new initialized instance of 'user' sub command. -func NewCmdUser(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - cmd := &cobra.Command{ - Use: "user SUBCOMMAND", - DisableFlagsInUseLine: true, - Short: "Manage users on iam platform", - Long: userLong, - Run: cmdutil.DefaultSubCommandRun(ioStreams.ErrOut), - } - - cmd.AddCommand(NewCmdCreate(f, ioStreams)) - cmd.AddCommand(NewCmdGet(f, ioStreams)) - cmd.AddCommand(NewCmdList(f, ioStreams)) - cmd.AddCommand(NewCmdDelete(f, ioStreams)) - cmd.AddCommand(NewCmdUpdate(f, ioStreams)) - - return cmd -} - -// setHeader set headers for user commands. -func setHeader(table *tablewriter.Table) *tablewriter.Table { - table.SetHeader([]string{"Name", "Nickname", "Email", "Phone", "Created", "Updated"}) - table.SetHeaderColor(tablewriter.Colors{tablewriter.FgGreenColor}, - tablewriter.Colors{tablewriter.FgRedColor}, - tablewriter.Colors{tablewriter.FgCyanColor}, - tablewriter.Colors{tablewriter.FgMagentaColor}, - tablewriter.Colors{tablewriter.FgGreenColor}, - tablewriter.Colors{tablewriter.FgWhiteColor}) - - return table -} diff --git a/tools/imctl/internal/imctl/cmd/user/user_create.go b/tools/imctl/internal/imctl/cmd/user/user_create.go deleted file mode 100644 index 0a52454ab..000000000 --- a/tools/imctl/internal/imctl/cmd/user/user_create.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package user - -import ( - "context" - "fmt" - - v1 "github.com/marmotedu/api/apiserver/v1" - apiclientv1 "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam/apiserver/v1" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - createUsageStr = "create USERNAME PASSWORD EMAIL" -) - -// CreateOptions is an options struct to support create subcommands. -type CreateOptions struct { - Nickname string - Phone string - - User *v1.User - - Client apiclientv1.APIV1Interface - genericclioptions.IOStreams -} - -var ( - createLong = templates.LongDesc(`Create a user on iam platform. -If nickname not specified, username will be used.`) - - createExample = templates.Examples(` - # Create user with given input - iamctl user create foo Foo@2020 foo@foxmail.com - - # Create user wt - iamctl user create foo Foo@2020 foo@foxmail.com --phone=18128845xxx --nickname=colin`) - - createUsageErrStr = fmt.Sprintf( - "expected '%s'.\nUSERNAME, PASSWORD and EMAIL are required arguments for the create command", - createUsageStr, - ) -) - -// NewCreateOptions returns an initialized CreateOptions instance. -func NewCreateOptions(ioStreams genericclioptions.IOStreams) *CreateOptions { - return &CreateOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdCreate returns new initialized instance of create sub command. -func NewCmdCreate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewCreateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: createUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Create a user resource", - TraverseChildren: true, - Long: createLong, - Example: createExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - // mark flag as deprecated - cmd.Flags().StringVar(&o.Nickname, "nickname", o.Nickname, "The nickname of the user.") - cmd.Flags().StringVar(&o.Phone, "phone", o.Phone, "The phone number of the user.") - - return cmd -} - -// Complete completes all the required options. -func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) < 3 { - return cmdutil.UsageErrorf(cmd, createUsageErrStr) - } - - if o.Nickname == "" { - o.Nickname = args[0] - } - - o.User = &v1.User{ - ObjectMeta: metav1.ObjectMeta{ - Name: args[0], - }, - Nickname: o.Nickname, - Password: args[1], - Email: args[2], - Phone: o.Phone, - } - - clientConfig, err := f.ToRESTConfig() - if err != nil { - return err - } - o.Client, err = apiclientv1.NewForConfig(clientConfig) - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *CreateOptions) Validate(cmd *cobra.Command, args []string) error { - if errs := o.User.Validate(); len(errs) != 0 { - return errs.ToAggregate() - } - - return nil -} - -// Run executes a create subcommand using the specified options. -func (o *CreateOptions) Run(args []string) error { - ret, err := o.Client.Users().Create(context.TODO(), o.User, metav1.CreateOptions{}) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "user/%s created\n", ret.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/user/user_delete.go b/tools/imctl/internal/imctl/cmd/user/user_delete.go deleted file mode 100644 index eecfabc78..000000000 --- a/tools/imctl/internal/imctl/cmd/user/user_delete.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package user - -import ( - "context" - "fmt" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - deleteUsageStr = "delete USERNAME" -) - -// DeleteOptions is an options struct to support delete subcommands. -type DeleteOptions struct { - Name string - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - deleteExample = templates.Examples(` - # Delete user foo from platform - iamctl user delete foo`) - - deleteUsageErrStr = fmt.Sprintf( - "expected '%s'.\nUSERNAME is required arguments for the delete command", - deleteUsageStr, - ) -) - -// NewDeleteOptions returns an initialized DeleteOptions instance. -func NewDeleteOptions(ioStreams genericclioptions.IOStreams) *DeleteOptions { - return &DeleteOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdDelete returns new initialized instance of delete sub command. -func NewCmdDelete(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewDeleteOptions(ioStreams) - - cmd := &cobra.Command{ - Use: deleteUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Delete a user resource from iam platform (Administrator rights required)", - TraverseChildren: true, - Long: "Delete a user resource from iam platform, only administrator can do this operation.", - Example: deleteExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run()) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *DeleteOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, deleteUsageErrStr) - } - - o.Name = args[0] - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *DeleteOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a delete subcommand using the specified options. -func (o *DeleteOptions) Run() error { - if err := o.iamclient.APIV1().Users().Delete(context.TODO(), o.Name, metav1.DeleteOptions{}); err != nil { - return err - } - - fmt.Fprintf(o.Out, "user/%s deleted\n", o.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/user/user_get.go b/tools/imctl/internal/imctl/cmd/user/user_get.go deleted file mode 100644 index d3e76fc77..000000000 --- a/tools/imctl/internal/imctl/cmd/user/user_get.go +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package user - -import ( - "context" - "fmt" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/olekukonko/tablewriter" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - getUsageStr = "get USERNAME" -) - -// GetOptions is an options struct to support get subcommands. -type GetOptions struct { - Name string - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - getExample = templates.Examples(` - # Get user foo detail information - iamctl user get foo`) - - getUsageErrStr = fmt.Sprintf("expected '%s'.\nUSERNAME is required arguments for the get command", getUsageStr) -) - -// NewGetOptions returns an initialized GetOptions instance. -func NewGetOptions(ioStreams genericclioptions.IOStreams) *GetOptions { - return &GetOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdGet returns new initialized instance of get sub command. -func NewCmdGet(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewGetOptions(ioStreams) - - cmd := &cobra.Command{ - Use: getUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Display a user resource.", - TraverseChildren: true, - Long: `Display a user resource.`, - Example: getExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *GetOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, getUsageErrStr) - } - - o.Name = args[0] - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *GetOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a get subcommand using the specified options. -func (o *GetOptions) Run(args []string) error { - user, err := o.iamclient.APIV1().Users().Get(context.TODO(), o.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - table := tablewriter.NewWriter(o.Out) - - data := [][]string{ - { - user.Name, - user.Nickname, - user.Email, - user.Phone, - user.CreatedAt.Format("2006-01-02 15:04:05"), - user.UpdatedAt.Format("2006-01-02 15:04:05"), - }, - } - - table = setHeader(table) - table = cmdutil.TableWriterDefaultConfig(table) - table.AppendBulk(data) - table.Render() - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/user/user_list.go b/tools/imctl/internal/imctl/cmd/user/user_list.go deleted file mode 100644 index c219baed8..000000000 --- a/tools/imctl/internal/imctl/cmd/user/user_list.go +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package user - -import ( - "context" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - "github.com/olekukonko/tablewriter" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - defaultLimit = 1000 -) - -// ListOptions is an options struct to support list subcommands. -type ListOptions struct { - Offset int64 - Limit int64 - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var listExample = templates.Examples(` - # List all users - iamctl user list - - # List users with limit and offset - iamctl user list --offset=0 --limit=10`) - -// NewListOptions returns an initialized ListOptions instance. -func NewListOptions(ioStreams genericclioptions.IOStreams) *ListOptions { - return &ListOptions{ - IOStreams: ioStreams, - Offset: 0, - Limit: defaultLimit, - } -} - -// NewCmdList returns new initialized instance of list sub command. -func NewCmdList(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewListOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "list", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Display all users in iam platform (Administrator rights required)", - TraverseChildren: true, - Long: "Display all users in iam platform (Administrator rights required).", - Example: listExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - cmd.Flags().Int64VarP(&o.Offset, "offset", "o", o.Offset, "Specify the offset of the first row to be returned.") - cmd.Flags().Int64VarP(&o.Limit, "limit", "l", o.Limit, "Specify the amount records to be returned.") - - return cmd -} - -// Complete completes all the required options. -func (o *ListOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *ListOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a list subcommand using the specified options. -func (o *ListOptions) Run(args []string) error { - users, err := o.iamclient.APIV1().Users().List(context.TODO(), metav1.ListOptions{ - Offset: &o.Offset, - Limit: &o.Limit, - }) - if err != nil { - return err - } - - data := make([][]string, 0, 1) - table := tablewriter.NewWriter(o.Out) - - for _, user := range users.Items { - data = append(data, []string{ - user.Name, user.Nickname, user.Email, - user.Phone, user.CreatedAt.Format("2006-01-02 15:04:05"), user.UpdatedAt.Format("2006-01-02 15:04:05"), - }) - } - - table = setHeader(table) - table = cmdutil.TableWriterDefaultConfig(table) - table.AppendBulk(data) - table.Render() - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/user/user_update.go b/tools/imctl/internal/imctl/cmd/user/user_update.go deleted file mode 100644 index 7bf5508d7..000000000 --- a/tools/imctl/internal/imctl/cmd/user/user_update.go +++ /dev/null @@ -1,142 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package user - -import ( - "context" - "fmt" - - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - metav1 "github.com/openim-sigs/component-base/pkg/meta/v1" - "github.com/spf13/cobra" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - updateUsageStr = "update USERNAME" -) - -// UpdateOptions is an options struct to support update subcommands. -type UpdateOptions struct { - Name string - Nickname string - Email string - Phone string - - iamclient iam.IamInterface - genericclioptions.IOStreams -} - -var ( - updateLong = templates.LongDesc(`Update a user resource. - -Can only update nickname, email and phone. - -NOTICE: field will be updated to zero value if not specified.`) - - updateExample = templates.Examples(` - # Update use foo's information - iamctl user update foo --nickname=foo2 --email=foo@qq.com --phone=1812883xxxx`) - - updateUsageErrStr = fmt.Sprintf( - "expected '%s'.\nUSERNAME is required arguments for the update command", - updateUsageStr, - ) -) - -// NewUpdateOptions returns an initialized UpdateOptions instance. -func NewUpdateOptions(ioStreams genericclioptions.IOStreams) *UpdateOptions { - return &UpdateOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdUpdate returns new initialized instance of update sub command. -func NewCmdUpdate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewUpdateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: updateUsageStr, - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Update a user resource", - TraverseChildren: true, - Long: updateLong, - Example: updateExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - cmd.Flags().StringVar(&o.Nickname, "nickname", o.Nickname, "The nickname of the user.") - cmd.Flags().StringVar(&o.Email, "email", o.Email, "The email of the user.") - cmd.Flags().StringVar(&o.Phone, "phone", o.Phone, "The phone number of the user.") - - return cmd -} - -// Complete completes all the required options. -func (o *UpdateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - var err error - if len(args) == 0 { - return cmdutil.UsageErrorf(cmd, updateUsageErrStr) - } - - o.Name = args[0] - o.iamclient, err = f.IAMClient() - if err != nil { - return err - } - - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *UpdateOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes an update subcommand using the specified options. -func (o *UpdateOptions) Run(args []string) error { - user, err := o.iamclient.APIV1().Users().Get(context.TODO(), o.Name, metav1.GetOptions{}) - if err != nil { - return err - } - - if o.Nickname != "" { - user.Nickname = o.Nickname - } - if o.Email != "" { - user.Email = o.Email - } - if o.Phone != "" { - user.Phone = o.Phone - } - - ret, err := o.iamclient.APIV1().Users().Update(context.TODO(), user, metav1.UpdateOptions{}) - if err != nil { - return err - } - - fmt.Fprintf(o.Out, "user/%s updated\n", ret.Name) - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/util/factory.go b/tools/imctl/internal/imctl/cmd/util/factory.go deleted file mode 100644 index 65652709e..000000000 --- a/tools/imctl/internal/imctl/cmd/util/factory.go +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package util - -import ( - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - restclient "github.com/marmotedu/marmotedu-sdk-go/rest" - - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -// Factory provides abstractions that allow the IAM command to be extended across multiple types -// of resources and different API sets. -// The rings are here for a reason. In order for composers to be able to provide alternative factory implementations -// they need to provide low level pieces of *certain* functions so that when the factory calls back into itself -// it uses the custom version of the function. Rather than try to enumerate everything that someone would want to -// override -// we split the factory into rings, where each ring can depend on methods in an earlier ring, but cannot depend -// upon peer methods in its own ring. -// TODO: make the functions interfaces -// TODO: pass the various interfaces on the factory directly into the command constructors (so the -// commands are decoupled from the factory). -type Factory interface { - genericclioptions.RESTClientGetter - - // IAMClient gives you back an external iamclient - IAMClient() (*iam.IamClient, error) - - // Returns a RESTClient for accessing IAM resources or an error. - RESTClient() (*restclient.RESTClient, error) -} diff --git a/tools/imctl/internal/imctl/cmd/util/factory_client_access.go b/tools/imctl/internal/imctl/cmd/util/factory_client_access.go deleted file mode 100644 index 1064bd129..000000000 --- a/tools/imctl/internal/imctl/cmd/util/factory_client_access.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// this file contains factories with no other dependencies - -package util - -import ( - "github.com/marmotedu/marmotedu-sdk-go/marmotedu/service/iam" - restclient "github.com/marmotedu/marmotedu-sdk-go/rest" - "github.com/marmotedu/marmotedu-sdk-go/tools/clientcmd" - - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -type factoryImpl struct { - clientGetter genericclioptions.RESTClientGetter -} - -func NewFactory(clientGetter genericclioptions.RESTClientGetter) Factory { - if clientGetter == nil { - panic("attempt to instantiate client_access_factory with nil clientGetter") - } - - f := &factoryImpl{ - clientGetter: clientGetter, - } - - return f -} - -func (f *factoryImpl) ToRESTConfig() (*restclient.Config, error) { - return f.clientGetter.ToRESTConfig() -} - -func (f *factoryImpl) ToRawIAMConfigLoader() clientcmd.ClientConfig { - return f.clientGetter.ToRawIAMConfigLoader() -} - -func (f *factoryImpl) IAMClient() (*iam.IamClient, error) { - clientConfig, err := f.ToRESTConfig() - if err != nil { - return nil, err - } - return iam.NewForConfig(clientConfig) -} - -func (f *factoryImpl) RESTClient() (*restclient.RESTClient, error) { - clientConfig, err := f.ToRESTConfig() - if err != nil { - return nil, err - } - setIAMDefaults(clientConfig) - return restclient.RESTClientFor(clientConfig) -} diff --git a/tools/imctl/internal/imctl/cmd/util/helpers.go b/tools/imctl/internal/imctl/cmd/util/helpers.go deleted file mode 100644 index e42791916..000000000 --- a/tools/imctl/internal/imctl/cmd/util/helpers.go +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package util - -import ( - "bytes" - "fmt" - "io" - "net/http" - "net/url" - "os" - "strings" - "time" - - "github.com/marmotedu/errors" - "github.com/marmotedu/marmotedu-sdk-go/marmotedu" - restclient "github.com/marmotedu/marmotedu-sdk-go/rest" - "github.com/olekukonko/tablewriter" - "github.com/parnurzeal/gorequest" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/log" -) - -const ( - // DefaultErrorExitCode defines the default exit code. - DefaultErrorExitCode = 1 -) - -type debugError interface { - DebugError() (msg string, args []interface{}) -} - -var fatalErrHandler = fatal - -// BehaviorOnFatal allows you to override the default behavior when a fatal -// error occurs, which is to call os.Exit(code). You can pass 'panic' as a function -// here if you prefer the panic() over os.Exit(1). -func BehaviorOnFatal(f func(string, int)) { - fatalErrHandler = f -} - -// DefaultBehaviorOnFatal allows you to undo any previous override. Useful in -// tests. -func DefaultBehaviorOnFatal() { - fatalErrHandler = fatal -} - -// fatal prints the message (if provided) and then exits. -func fatal(msg string, code int) { - if len(msg) > 0 { - // add newline if needed - if !strings.HasSuffix(msg, "\n") { - msg += "\n" - } - fmt.Fprint(os.Stderr, msg) - } - os.Exit(code) -} - -// ErrExit may be passed to CheckError to instruct it to output nothing but exit with -// status code 1. -var ErrExit = fmt.Errorf("exit") - -// CheckErr prints a user-friendly error to STDERR and exits with a non-zero -// exit code. Unrecognized errors will be printed with an "error: " prefix. -// -// This method is generic to the command in use and may be used by non-IAM -// commands. -func CheckErr(err error) { - checkErr(err, fatalErrHandler) -} - -// CheckDiffErr prints a user-friendly error to STDERR and exits with a -// non-zero and non-one exit code. Unrecognized errors will be printed -// with an "error: " prefix. -// -// This method is meant specifically for `iamctl diff` and may be used -// by other commands. -func CheckDiffErr(err error) { - checkErr(err, func(msg string, code int) { - fatalErrHandler(msg, code+1) - }) -} - -// checkErr formats a given error as a string and calls the passed handleErr -// func with that string and an iamctl exit code. -func checkErr(err error, handleErr func(string, int)) { - // unwrap aggregates of 1 - if agg, ok := err.(errors.Aggregate); ok && len(agg.Errors()) == 1 { - err = agg.Errors()[0] - } - - if err == nil { - return - } - - switch { - case err == ErrExit: - handleErr("", DefaultErrorExitCode) - default: - switch err := err.(type) { - case errors.Aggregate: - handleErr(MultipleErrors(``, err.Errors()), DefaultErrorExitCode) - default: // for any other error type - msg, ok := StandardErrorMessage(err) - if !ok { - msg = err.Error() - if !strings.HasPrefix(msg, "error: ") { - msg = fmt.Sprintf("error: %s", msg) - } - } - handleErr(msg, DefaultErrorExitCode) - } - } -} - -// StandardErrorMessage translates common errors into a human readable message, or returns -// false if the error is not one of the recognized types. It may also log extended information to klog. -// -// This method is generic to the command in use and may be used by non-IAM -// commands. -func StandardErrorMessage(err error) (string, bool) { - if debugErr, ok := err.(debugError); ok { - log.Infof(debugErr.DebugError()) - } - if t, ok := err.(*url.Error); ok { - log.Infof("Connection error: %s %s: %v", t.Op, t.URL, t.Err) - if strings.Contains(t.Err.Error(), "connection refused") { - host := t.URL - if server, err := url.Parse(t.URL); err == nil { - host = server.Host - } - return fmt.Sprintf( - "The connection to the server %s was refused - did you specify the right host or port?", - host, - ), true - } - - return fmt.Sprintf("Unable to connect to the server: %v", t.Err), true - } - return "", false -} - -// MultilineError returns a string representing an error that splits sub errors into their own -// lines. The returned string will end with a newline. -func MultilineError(prefix string, err error) string { - if agg, ok := err.(errors.Aggregate); ok { - errs := errors.Flatten(agg).Errors() - buf := &bytes.Buffer{} - switch len(errs) { - case 0: - return fmt.Sprintf("%s%v\n", prefix, err) - case 1: - return fmt.Sprintf("%s%v\n", prefix, messageForError(errs[0])) - default: - fmt.Fprintln(buf, prefix) - for _, err := range errs { - fmt.Fprintf(buf, "* %v\n", messageForError(err)) - } - return buf.String() - } - } - return fmt.Sprintf("%s%s\n", prefix, err) -} - -// MultipleErrors returns a newline delimited string containing -// the prefix and referenced errors in standard form. -func MultipleErrors(prefix string, errs []error) string { - buf := &bytes.Buffer{} - for _, err := range errs { - fmt.Fprintf(buf, "%s%v\n", prefix, messageForError(err)) - } - return buf.String() -} - -// messageForError returns the string representing the error. -func messageForError(err error) string { - msg, ok := StandardErrorMessage(err) - if !ok { - msg = err.Error() - } - return msg -} - -// UsageErrorf returns error with command path. -func UsageErrorf(cmd *cobra.Command, format string, args ...interface{}) error { - msg := fmt.Sprintf(format, args...) - return fmt.Errorf("%s\nSee '%s -h' for help and examples", msg, cmd.CommandPath()) -} - -// IsFilenameSliceEmpty checkes where filenames and directory are both zero value. -func IsFilenameSliceEmpty(filenames []string, directory string) bool { - return len(filenames) == 0 && directory == "" -} - -// GetFlagString returns the value of the given flag. -func GetFlagString(cmd *cobra.Command, flag string) string { - s, err := cmd.Flags().GetString(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return s -} - -// GetFlagStringSlice can be used to accept multiple argument with flag repetition (e.g. -f arg1,arg2 -f arg3 ...). -func GetFlagStringSlice(cmd *cobra.Command, flag string) []string { - s, err := cmd.Flags().GetStringSlice(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return s -} - -// GetFlagStringArray can be used to accept multiple argument with flag repetition (e.g. -f arg1 -f arg2 ...). -func GetFlagStringArray(cmd *cobra.Command, flag string) []string { - s, err := cmd.Flags().GetStringArray(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return s -} - -// GetFlagBool returns the value of the given flag. -func GetFlagBool(cmd *cobra.Command, flag string) bool { - b, err := cmd.Flags().GetBool(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return b -} - -// GetFlagInt returns the value of the given flag. -func GetFlagInt(cmd *cobra.Command, flag string) int { - i, err := cmd.Flags().GetInt(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return i -} - -// GetFlagInt32 returns the value of the given flag. -func GetFlagInt32(cmd *cobra.Command, flag string) int32 { - i, err := cmd.Flags().GetInt32(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return i -} - -// GetFlagInt64 returns the value of the given flag. -func GetFlagInt64(cmd *cobra.Command, flag string) int64 { - i, err := cmd.Flags().GetInt64(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return i -} - -// GetFlagDuration return the value of the given flag. -func GetFlagDuration(cmd *cobra.Command, flag string) time.Duration { - d, err := cmd.Flags().GetDuration(flag) - if err != nil { - log.Fatalf("error accessing flag %s for command %s: %v", flag, cmd.Name(), err) - } - return d -} - -// AddCleanFlags add clean flags. -func AddCleanFlags(cmd *cobra.Command) { - cmd.Flags().StringP("user", "u", "", "Specify the user name.") - cmd.Flags().BoolP("erase", "c", false, "Erase the records from the db") -} - -// ValidateOptions defines the validate options. -type ValidateOptions struct { - EnableValidation bool -} - -// IsSiblingCommandExists receives a pointer to a cobra command and a target string. -// Returns true if the target string is found in the list of sibling commands. -func IsSiblingCommandExists(cmd *cobra.Command, targetCmdName string) bool { - for _, c := range cmd.Parent().Commands() { - if c.Name() == targetCmdName { - return true - } - } - - return false -} - -// DefaultSubCommandRun prints a command's help string to the specified output if no -// arguments (sub-commands) are provided, or a usage error otherwise. -func DefaultSubCommandRun(out io.Writer) func(c *cobra.Command, args []string) { - return func(c *cobra.Command, args []string) { - c.SetOutput(out) - RequireNoArguments(c, args) - c.Help() - CheckErr(ErrExit) - } -} - -// RequireNoArguments exits with a usage error if extra arguments are provided. -func RequireNoArguments(c *cobra.Command, args []string) { - if len(args) > 0 { - CheckErr(UsageErrorf(c, "unknown command %q", strings.Join(args, " "))) - } -} - -// ManualStrip is used for dropping comments from a YAML file. -func ManualStrip(file []byte) []byte { - stripped := []byte{} - lines := bytes.Split(file, []byte("\n")) - for i, line := range lines { - if bytes.HasPrefix(bytes.TrimSpace(line), []byte("#")) { - continue - } - stripped = append(stripped, line...) - if i < len(lines)-1 { - stripped = append(stripped, '\n') - } - } - return stripped -} - -// Warning write warning message to io.Writer. -func Warning(cmdErr io.Writer, newGeneratorName, oldGeneratorName string) { - fmt.Fprintf(cmdErr, "WARNING: New generator %q specified, "+ - "but it isn't available. "+ - "Falling back to %q.\n", - newGeneratorName, - oldGeneratorName, - ) -} - -// CombineRequestErr combines the http response error and error in errs array. -func CombineRequestErr(resp gorequest.Response, body string, errs []error) error { - var e, sep string - if len(errs) > 0 { - for _, err := range errs { - e = sep + err.Error() - sep = "\n" - } - return errors.New(e) - } - - if resp.StatusCode != http.StatusOK { - return errors.New(body) - } - - return nil -} - -func NewForConfigOrDie() *marmotedu.Clientset { - clientConfig := &restclient.Config{ - Host: viper.GetString("server.address"), - BearerToken: viper.GetString("user.token"), - Username: viper.GetString("user.username"), - Password: viper.GetString("user.password"), - SecretID: viper.GetString("user.secret-id"), - SecretKey: viper.GetString("user.secret-key"), - Timeout: viper.GetDuration("server.timeout"), - MaxRetries: viper.GetInt("server.max-retries"), - RetryInterval: viper.GetDuration("server.retry-interval"), - } - - return marmotedu.NewForConfigOrDie(clientConfig) -} - -func TableWriterDefaultConfig(table *tablewriter.Table) *tablewriter.Table { - table.SetAutoWrapText(false) - table.SetAutoFormatHeaders(true) - table.SetHeaderAlignment(tablewriter.ALIGN_LEFT) - table.SetAlignment(tablewriter.ALIGN_LEFT) - table.SetCenterSeparator("") - table.SetColumnSeparator("") - table.SetRowSeparator("") - table.SetHeaderLine(false) - table.SetBorder(false) - table.SetTablePadding(" ") // pad with two space - table.SetNoWhiteSpace(true) - - return table -} diff --git a/tools/imctl/internal/imctl/cmd/util/iam_match_version.go b/tools/imctl/internal/imctl/cmd/util/iam_match_version.go deleted file mode 100644 index e03bb4fca..000000000 --- a/tools/imctl/internal/imctl/cmd/util/iam_match_version.go +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package util - -import ( - "context" - "fmt" - "sync" - - "github.com/marmotedu/marmotedu-sdk-go/rest" - "github.com/marmotedu/marmotedu-sdk-go/tools/clientcmd" - "github.com/openim-sigs/component-base/pkg/runtime" - "github.com/openim-sigs/component-base/pkg/scheme" - "github.com/openim-sigs/component-base/pkg/version" - "github.com/spf13/pflag" - - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -const ( - flagMatchBinaryVersion = "match-server-version" -) - -// MatchVersionFlags is for setting the "match server version" function. -type MatchVersionFlags struct { - Delegate genericclioptions.RESTClientGetter - - RequireMatchedServerVersion bool - checkServerVersion sync.Once - matchesServerVersionErr error -} - -var _ genericclioptions.RESTClientGetter = &MatchVersionFlags{} - -func (f *MatchVersionFlags) checkMatchingServerVersion() error { - f.checkServerVersion.Do(func() { - if !f.RequireMatchedServerVersion { - return - } - - clientConfig, err := f.Delegate.ToRESTConfig() - if err != nil { - f.matchesServerVersionErr = err - return - } - - setIAMDefaults(clientConfig) - restClient, err := rest.RESTClientFor(clientConfig) - if err != nil { - f.matchesServerVersionErr = err - return - } - - var sVer *version.Info - if err := restClient.Get().AbsPath("/version").Do(context.TODO()).Into(&sVer); err != nil { - f.matchesServerVersionErr = err - return - } - - clientVersion := version.Get() - - // GitVersion includes GitCommit and GitTreeState, but best to be safe? - if clientVersion.GitVersion != sVer.GitVersion || clientVersion.GitCommit != sVer.GitCommit || - clientVersion.GitTreeState != sVer.GitTreeState { - f.matchesServerVersionErr = fmt.Errorf( - "server version (%#v) differs from client version (%#v)", - sVer, - version.Get(), - ) - } - }) - - return f.matchesServerVersionErr -} - -// ToRESTConfig implements RESTClientGetter. -// Returns a REST client configuration based on a provided path -// to a .iamconfig file, loading rules, and config flag overrides. -// Expects the AddFlags method to have been called. -func (f *MatchVersionFlags) ToRESTConfig() (*rest.Config, error) { - if err := f.checkMatchingServerVersion(); err != nil { - return nil, err - } - clientConfig, err := f.Delegate.ToRESTConfig() - if err != nil { - return nil, err - } - // TODO we should not have to do this. It smacks of something going wrong. - setIAMDefaults(clientConfig) - return clientConfig, nil -} - -func (f *MatchVersionFlags) ToRawIAMConfigLoader() clientcmd.ClientConfig { - return f.Delegate.ToRawIAMConfigLoader() -} - -func (f *MatchVersionFlags) AddFlags(flags *pflag.FlagSet) { - flags.BoolVar( - &f.RequireMatchedServerVersion, - flagMatchBinaryVersion, - f.RequireMatchedServerVersion, - "Require server version to match client version", - ) -} - -func NewMatchVersionFlags(delegate genericclioptions.RESTClientGetter) *MatchVersionFlags { - return &MatchVersionFlags{ - Delegate: delegate, - } -} - -// setIAMDefaults sets default values on the provided client config for accessing the -// IAM API or returns an error if any of the defaults are impossible or invalid. -// TODO this isn't what we want. Each iamclient should be setting defaults as it sees fit. -func setIAMDefaults(config *rest.Config) error { - // TODO remove this hack. This is allowing the GetOptions to be serialized. - config.GroupVersion = &scheme.GroupVersion{Group: "iam.api", Version: "v1"} - - if config.APIPath == "" { - config.APIPath = "/api" - } - if config.Negotiator == nil { - // This codec factory ensures the resources are not converted. Therefore, resources - // will not be round-tripped through internal versions. Defaulting does not happen - // on the client. - config.Negotiator = runtime.NewSimpleClientNegotiator() - } - return rest.SetIAMDefaults(config) -} diff --git a/tools/imctl/internal/imctl/cmd/validate/validate.go b/tools/imctl/internal/imctl/cmd/validate/validate.go deleted file mode 100644 index 76642992f..000000000 --- a/tools/imctl/internal/imctl/cmd/validate/validate.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package validate validate the basic environment for iamctl to run. -package validate - -import ( - "fmt" - "net" - "net/url" - - "github.com/fatih/color" - "github.com/olekukonko/tablewriter" - "github.com/spf13/cobra" - "github.com/spf13/viper" - - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" -) - -// ValidateOptions is an options struct to support 'validate' sub command. -type ValidateOptions struct { - genericclioptions.IOStreams -} - -// ValidateInfo defines the validate information. -type ValidateInfo struct { - ItemName string - Status string - Message string -} - -var validateExample = templates.Examples(` - # Validate the basic environment for iamctl to run - iamctl validate`) - -// NewValidateOptions returns an initialized ValidateOptions instance. -func NewValidateOptions(ioStreams genericclioptions.IOStreams) *ValidateOptions { - return &ValidateOptions{ - IOStreams: ioStreams, - } -} - -// NewCmdValidate returns new initialized instance of 'validate' sub command. -func NewCmdValidate(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command { - o := NewValidateOptions(ioStreams) - - cmd := &cobra.Command{ - Use: "validate", - DisableFlagsInUseLine: true, - Aliases: []string{}, - Short: "Validate the basic environment for iamctl to run", - TraverseChildren: true, - Long: "Validate the basic environment for iamctl to run.", - Example: validateExample, - Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(o.Complete(f, cmd, args)) - cmdutil.CheckErr(o.Validate(cmd, args)) - cmdutil.CheckErr(o.Run(args)) - }, - SuggestFor: []string{}, - } - - return cmd -} - -// Complete completes all the required options. -func (o *ValidateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { - return nil -} - -// Validate makes sure there is no discrepency in command options. -func (o *ValidateOptions) Validate(cmd *cobra.Command, args []string) error { - return nil -} - -// Run executes a validate sub command using the specified options. -func (o *ValidateOptions) Run(args []string) error { - data := [][]string{} - FAIL := color.RedString("FAIL") - PASS := color.GreenString("PASS") - validateInfo := ValidateInfo{} - - // check if can access db - validateInfo.ItemName = "iam-apiserver" - target, err := url.Parse(viper.GetString("server.address")) - if err != nil { - return err - } - _, err = net.Dial("tcp", target.Host) - // defer client.Close() - if err != nil { - validateInfo.Status = FAIL - validateInfo.Message = fmt.Sprintf("%v", err) - } else { - validateInfo.Status = PASS - validateInfo.Message = "" - } - - data = append(data, []string{validateInfo.ItemName, validateInfo.Status, validateInfo.Message}) - - table := tablewriter.NewWriter(o.Out) - table.SetAlignment(tablewriter.ALIGN_LEFT) - table.SetColWidth(iamctl.TableWidth) - table.SetHeader([]string{"ValidateItem", "Result", "Message"}) - - for _, v := range data { - table.Append(v) - } - - table.Render() - - return nil -} diff --git a/tools/imctl/internal/imctl/cmd/version/version.go b/tools/imctl/internal/imctl/cmd/version/version.go index 9dd447196..851f9b28d 100644 --- a/tools/imctl/internal/imctl/cmd/version/version.go +++ b/tools/imctl/internal/imctl/cmd/version/version.go @@ -21,14 +21,13 @@ import ( "fmt" "github.com/ghodss/yaml" - restclient "github.com/marmotedu/marmotedu-sdk-go/rest" "github.com/openim-sigs/component-base/pkg/json" "github.com/openim-sigs/component-base/pkg/version" "github.com/spf13/cobra" - cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/cmd/util" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/imctl/util/templates" "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/cli/genericclioptions" + cmdutil "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/pkg/util" ) // Version is a struct for version information. @@ -39,7 +38,7 @@ type Version struct { var versionExample = templates.Examples(` # Print the client and server versions for the current context - iamctl version`) + imctl version`) // Options is a struct to support version command. type Options struct { diff --git a/tools/imctl/internal/imctl/util/interrupt/interrupt.go b/tools/imctl/internal/imctl/util/interrupt/interrupt.go deleted file mode 100644 index e1d8386de..000000000 --- a/tools/imctl/internal/imctl/util/interrupt/interrupt.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package interrupt deal with signals. -package interrupt - -import ( - "os" - "os/signal" - "sync" - "syscall" -) - -// terminationSignals are signals that cause the program to exit in the -// supported platforms (linux, darwin, windows). -var terminationSignals = []os.Signal{syscall.SIGHUP, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT} - -// Handler guarantees execution of notifications after a critical section (the function passed -// to a Run method), even in the presence of process termination. It guarantees exactly once -// invocation of the provided notify functions. -type Handler struct { - notify []func() - final func(os.Signal) - once sync.Once -} - -// Chain creates a new handler that invokes all notify functions when the critical section exits -// and then invokes the optional handler's notifications. This allows critical sections to be -// nested without losing exactly once invocations. Notify functions can invoke any cleanup needed -// but should not exit (which is the responsibility of the parent handler). -func Chain(handler *Handler, notify ...func()) *Handler { - if handler == nil { - return New(nil, notify...) - } - return New(handler.Signal, append(notify, handler.Close)...) -} - -// New creates a new handler that guarantees all notify functions are run after the critical -// section exits (or is interrupted by the OS), then invokes the final handler. If no final -// handler is specified, the default final is `os.Exit(1)`. A handler can only be used for -// one critical section. -func New(final func(os.Signal), notify ...func()) *Handler { - return &Handler{ - final: final, - notify: notify, - } -} - -// Close executes all the notification handlers if they have not yet been executed. -func (h *Handler) Close() { - h.once.Do(func() { - for _, fn := range h.notify { - fn() - } - }) -} - -// Signal is called when an os.Signal is received, and guarantees that all notifications -// are executed, then the final handler is executed. This function should only be called once -// per Handler instance. -func (h *Handler) Signal(s os.Signal) { - h.once.Do(func() { - for _, fn := range h.notify { - fn() - } - if h.final == nil { - os.Exit(1) - } - h.final(s) - }) -} - -// Run ensures that any notifications are invoked after the provided fn exits (even if the -// process is interrupted by an OS termination signal). Notifications are only invoked once -// per Handler instance, so calling Run more than once will not behave as the user expects. -func (h *Handler) Run(fn func() error) error { - ch := make(chan os.Signal, 1) - signal.Notify(ch, terminationSignals...) - defer func() { - signal.Stop(ch) - close(ch) - }() - go func() { - sig, ok := <-ch - if !ok { - return - } - h.Signal(sig) - }() - defer h.Close() - return fn() -} diff --git a/tools/imctl/internal/imctl/util/templates/command_groups.go b/tools/imctl/internal/imctl/util/templates/command_groups.go deleted file mode 100644 index 538b43ac4..000000000 --- a/tools/imctl/internal/imctl/util/templates/command_groups.go +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package templates - -import ( - "github.com/spf13/cobra" -) - -type CommandGroup struct { - Message string - Commands []*cobra.Command -} - -type CommandGroups []CommandGroup - -func (g CommandGroups) Add(c *cobra.Command) { - for _, group := range g { - c.AddCommand(group.Commands...) - } -} - -func (g CommandGroups) Has(c *cobra.Command) bool { - for _, group := range g { - for _, command := range group.Commands { - if command == c { - return true - } - } - } - return false -} - -func AddAdditionalCommands(g CommandGroups, message string, cmds []*cobra.Command) CommandGroups { - group := CommandGroup{Message: message} - for _, c := range cmds { - // Don't show commands that have no short description - if !g.Has(c) && len(c.Short) != 0 { - group.Commands = append(group.Commands, c) - } - } - if len(group.Commands) == 0 { - return g - } - return append(g, group) -} diff --git a/tools/imctl/internal/imctl/util/templates/markdown.go b/tools/imctl/internal/imctl/util/templates/markdown.go deleted file mode 100644 index 5621163f8..000000000 --- a/tools/imctl/internal/imctl/util/templates/markdown.go +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package templates - -import ( - "bytes" - "fmt" - "io" - "strings" - - "github.com/russross/blackfriday" -) - -const linebreak = "\n" - -// ASCIIRenderer implements blackfriday.Renderer. -var _ blackfriday.Renderer = &ASCIIRenderer{} - -// ASCIIRenderer is a blackfriday.Renderer intended for rendering markdown -// documents as plain text, well suited for human reading on terminals. -type ASCIIRenderer struct { - Indentation string - - listItemCount uint - listLevel uint -} - -// NormalText gets a text chunk *after* the markdown syntax was already -// processed and does a final cleanup on things we don't expect here, like -// removing linebreaks on things that are not a paragraph break (auto unwrap). -func (r *ASCIIRenderer) NormalText(out *bytes.Buffer, text []byte) { - raw := string(text) - lines := strings.Split(raw, linebreak) - for _, line := range lines { - trimmed := strings.Trim(line, " \n\t") - if len(trimmed) > 0 && trimmed[0] != '_' { - out.WriteString(" ") - } - out.WriteString(trimmed) - } -} - -// List renders the start and end of a list. -func (r *ASCIIRenderer) List(out *bytes.Buffer, text func() bool, flags int) { - r.listLevel++ - out.WriteString(linebreak) - text() - r.listLevel-- -} - -// ListItem renders list items and supports both ordered and unordered lists. -func (r *ASCIIRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) { - if flags&blackfriday.LIST_ITEM_BEGINNING_OF_LIST != 0 { - r.listItemCount = 1 - } else { - r.listItemCount++ - } - indent := strings.Repeat(r.Indentation, int(r.listLevel)) - var bullet string - if flags&blackfriday.LIST_TYPE_ORDERED != 0 { - bullet += fmt.Sprintf("%d.", r.listItemCount) - } else { - bullet += "*" - } - out.WriteString(indent + bullet + " ") - r.fw(out, text) - out.WriteString(linebreak) -} - -// Paragraph renders the start and end of a paragraph. -func (r *ASCIIRenderer) Paragraph(out *bytes.Buffer, text func() bool) { - out.WriteString(linebreak) - text() - out.WriteString(linebreak) -} - -// BlockCode renders a chunk of text that represents source code. -func (r *ASCIIRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) { - out.WriteString(linebreak) - lines := []string{} - for _, line := range strings.Split(string(text), linebreak) { - indented := r.Indentation + line - lines = append(lines, indented) - } - out.WriteString(strings.Join(lines, linebreak)) -} - -func (r *ASCIIRenderer) GetFlags() int { return 0 } -func (r *ASCIIRenderer) HRule(out *bytes.Buffer) { - out.WriteString(linebreak + "----------" + linebreak) -} -func (r *ASCIIRenderer) LineBreak(out *bytes.Buffer) { out.WriteString(linebreak) } -func (r *ASCIIRenderer) TitleBlock(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) { text() } -func (r *ASCIIRenderer) BlockHtml(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) BlockQuote(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) TableRow(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { r.fw(out, text) } -func (r *ASCIIRenderer) TableCell(out *bytes.Buffer, text []byte, align int) { r.fw(out, text) } -func (r *ASCIIRenderer) Footnotes(out *bytes.Buffer, text func() bool) { text() } -func (r *ASCIIRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { - r.fw(out, text) -} -func (r *ASCIIRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) { r.fw(out, link) } -func (r *ASCIIRenderer) CodeSpan(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) Emphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) RawHtmlTag(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) StrikeThrough(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { r.fw(out, ref) } -func (r *ASCIIRenderer) Entity(out *bytes.Buffer, entity []byte) { r.fw(out, entity) } -func (r *ASCIIRenderer) Smartypants(out *bytes.Buffer, text []byte) { r.fw(out, text) } -func (r *ASCIIRenderer) DocumentHeader(out *bytes.Buffer) {} -func (r *ASCIIRenderer) DocumentFooter(out *bytes.Buffer) {} -func (r *ASCIIRenderer) TocHeaderWithAnchor(text []byte, level int, anchor string) {} -func (r *ASCIIRenderer) TocHeader(text []byte, level int) {} -func (r *ASCIIRenderer) TocFinalize() {} - -func (r *ASCIIRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) { - r.fw(out, header, body) -} - -func (r *ASCIIRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) { - out.WriteString(" ") - r.fw(out, link) -} - -func (r *ASCIIRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) { - r.fw(out, link) -} - -func (r *ASCIIRenderer) fw(out io.Writer, text ...[]byte) { - for _, t := range text { - out.Write(t) - } -} diff --git a/tools/imctl/internal/imctl/util/templates/normalizers.go b/tools/imctl/internal/imctl/util/templates/normalizers.go deleted file mode 100644 index f5873a0be..000000000 --- a/tools/imctl/internal/imctl/util/templates/normalizers.go +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package templates - -import ( - "strings" - - "github.com/MakeNowJust/heredoc/v2" - "github.com/russross/blackfriday" - "github.com/spf13/cobra" -) - -const Indentation = ` ` - -// LongDesc normalizes a command's long description to follow the conventions. -func LongDesc(s string) string { - if len(s) == 0 { - return s - } - return normalizer{s}.heredoc().markdown().trim().string -} - -// Examples normalizes a command's examples to follow the conventions. -func Examples(s string) string { - if len(s) == 0 { - return s - } - return normalizer{s}.trim().indent().string -} - -// Normalize perform all required normalizations on a given command. -func Normalize(cmd *cobra.Command) *cobra.Command { - if len(cmd.Long) > 0 { - cmd.Long = LongDesc(cmd.Long) - } - if len(cmd.Example) > 0 { - cmd.Example = Examples(cmd.Example) - } - return cmd -} - -// NormalizeAll perform all required normalizations in the entire command tree. -func NormalizeAll(cmd *cobra.Command) *cobra.Command { - if cmd.HasSubCommands() { - for _, subCmd := range cmd.Commands() { - NormalizeAll(subCmd) - } - } - Normalize(cmd) - return cmd -} - -type normalizer struct { - string -} - -func (s normalizer) markdown() normalizer { - bytes := []byte(s.string) - formatted := blackfriday.Markdown( - bytes, - &ASCIIRenderer{Indentation: Indentation}, - blackfriday.EXTENSION_NO_INTRA_EMPHASIS, - ) - s.string = string(formatted) - return s -} - -func (s normalizer) heredoc() normalizer { - s.string = heredoc.Doc(s.string) - return s -} - -func (s normalizer) trim() normalizer { - s.string = strings.TrimSpace(s.string) - return s -} - -func (s normalizer) indent() normalizer { - indentedLines := []string{} - for _, line := range strings.Split(s.string, "\n") { - trimmed := strings.TrimSpace(line) - indented := Indentation + trimmed - indentedLines = append(indentedLines, indented) - } - s.string = strings.Join(indentedLines, "\n") - return s -} diff --git a/tools/imctl/internal/imctl/util/templates/templater.go b/tools/imctl/internal/imctl/util/templates/templater.go deleted file mode 100644 index 7b75cef13..000000000 --- a/tools/imctl/internal/imctl/util/templates/templater.go +++ /dev/null @@ -1,296 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package templates - -import ( - "bytes" - "fmt" - "strings" - "text/template" - "unicode" - - "github.com/spf13/cobra" - flag "github.com/spf13/pflag" - - "github.com/OpenIMSDK/Open-IM-Server/tools/imctl/internal/util/term" -) - -type FlagExposer interface { - ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer -} - -func ActsAsRootCommand(cmd *cobra.Command, filters []string, groups ...CommandGroup) FlagExposer { - if cmd == nil { - panic("nil root command") - } - templater := &templater{ - RootCmd: cmd, - UsageTemplate: MainUsageTemplate(), - HelpTemplate: MainHelpTemplate(), - CommandGroups: groups, - Filtered: filters, - } - cmd.SetFlagErrorFunc(templater.FlagErrorFunc()) - cmd.SilenceUsage = true - cmd.SetUsageFunc(templater.UsageFunc()) - cmd.SetHelpFunc(templater.HelpFunc()) - return templater -} - -func UseOptionsTemplates(cmd *cobra.Command) { - templater := &templater{ - UsageTemplate: OptionsUsageTemplate(), - HelpTemplate: OptionsHelpTemplate(), - } - cmd.SetUsageFunc(templater.UsageFunc()) - cmd.SetHelpFunc(templater.HelpFunc()) -} - -type templater struct { - UsageTemplate string - HelpTemplate string - RootCmd *cobra.Command - CommandGroups - Filtered []string -} - -func (t *templater) FlagErrorFunc(exposedFlags ...string) func(*cobra.Command, error) error { - return func(c *cobra.Command, err error) error { - c.SilenceUsage = true - switch c.CalledAs() { - case "options": - return fmt.Errorf("%s\nrun '%s' without flags", err, c.CommandPath()) - default: - return fmt.Errorf("%s\nsee '%s --help' for usage", err, c.CommandPath()) - } - } -} - -func (t *templater) ExposeFlags(cmd *cobra.Command, flags ...string) FlagExposer { - cmd.SetUsageFunc(t.UsageFunc(flags...)) - return t -} - -func (t *templater) HelpFunc() func(*cobra.Command, []string) { - return func(c *cobra.Command, s []string) { - tt := template.New("help") - tt.Funcs(t.templateFuncs()) - template.Must(tt.Parse(t.HelpTemplate)) - out := term.NewResponsiveWriter(c.OutOrStdout()) - err := tt.Execute(out, c) - if err != nil { - c.Println(err) - } - } -} - -func (t *templater) UsageFunc(exposedFlags ...string) func(*cobra.Command) error { - return func(c *cobra.Command) error { - tt := template.New("usage") - tt.Funcs(t.templateFuncs(exposedFlags...)) - template.Must(tt.Parse(t.UsageTemplate)) - out := term.NewResponsiveWriter(c.OutOrStderr()) - return tt.Execute(out, c) - } -} - -func (t *templater) templateFuncs(exposedFlags ...string) template.FuncMap { - return template.FuncMap{ - "trim": strings.TrimSpace, - "trimRight": func(s string) string { return strings.TrimRightFunc(s, unicode.IsSpace) }, - "trimLeft": func(s string) string { return strings.TrimLeftFunc(s, unicode.IsSpace) }, - "gt": cobra.Gt, - "eq": cobra.Eq, - "rpad": rpad, - "appendIfNotPresent": appendIfNotPresent, - "flagsNotIntersected": flagsNotIntersected, - "visibleFlags": visibleFlags, - "flagsUsages": flagsUsages, - "cmdGroups": t.cmdGroups, - "cmdGroupsString": t.cmdGroupsString, - "rootCmd": t.rootCmdName, - "isRootCmd": t.isRootCmd, - "optionsCmdFor": t.optionsCmdFor, - "usageLine": t.usageLine, - "exposed": func(c *cobra.Command) *flag.FlagSet { - exposed := flag.NewFlagSet("exposed", flag.ContinueOnError) - if len(exposedFlags) > 0 { - for _, name := range exposedFlags { - if flag := c.Flags().Lookup(name); flag != nil { - exposed.AddFlag(flag) - } - } - } - return exposed - }, - } -} - -func (t *templater) cmdGroups(c *cobra.Command, all []*cobra.Command) []CommandGroup { - if len(t.CommandGroups) > 0 && c == t.RootCmd { - all = filter(all, t.Filtered...) - return AddAdditionalCommands(t.CommandGroups, "Other Commands:", all) - } - all = filter(all, "options") - return []CommandGroup{ - { - Message: "Available Commands:", - Commands: all, - }, - } -} - -func (t *templater) cmdGroupsString(c *cobra.Command) string { - groups := []string{} - for _, cmdGroup := range t.cmdGroups(c, c.Commands()) { - cmds := []string{cmdGroup.Message} - for _, cmd := range cmdGroup.Commands { - if cmd.IsAvailableCommand() { - cmds = append(cmds, " "+rpad(cmd.Name(), cmd.NamePadding())+" "+cmd.Short) - } - } - groups = append(groups, strings.Join(cmds, "\n")) - } - return strings.Join(groups, "\n\n") -} - -func (t *templater) rootCmdName(c *cobra.Command) string { - return t.rootCmd(c).CommandPath() -} - -func (t *templater) isRootCmd(c *cobra.Command) bool { - return t.rootCmd(c) == c -} - -func (t *templater) parents(c *cobra.Command) []*cobra.Command { - parents := []*cobra.Command{c} - for current := c; !t.isRootCmd(current) && current.HasParent(); { - current = current.Parent() - parents = append(parents, current) - } - return parents -} - -func (t *templater) rootCmd(c *cobra.Command) *cobra.Command { - if c != nil && !c.HasParent() { - return c - } - if t.RootCmd == nil { - panic("nil root cmd") - } - return t.RootCmd -} - -func (t *templater) optionsCmdFor(c *cobra.Command) string { - if !c.Runnable() { - return "" - } - rootCmdStructure := t.parents(c) - for i := len(rootCmdStructure) - 1; i >= 0; i-- { - cmd := rootCmdStructure[i] - if _, _, err := cmd.Find([]string{"options"}); err == nil { - return cmd.CommandPath() + " options" - } - } - return "" -} - -func (t *templater) usageLine(c *cobra.Command) string { - usage := c.UseLine() - suffix := "[options]" - if c.HasFlags() && !strings.Contains(usage, suffix) { - usage += " " + suffix - } - return usage -} - -func flagsUsages(f *flag.FlagSet) string { - x := new(bytes.Buffer) - - f.VisitAll(func(flag *flag.Flag) { - if flag.Hidden { - return - } - format := "--%s=%s: %s\n" - - if flag.Value.Type() == "string" { - format = "--%s='%s': %s\n" - } - - if len(flag.Shorthand) > 0 { - format = " -%s, " + format - } else { - format = " %s " + format - } - - fmt.Fprintf(x, format, flag.Shorthand, flag.Name, flag.DefValue, flag.Usage) - }) - - return x.String() -} - -func rpad(s string, padding int) string { - template := fmt.Sprintf("%%-%ds", padding) - return fmt.Sprintf(template, s) -} - -func appendIfNotPresent(s, stringToAppend string) string { - if strings.Contains(s, stringToAppend) { - return s - } - return s + " " + stringToAppend -} - -func flagsNotIntersected(l *flag.FlagSet, r *flag.FlagSet) *flag.FlagSet { - f := flag.NewFlagSet("notIntersected", flag.ContinueOnError) - l.VisitAll(func(flag *flag.Flag) { - if r.Lookup(flag.Name) == nil { - f.AddFlag(flag) - } - }) - return f -} - -func visibleFlags(l *flag.FlagSet) *flag.FlagSet { - hidden := "help" - f := flag.NewFlagSet("visible", flag.ContinueOnError) - l.VisitAll(func(flag *flag.Flag) { - if flag.Name != hidden { - f.AddFlag(flag) - } - }) - return f -} - -func filter(cmds []*cobra.Command, names ...string) []*cobra.Command { - out := []*cobra.Command{} - for _, c := range cmds { - if c.Hidden { - continue - } - skip := false - for _, name := range names { - if name == c.Name() { - skip = true - break - } - } - if skip { - continue - } - out = append(out, c) - } - return out -} diff --git a/tools/imctl/internal/imctl/util/templates/templates.go b/tools/imctl/internal/imctl/util/templates/templates.go deleted file mode 100644 index ec71434ce..000000000 --- a/tools/imctl/internal/imctl/util/templates/templates.go +++ /dev/null @@ -1,103 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package templates provides template functions for working with templates. -package templates - -import ( - "strings" - "unicode" -) - -const ( - // SectionVars is the help template section that declares variables to be used in the template. - SectionVars = `{{$isRootCmd := isRootCmd .}}` + - `{{$rootCmd := rootCmd .}}` + - `{{$visibleFlags := visibleFlags (flagsNotIntersected .LocalFlags .PersistentFlags)}}` + - `{{$explicitlyExposedFlags := exposed .}}` + - `{{$optionsCmdFor := optionsCmdFor .}}` + - `{{$usageLine := usageLine .}}` - - // SectionAliases is the help template section that displays command aliases. - SectionAliases = `{{if gt .Aliases 0}}Aliases: -{{.NameAndAliases}} - -{{end}}` - - // SectionExamples is the help template section that displays command examples. - SectionExamples = `{{if .HasExample}}Examples: -{{trimRight .Example}} - -{{end}}` - - // SectionSubcommands is the help template section that displays the command's subcommands. - SectionSubcommands = `{{if .HasAvailableSubCommands}}{{cmdGroupsString .}} - -{{end}}` - - // SectionFlags is the help template section that displays the command's flags. - SectionFlags = `{{ if or $visibleFlags.HasFlags $explicitlyExposedFlags.HasFlags}}Options: -{{ if $visibleFlags.HasFlags}}{{trimRight (flagsUsages $visibleFlags)}}{{end}}{{ if $explicitlyExposedFlags.HasFlags}}{{ if $visibleFlags.HasFlags}} -{{end}}{{trimRight (flagsUsages $explicitlyExposedFlags)}}{{end}} - -{{end}}` - - // SectionUsage is the help template section that displays the command's usage. - SectionUsage = `{{if and .Runnable (ne .UseLine "") (ne .UseLine $rootCmd)}}Usage: - {{$usageLine}} - -{{end}}` - - // SectionTipsHelp is the help template section that displays the '--help' hint. - SectionTipsHelp = `{{if .HasSubCommands}}Use "{{$rootCmd}} --help" for more information about a given command. -{{end}}` - - // SectionTipsGlobalOptions is the help template section that displays the 'options' hint for displaying global - // flags. - SectionTipsGlobalOptions = `{{if $optionsCmdFor}}Use "{{$optionsCmdFor}}" for a list of global command-line options (applies to all commands). -{{end}}` -) - -// MainHelpTemplate if the template for 'help' used by most commands. -func MainHelpTemplate() string { - return `{{with or .Long .Short }}{{. | trim}}{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` -} - -// MainUsageTemplate if the template for 'usage' used by most commands. -func MainUsageTemplate() string { - sections := []string{ - "\n\n", - SectionVars, - SectionAliases, - SectionExamples, - SectionSubcommands, - SectionFlags, - SectionUsage, - SectionTipsHelp, - SectionTipsGlobalOptions, - } - return strings.TrimRightFunc(strings.Join(sections, ""), unicode.IsSpace) -} - -// OptionsHelpTemplate if the template for 'help' used by the 'options' command. -func OptionsHelpTemplate() string { - return "" -} - -// OptionsUsageTemplate if the template for 'usage' used by the 'options' command. -func OptionsUsageTemplate() string { - return `{{ if .HasInheritedFlags}}The following options can be passed to any command: - -{{flagsUsages .InheritedFlags}}{{end}}` -} diff --git a/tools/imctl/internal/imctl/util/term/resize.go b/tools/imctl/internal/imctl/util/term/resize.go deleted file mode 100644 index 0063d0723..000000000 --- a/tools/imctl/internal/imctl/util/term/resize.go +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package term - -import ( - "github.com/moby/term" -) - -// TerminalSize represents the width and height of a terminal. -type TerminalSize struct { - Width uint16 - Height uint16 -} - -// TerminalSizeQueue is capable of returning terminal resize events as they occur. -type TerminalSizeQueue interface { - // Next returns the new terminal size after the terminal has been resized. It returns nil when - // monitoring has been stopped. - Next() *TerminalSize -} - -// GetSize returns the current size of the user's terminal. If it isn't a terminal, -// nil is returned. -func (t TTY) GetSize() *TerminalSize { - outFd, isTerminal := term.GetFdInfo(t.Out) - if !isTerminal { - return nil - } - return GetSize(outFd) -} - -// GetSize returns the current size of the terminal associated with fd. -func GetSize(fd uintptr) *TerminalSize { - winsize, err := term.GetWinsize(fd) - if err != nil { - // runtime.HandleError(fmt.Errorf("unable to get terminal size: %v", err)) - return nil - } - - return &TerminalSize{Width: winsize.Width, Height: winsize.Height} -} diff --git a/tools/imctl/internal/imctl/util/term/term.go b/tools/imctl/internal/imctl/util/term/term.go deleted file mode 100644 index 45c820384..000000000 --- a/tools/imctl/internal/imctl/util/term/term.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// Package term provides structures and helper functions to work with -// terminal (state, sizes). -package term - -import ( - "io" -) - -// TTY helps invoke a function and preserve the state of the terminal, even if the process is -// terminated during execution. It also provides support for terminal resizing for remote command -// execution/attachment. -type TTY struct { - // In is a reader representing stdin. It is a required field. - In io.Reader - // Out is a writer representing stdout. It must be set to support terminal resizing. It is an - // optional field. - Out io.Writer - // Raw is true if the terminal should be set raw. - Raw bool - // TryDev indicates the TTY should try to open /dev/tty if the provided input - // is not a file descriptor. - TryDev bool -} diff --git a/tools/imctl/internal/imctl/util/term/term_writer.go b/tools/imctl/internal/imctl/util/term/term_writer.go deleted file mode 100644 index 700a223af..000000000 --- a/tools/imctl/internal/imctl/util/term/term_writer.go +++ /dev/null @@ -1,124 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package term - -import ( - "io" - "os" - - wordwrap "github.com/mitchellh/go-wordwrap" - "github.com/moby/term" -) - -type wordWrapWriter struct { - limit uint - writer io.Writer -} - -// NewResponsiveWriter creates a Writer that detects the column width of the -// terminal we are in, and adjusts every line width to fit and use recommended -// terminal sizes for better readability. Does proper word wrapping automatically. -// -// if terminal width >= 120 columns use 120 columns -// if terminal width >= 100 columns use 100 columns -// if terminal width >= 80 columns use 80 columns -// -// In case we're not in a terminal or if it's smaller than 80 columns width, -// doesn't do any wrapping. -func NewResponsiveWriter(w io.Writer) io.Writer { - file, ok := w.(*os.File) - if !ok { - return w - } - fd := file.Fd() - if !term.IsTerminal(fd) { - return w - } - - terminalSize := GetSize(fd) - if terminalSize == nil { - return w - } - - var limit uint - switch { - case terminalSize.Width >= 120: - limit = 120 - case terminalSize.Width >= 100: - limit = 100 - case terminalSize.Width >= 80: - limit = 80 - } - - return NewWordWrapWriter(w, limit) -} - -// NewWordWrapWriter is a Writer that supports a limit of characters on every line -// and does auto word wrapping that respects that limit. -func NewWordWrapWriter(w io.Writer, limit uint) io.Writer { - return &wordWrapWriter{ - limit: limit, - writer: w, - } -} - -func (w wordWrapWriter) Write(p []byte) (nn int, err error) { - if w.limit == 0 { - return w.writer.Write(p) - } - original := string(p) - wrapped := wordwrap.WrapString(original, w.limit) - return w.writer.Write([]byte(wrapped)) -} - -// NewPunchCardWriter is a NewWordWrapWriter that limits the line width to 80 columns. -func NewPunchCardWriter(w io.Writer) io.Writer { - return NewWordWrapWriter(w, 80) -} - -type maxWidthWriter struct { - maxWidth uint - currentWidth uint - written uint - writer io.Writer -} - -// NewMaxWidthWriter is a Writer that supports a limit of characters on every -// line, but doesn't do any word wrapping automatically. -func NewMaxWidthWriter(w io.Writer, maxWidth uint) io.Writer { - return &maxWidthWriter{ - maxWidth: maxWidth, - writer: w, - } -} - -func (m maxWidthWriter) Write(p []byte) (nn int, err error) { - for _, b := range p { - if m.currentWidth == m.maxWidth { - m.writer.Write([]byte{'\n'}) - m.currentWidth = 0 - } - if b == '\n' { - m.currentWidth = 0 - } - _, err := m.writer.Write([]byte{b}) - if err != nil { - return int(m.written), err - } - m.written++ - m.currentWidth++ - } - return len(p), nil -} diff --git a/tools/imctl/internal/imctl/util/term/term_writer_test.go b/tools/imctl/internal/imctl/util/term/term_writer_test.go deleted file mode 100644 index 588ba3418..000000000 --- a/tools/imctl/internal/imctl/util/term/term_writer_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright © 2023 OpenIM. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package term - -import ( - "bytes" - "strings" - "testing" -) - -const test = "Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam Iam" - -func TestWordWrapWriter(t *testing.T) { - testcases := map[string]struct { - input string - maxWidth uint - }{ - "max 10": {input: test, maxWidth: 10}, - "max 80": {input: test, maxWidth: 80}, - "max 120": {input: test, maxWidth: 120}, - "max 5000": {input: test, maxWidth: 5000}, - } - for k, tc := range testcases { - b := bytes.NewBufferString("") - w := NewWordWrapWriter(b, tc.maxWidth) - _, err := w.Write([]byte(tc.input)) - if err != nil { - t.Errorf("%s: Unexpected error: %v", k, err) - } - result := b.String() - if !strings.Contains(result, "Iam") { - t.Errorf("%s: Expected to contain \"Iam\"", k) - } - if len(result) < len(tc.input) { - t.Errorf( - "%s: Unexpectedly short string, got %d wanted at least %d chars: %q", - k, - len(result), - len(tc.input), - result, - ) - } - for _, line := range strings.Split(result, "\n") { - if len(line) > int(tc.maxWidth) { - t.Errorf("%s: Every line must be at most %d chars long, got %d: %q", k, tc.maxWidth, len(line), line) - } - } - for _, word := range strings.Split(result, " ") { - if !strings.Contains(word, "Iam") { - t.Errorf("%s: Unexpected broken word: %q", k, word) - } - } - } -} - -func TestMaxWidthWriter(t *testing.T) { - testcases := map[string]struct { - input string - maxWidth uint - }{ - "max 10": {input: test, maxWidth: 10}, - "max 80": {input: test, maxWidth: 80}, - "max 120": {input: test, maxWidth: 120}, - "max 5000": {input: test, maxWidth: 5000}, - } - for k, tc := range testcases { - b := bytes.NewBufferString("") - w := NewMaxWidthWriter(b, tc.maxWidth) - _, err := w.Write([]byte(tc.input)) - if err != nil { - t.Errorf("%s: Unexpected error: %v", k, err) - } - result := b.String() - if !strings.Contains(result, "Iam") { - t.Errorf("%s: Expected to contain \"Iam\"", k) - } - if len(result) < len(tc.input) { - t.Errorf( - "%s: Unexpectedly short string, got %d wanted at least %d chars: %q", - k, - len(result), - len(tc.input), - result, - ) - } - lines := strings.Split(result, "\n") - for i, line := range lines { - if len(line) > int(tc.maxWidth) { - t.Errorf("%s: Every line must be at most %d chars long, got %d: %q", k, tc.maxWidth, len(line), line) - } - if i < len(lines)-1 && len(line) != int(tc.maxWidth) { - t.Errorf( - "%s: Lines except the last one are expected to be exactly %d chars long, got %d: %q", - k, - tc.maxWidth, - len(line), - line, - ) - } - } - } -}