Skip to content

Commit 302b8fd

Browse files
committed
add global flag --profile & add 'ucloud ext'
1 parent 7027140 commit 302b8fd

840 files changed

Lines changed: 272258 additions & 142 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Dockerfile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
FROM ubuntu:18.04
2+
RUN apt-get update && apt-get install wget -y
3+
RUN wget https://github.com/ucloud/ucloud-cli/releases/download/0.1.20/ucloud-cli-linux-0.1.20-amd64.tgz
4+
RUN tar -zxf ucloud-cli-linux-0.1.20-amd64.tgz -C /usr/local/bin/
5+
RUN echo "complete -C $(which ucloud) ucloud" >> ~/.bashrc

Makefile

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
export VERSION=0.1.20
22

3-
.PHONY : build
4-
build:
5-
go install && mv ${GOPATH}/bin/ucloud-cli /usr/local/bin/ucloud
3+
.PHONY : install
4+
install:
5+
go build -i -v -mod=vendor -o out/ucloud main.go
6+
cp out/ucloud /usr/local/bin
67

78
.PHONY : build_mac
89
build_mac:
@@ -25,7 +26,3 @@ build_windows:
2526
.PHONY : build_all
2627
build_all: build_mac build_linux build_windows
2728

28-
.PHONY : install
29-
install:
30-
go build -o out/ucloud main.go
31-
cp out/ucloud /usr/local/bin

README.md

Lines changed: 55 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,58 +5,99 @@
55
The UCloud CLI provides a unified command line interface to UCloud services. It works on Golang SDK based on UCloud OpenAPI and supports Linux, macOS and Windows.
66
https://docs.ucloud.cn/software/cli/index
77

8-
## Installing ucloud-cli
8+
## Installing ucloud-cli on macOS or Linux
99

1010
**Using Homebrew(Preferred)**
1111

