Skip to content
Merged
34 changes: 34 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,40 @@ Then copy the `./bin/swctl-latest-(darwin|linux|windows)-amd64` to your `PATH` d

You can also copy it to any directory you like, then add that directory to `PATH`. **We recommend you to rename the `swctl-latest-(darwin|linux|windows)-amd64` to `swctl`.**

## Autocompletion

`swctl` provides auto-completion support for bash and powershell, which can save you a lot of typing.

### Bash

The swctl completion script for bash can be generated with the command `swctl completion bash`. Sourcing the completion script in your shell enables swctl auto-completion:

```shell
swctl completion bash > bash_autocomplete &&
sudo cp ./bash_autocomplete /etc/bash_completion.d/swctl &&
echo >> ~/.bashrc &&
echo "export PROG=swctl" >> ~/.bashrc
```

After reloading your shell, swctl auto-completion should be working.

### powershell

Similarly, run the following command in your powershell terminal to enable auto-completion:

```shell
set-executionpolicy remotesigned -Scope CurrentUser
swctl completion powershell >> $profile
```

If you get an error like `OpenError: (:) [Out-File], DirectoryNotFoundException`, then you need to run the following command to create `$profile` file:

```shell
New-Item -Type file -Force $profile
```

After reloading your shell, swctl auto-completion should be working.


# Commands
Commands in SkyWalking CLI are organized into two levels, in the form of `swctl --option <level1> --option <level2> --option`,
Expand Down
8 changes: 8 additions & 0 deletions cmd/swctl/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"io/ioutil"
"os"

"github.com/apache/skywalking-cli/internal/commands/completion"
"github.com/apache/skywalking-cli/internal/commands/dashboard"
"github.com/apache/skywalking-cli/internal/commands/dependency"
"github.com/apache/skywalking-cli/internal/commands/endpoint"
Expand Down Expand Up @@ -125,6 +126,7 @@ func main() {
event.Command,
logs.Command,
profile.Command,
completion.Command,
dependency.Command,
}

Expand All @@ -137,6 +139,12 @@ func main() {
app.Flags = flags
app.CommandNotFound = util.CommandNotFound

// Enable auto-completion.
app.EnableBashCompletion = true
cli.BashCompletionFlag = cli.BoolFlag{
Name: "auto_complete",
Hidden: true,
}
if err := app.Run(os.Args); err != nil {
log.Fatalln(err)
}
Expand Down
58 changes: 58 additions & 0 deletions internal/commands/completion/bash.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 completion

import (
"fmt"

"github.com/urfave/cli"
)

var bashCommand = cli.Command{
Name: "bash",
Aliases: []string{"b"},
Usage: "Output shell completion code for bash",
ArgsUsage: "[parameters...]",
Action: func(ctx *cli.Context) error {
fmt.Print(bashScript)
return nil
},
}

const bashScript = `
: ${PROG:=$(basename ${BASH_SOURCE})}

_cli_bash_autocomplete() {
if [[ "${COMP_WORDS[0]}" != "source" ]]; then
local cur opts base
COMPREPLY=()
cur="${COMP_WORDS[COMP_CWORD]}"
if [[ "$cur" == "-"* ]]; then
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} ${cur} --auto_complete )
else
opts=$( ${COMP_WORDS[@]:0:$COMP_CWORD} --auto_complete )
fi
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
return 0
fi
}

complete -o bashdefault -o default -o nospace -F _cli_bash_autocomplete $PROG
unset PROG

`
31 changes: 31 additions & 0 deletions internal/commands/completion/completion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 completion

import (
"github.com/urfave/cli"
)

var Command = cli.Command{
Name: "completion",
Usage: "Output shell completion code for bash and powershell",
Subcommands: []cli.Command{
bashCommand,
powershellCommand,
},
}
71 changes: 71 additions & 0 deletions internal/commands/completion/powershell.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// Licensed to Apache Software Foundation (ASF) under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Apache Software Foundation (ASF) licenses this file to you 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 completion

import (
"fmt"

"github.com/urfave/cli"
)

var powershellCommand = cli.Command{
Name: "powershell",
Aliases: []string{"p"},
Usage: "Output shell completion code for powershell",
ArgsUsage: "[parameters...]",
Action: func(ctx *cli.Context) error {
fmt.Print(powershellScript)
return nil
},
}

const powershellScript = `
Register-ArgumentCompleter -Native -CommandName swctl -ScriptBlock {
param($commandName, $commands, $cursorPosition)

$match = $($(complete $commands $cursorPosition) -split " ")
# Output matched commands one by one.
for($i=0; $i -lt ($match.Length-1); $i+=1){
Write-Output $match[$i]
}
}
# Find all matching commands.
function complete($commands, $cursorPosition){
# Get command line parameters.
$parameters = $($commands -split " ")
# Uncompleted parameters.
$uncomplete = $parameters[-1]

# Get the parameters before $uncomplete.
$len = $parameters.Length-2
if ("$commands".Length -ne $cursorPosition) { return "" }
$beforeCommands = $parameters[0..($len)]

# Find the command prefixed with $uncomplete.
$match = ""
Invoke-Expression "$beforeCommands --auto_complete" | ForEach-Object {
$flag = 1
for ($i=0; $i -lt $uncomplete.Length; $i = $i +1){
if ($_[$i] -ne $uncomplete[$i]) { $flag = 0 }
}
if ($flag -eq 1) { $match+="$_ " }
}
return $match
}

`