12-
The [Homebrew](https://docs.brew.sh/Installation) package manager may be used on macOS, Linux and Windows Subsystem for Linux (WSL).
12+
The [Homebrew](https://docs.brew.sh/Installation) package manager may be used on macOS and Linux.
1313
It could install ucloud-cli and its dependencies automatically by running command below.
1414

1515
```
16-
$ brew install ucloud
16+
brew install ucloud
1717
```
1818

1919
If you have installed ucloud-cli already and want to upgrade to the latest version, just run:
2020

2121
```
22-
$ brew upgrade ucloud
22+
brew upgrade ucloud
2323
```
2424

2525
If you come across some errors during the installation via homebrew, please update the homebrew first and try again.
2626

2727
```
28-
$ brew update
28+
brew update
2929
```
3030

3131
If the error is still unresolved, try the following command for help.
3232

3333
```
34-
$ brew doctor
34+
brew doctor
3535
```
3636

3737
**Building from source**
3838

3939
If you have installed git and golang on your platform, you can fetch the source code of ucloud cli from github and complie it by yourself.
4040

4141
```
42-
$ git clone https://github.com/ucloud/ucloud-cli.git
43-
$ cd ucloud-cli
44-
$ make install
42+
git clone https://github.com/ucloud/ucloud-cli.git
43+
cd ucloud-cli
44+
make install
4545
```
4646

4747
**Downloading binary release**
4848

49-
Vist the [Releases page](https://github.com/ucloud/ucloud-cli/releases) of ucloud cli, and find the appropriate archive for your operating system and architecture.
49+
Vist the [releases page](https://github.com/ucloud/ucloud-cli/releases) of ucloud cli, and find the appropriate archive for your operating system and architecture.
5050
Download the archive , check the shasum256 hashcode and extract it to your $PATH
5151

5252
For example
5353
```
54-
curl -OL https://github.com/ucloud/ucloud-cli/releases/download/0.1.14/ucloud-cli-macosx-0.1.14-amd64.tgz
55-
echo "6953232b20f3474973cf234218097006a2e0d1d049c115da6c0e09c103762d4d *ucloud-cli-macosx-0.1.14-amd64.tgz" | shasum -c
56-
tar zxf ucloud-cli-macosx-0.1.14-amd64.tgz -C /usr/local/bin/
54+
curl -OL https://github.com/ucloud/ucloud-cli/releases/download/0.1.20/ucloud-cli-macosx-0.1.20-amd64.tgz
55+
echo "6953232b20f3474973cf234218097006a2e0d1d049c115da6c0e09c103762d4d *ucloud-cli-macosx-0.1.20-amd64.tgz" | shasum -c
56+
tar zxf ucloud-cli-macosx-0.1.20-amd64.tgz -C /usr/local/bin/
5757
```
5858

59-
## Enabling Shell Auto-Completion
59+
## Installing ucloud cli on Windows
60+
61+
**Building from source**
62+
63+
Download the source code of ucloud cli from [releases page](https://github.com/ucloud/ucloud-cli/releases). You can also download it by running ```git clone https://github.com/ucloud/ucloud-cli.git```
64+
Ensure you have git installed, because go will download packages using git. Go to the directory of the source code, and then compile the source code by running "go build -o ucloud.exe"
65+
After that add ucloud.exe to your environment variable PATH. You could follow [this document](https://www.java.com/en/download/help/path.xml) if you don't know how to do.
66+
Open CMD Terminal and run ```ucloud --version ``` to test installation.
67+
68+
69+
**Downloading binary release**
70+
71+
Vist the [releases page](https://github.com/ucloud/ucloud-cli/releases) of ucloud cli, and find the appropriate archive for your operating system and architecture.
72+
Download the archive , and extract it. Add binary file ucloud.exe to your environment variable PATH following [this document](https://www.java.com/en/download/help/path.xml)
73+
74+
## Using ucloud cli in a Docker container
75+
If you have installed docker on your platform, pull the docker image embeded ucloud cli by follow command.
76+
```
77+
docker pull uhub.service.ucloud.cn/ucloudcli/ucloud-cli:0.1.20
78+
```
79+
80+
The docker image was built by the Dockerfile as follow.
81+
```
82+
FROM ubuntu:18.04
83+
RUN apt-get update && apt-get install wget -y
84+
RUN wget https://github.com/ucloud/ucloud-cli/releases/download/0.1.20/ucloud-cli-linux-0.1.20-amd64.tgz
85+
RUN tar -zxf ucloud-cli-linux-0.1.20-amd64.tgz -C /usr/local/bin/
86+
RUN echo "complete -C $(which ucloud) ucloud" >> ~/.bashrc #enable auto completion
87+
```
88+
89+
Create a docker container named ucloud-cli using the docker image your have pulled by following command.
90+
91+
```
92+
docker run --name ucloud-cli -it -d uhub.service.ucloud.cn/ucloudcli/ucloud-cli:0.1.20
93+
```
94+
Run bash command in ucloud-cli container, and then you could play with ucloud cli.
95+
96+
```
97+
docker exec -it ucloud-cli bash
98+
```
99+
100+
## Enabling Shell Auto-Completion for bash or zsh shell user.
60101

61102
UCloud CLI also has auto-completion support. It can be set up so that if you partially type a command and then press TAB, the rest of the command is automatically filled in.
62103

base/config.go

Lines changed: 88 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package base
33
import (
44
"encoding/json"
55
"fmt"
6-
"io"
76
"io/ioutil"
87
"os"
98
"strings"
@@ -21,6 +20,9 @@ var ConfigFilePath = fmt.Sprintf("%s/%s", GetConfigDir(), "config.json")
2120
//CredentialFilePath path of credential.json
2221
var CredentialFilePath = fmt.Sprintf("%s/%s", GetConfigDir(), "credential.json")
2322

23+
//LocalFileMode file mode of $HOME/ucloud/*
24+
const LocalFileMode os.FileMode = 0600
25+
2426
//DefaultTimeoutSec default timeout for requesting api, 15s
2527
const DefaultTimeoutSec = 15
2628

@@ -34,7 +36,11 @@ const DefaultProfile = "default"
3436
const Version = "0.1.20"
3537

3638
//ConfigIns 配置实例, 程序加载时生成
37-
var ConfigIns = &AggConfig{Profile: "default"}
39+
var ConfigIns = &AggConfig{
40+
Profile: DefaultProfile,
41+
BaseURL: DefaultBaseURL,
42+
Timeout: DefaultTimeoutSec,
43+
}
3844

3945
//AggConfigListIns 配置列表, 进程启动时从本地文件加载
4046
var AggConfigListIns = &AggConfigManager{}
@@ -59,6 +65,7 @@ type GlobalFlag struct {
5965
Completion bool
6066
Config bool
6167
Signup bool
68+
Profile string
6269
}
6370

6471
//CLIConfig cli_config element
@@ -162,17 +169,16 @@ func (p *AggConfig) copyToCredentialConfig(target *CredentialConfig) {
162169
type AggConfigManager struct {
163170
activeProfile string
164171
configs map[string]*AggConfig
165-
cfgFile io.Reader
166-
credFile io.Reader
172+
configFile *os.File
173+
credFile *os.File
167174
}
168175

169176
//NewAggConfigManager create instance
170-
func NewAggConfigManager(cfgFile, credFile io.Reader) (*AggConfigManager, error) {
171-
177+
func NewAggConfigManager(cfgFile, credFile *os.File) (*AggConfigManager, error) {
172178
manager := &AggConfigManager{
173-
configs: make(map[string]*AggConfig),
174-
cfgFile: cfgFile,
175-
credFile: credFile,
179+
configs: make(map[string]*AggConfig),
180+
configFile: cfgFile,
181+
credFile: credFile,
176182
}
177183

178184
err := manager.Load()
@@ -183,7 +189,7 @@ func NewAggConfigManager(cfgFile, credFile io.Reader) (*AggConfigManager, error)
183189

184190
aerr := adaptOldConfig()
185191
if aerr != nil {
186-
HandleError(aerr)
192+
HandleError(fmt.Errorf("adapt to old config failed: %v", aerr))
187193
return manager, aerr
188194
}
189195

@@ -296,8 +302,8 @@ func (p *AggConfigManager) Save() error {
296302
aggConfig.copyToCredentialConfig(credConfig)
297303
credcs = append(credcs, credConfig)
298304
}
299-
aerr := WriteJSONFile(clics, ConfigFilePath)
300-
berr := WriteJSONFile(credcs, CredentialFilePath)
305+
aerr := WriteJSONFile(clics, p.configFile.Name())
306+
berr := WriteJSONFile(credcs, p.credFile.Name())
301307

302308
if aerr != nil && berr != nil {
303309
return fmt.Errorf("save cli config failed: %v | save credentail failed: %v", aerr, berr)
@@ -365,26 +371,43 @@ func (p *AggConfigManager) GetActiveAggConfig() (*AggConfig, error) {
365371
return nil, fmt.Errorf("active profile not found. see 'ucloud config list'")
366372
}
367373

374+
//GetActiveAggConfigName get active config name
375+
func (p *AggConfigManager) GetActiveAggConfigName() string {
376+
if ac, ok := p.configs[p.activeProfile]; ok {
377+
return ac.Profile
378+
}
379+
return ""
380+
}
381+
368382
func (p *AggConfigManager) parseCLIConfigs() ([]CLIConfig, error) {
369-
byts, err := ioutil.ReadAll(p.cfgFile)
383+
var configs []CLIConfig
384+
rawConfig, err := ioutil.ReadAll(p.configFile)
370385
if err != nil {
371386
return nil, err
372387
}
373-
configs := []CLIConfig{}
374-
err = json.Unmarshal(byts, &configs)
388+
if len(rawConfig) == 0 {
389+
return nil, nil
390+
}
391+
392+
err = json.Unmarshal(rawConfig, &configs)
375393
if err != nil {
376394
return nil, fmt.Errorf("parse cli config faild: %v", err)
377395
}
378396
return configs, nil
379397
}
380398

381399
func (p *AggConfigManager) parseCredentials() ([]CredentialConfig, error) {
382-
byts, err := ioutil.ReadAll(p.credFile)
400+
var credentials []CredentialConfig
401+
rawCred, err := ioutil.ReadAll(p.credFile)
383402
if err != nil {
384403
return nil, err
385404
}
386-
credentials := make([]CredentialConfig, 0)
387-
err = json.Unmarshal(byts, &credentials)
405+
406+
if len(rawCred) == 0 {
407+
return nil, nil
408+
}
409+
410+
err = json.Unmarshal(rawCred, &credentials)
388411
if err != nil {
389412
return nil, fmt.Errorf("parse credential failed: %v", err)
390413
}
@@ -470,11 +493,19 @@ func adaptOldConfig() error {
470493
return AggConfigListIns.Append(ac)
471494
}
472495

496+
func init() {
497+
bc, err := GetBizClient(ConfigIns)
498+
if err != nil {
499+
HandleError(err)
500+
}
501+
BizClient = bc
502+
}
503+
473504
//GetBizClient 初始化BizClient
474505
func GetBizClient(ac *AggConfig) (*Client, error) {
475506
timeout, err := time.ParseDuration(fmt.Sprintf("%ds", ac.Timeout))
476507
if err != nil {
477-
return nil, fmt.Errorf("parse timeout %ds failed: %v", ac.Timeout, err)
508+
err = fmt.Errorf("parse timeout %ds failed: %v", ac.Timeout, err)
478509
}
479510
ClientConfig = &sdk.Config{
480511
BaseUrl: ac.BaseURL,
@@ -492,64 +523,61 @@ func GetBizClient(ac *AggConfig) (*Client, error) {
492523
PrivateKey: ac.PrivateKey,
493524
}
494525

495-
return NewClient(ClientConfig, AuthCredential), nil
526+
return NewClient(ClientConfig, AuthCredential), err
496527
}
497528

498-
func init() {
499-
initConfigDir()
500-
//配置日志
501-
err := initLog()
502-
if err != nil {
503-
fmt.Println(err)
504-
}
505-
cfgFile, err := os.Open(ConfigFilePath)
506-
if err != nil {
529+
//InitConfig 初始化配置
530+
func InitConfig() {
531+
configFile, err := os.OpenFile(ConfigFilePath, os.O_CREATE|os.O_RDONLY, LocalFileMode)
532+
if err != nil && !os.IsNotExist(err) {
507533
HandleError(err)
508-
} else {
509-
defer cfgFile.Close()
510534
}
511-
512-
credFile, err := os.Open(CredentialFilePath)
513-
if err != nil {
535+
credFile, err := os.OpenFile(CredentialFilePath, os.O_CREATE|os.O_RDONLY, LocalFileMode)
536+
if err != nil && !os.IsNotExist(err) {
514537
HandleError(err)
515-
} else {
516-
defer credFile.Close()
517538
}
518539

519-
AggConfigListIns, err = NewAggConfigManager(cfgFile, credFile)
540+
AggConfigListIns, err = NewAggConfigManager(configFile, credFile)
520541
if err != nil {
521-
HandleError(err)
522-
ins := &AggConfig{
523-
BaseURL: "https://api.ucloud.cn",
524-
Timeout: 15,
525-
Profile: "default",
526-
}
527-
bc, err := GetBizClient(ins)
528-
if err != nil {
529-
HandleError(err)
530-
} else {
531-
BizClient = bc
532-
}
542+
LogError(err.Error())
533543
} else {
534-
ins, err := AggConfigListIns.GetActiveAggConfig()
535-
if err != nil {
536-
LogInfo(fmt.Sprintf("load active config failed: %v", err))
537-
ins = &AggConfig{
538-
BaseURL: DefaultBaseURL,
539-
Timeout: DefaultTimeoutSec,
544+
var ins *AggConfig
545+
if Global.Profile == "" {
546+
ins, err = AggConfigListIns.GetActiveAggConfig()
547+
if err != nil && len(AggConfigListIns.GetAggConfigList()) != 0 {
548+
HandleError(err)
540549
}
541550
} else {
551+
var ok bool
552+
ins, ok = AggConfigListIns.GetAggConfigByProfile(Global.Profile)
553+
if !ok {
554+
HandleError(fmt.Errorf("Profile %s does not exist", Global.Profile))
555+
}
556+
}
557+
558+
if ins != nil {
542559
ConfigIns = ins
543-
tmpIns := *ins
544-
tmpIns.PublicKey = MosaicString(tmpIns.PublicKey, 5, 5)
545-
tmpIns.PrivateKey = MosaicString(tmpIns.PrivateKey, 5, 5)
546-
LogInfo(fmt.Sprintf("load active config : %#v", tmpIns))
560+
} else {
561+
ins = ConfigIns
547562
}
548-
bc, err := GetBizClient(ins)
563+
564+
tmpIns := *ins
565+
tmpIns.PublicKey = MosaicString(tmpIns.PublicKey, 5, 5)
566+
tmpIns.PrivateKey = MosaicString(tmpIns.PrivateKey, 5, 5)
567+
LogInfo(fmt.Sprintf("load active config : %#v", tmpIns))
568+
bc, err := GetBizClient(ConfigIns)
549569
if err != nil {
550570
HandleError(err)
551571
} else {
552572
BizClient = bc
553573
}
554574
}
555575
}
576+
577+
func init() {
578+
//配置日志
579+
err := initLog()
580+
if err != nil {
581+
fmt.Println(err)
582+
}
583+
}

0 commit comments

Comments
 (0)