Skip to content

Commit ae8f86a

Browse files
authored
use TextArea model for service account key (#243)
1 parent 3dccfb4 commit ae8f86a

File tree

8 files changed

+118
-11
lines changed

8 files changed

+118
-11
lines changed

docs/generate_doc/ticloud_serverless_export_create.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ ticloud serverless export create [flags]
4444
--filter strings Specify the exported table(s) with table filter patterns. See https://docs.pingcap.com/tidb/stable/table-filter to learn table filter.
4545
--force Create without confirmation. You need to confirm when you want to export the whole cluster in non-interactive mode.
4646
--gcs.service-account-key string The base64 encoded service account key of GCS.
47-
--gcs.uri string The GCS URI in gcs://<bucket>/<path> format. Required when target type is GCS.
47+
--gcs.uri string The GCS URI in gs://<bucket>/<path> format. Required when target type is GCS.
4848
-h, --help help for create
4949
--parquet.compression string The parquet compression algorithm. One of ["GZIP" "SNAPPY" "ZSTD" "NONE"]. (default "ZSTD")
5050
--s3.access-key-id string The access key ID of the S3. You only need to set one of the s3.role-arn and [s3.access-key-id, s3.secret-access-key].

docs/generate_doc/ticloud_serverless_import_start.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ ticloud serverless import start [flags]
4747
--csv.trim-last-separator Specifies whether to treat separator as the line terminator and trim all trailing separators in the CSV file.
4848
--file-type string The import file type, one of ["CSV" "SQL" "AURORA_SNAPSHOT" "PARQUET"].
4949
--gcs.service-account-key string The base64 encoded service account key of GCS.
50-
--gcs.uri string The GCS URI in gcs://<bucket>/<path> format. Required when source type is GCS.
50+
--gcs.uri string The GCS URI in gs://<bucket>/<path> format. Required when source type is GCS.
5151
-h, --help help for start
5252
--local.concurrency int The concurrency for uploading file. (default 5)
5353
--local.file-path string The local file path to import.

internal/cli/serverless/dataimport/start/gcs.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func (o GCSOpts) Run(cmd *cobra.Command) error {
6565
authType = authTypeModel.(ui.SelectModel).Choices[authTypeModel.(ui.SelectModel).Selected].(imp.ImportGcsAuthTypeEnum)
6666

6767
if authType == imp.IMPORTGCSAUTHTYPEENUM_SERVICE_ACCOUNT_KEY {
68-
inputs := []string{flag.GCSURI, flag.GCSServiceAccountKey}
68+
inputs := []string{flag.GCSURI}
6969
textInput, err := ui.InitialInputModel(inputs, inputDescription)
7070
if err != nil {
7171
return err
@@ -74,7 +74,11 @@ func (o GCSOpts) Run(cmd *cobra.Command) error {
7474
if gcsUri == "" {
7575
return errors.New("empty GCS URI")
7676
}
77-
accountKey = textInput.Inputs[1].Value()
77+
areaInput, err := ui.InitialTextAreaModel(inputDescription[flag.GCSServiceAccountKey])
78+
if err != nil {
79+
return errors.Trace(err)
80+
}
81+
accountKey = areaInput.Textarea.Value()
7882
if accountKey == "" {
7983
return errors.New("empty GCS service account key")
8084
}

internal/cli/serverless/dataimport/start/gcs_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ func (suite *GCSImportSuite) TestGCSImportArgs() {
7676
clusterID := "12345"
7777
importID := "imp-asdasd"
7878
accountKey := "xasdas"
79-
gcsUri := "gcs://xxx"
79+
gcsUri := "gs://xxx"
8080
t := time.Now()
8181
fileType := imp.IMPORTFILETYPEENUM_CSV
8282
csvFormat := &imp.CSVFormat{

internal/cli/serverless/dataimport/start/start.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ var inputDescription = map[string]string{
5555
flag.S3RoleArn: "Input your S3 role arn",
5656
flag.AzureBlobURI: "Input your Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format",
5757
flag.AzureBlobSASToken: "Input your Azure Blob SAS token",
58-
flag.GCSURI: "Input your GCS URI in gcs://<bucket>/<path> format",
58+
flag.GCSURI: "Input your GCS URI in gs://<bucket>/<path> format",
5959
flag.GCSServiceAccountKey: "Input your base64 encoded GCS service account key",
6060
flag.CSVSeparator: "Input the CSV separator: separator of each value in CSV files, skip to use default value (,)",
6161
flag.CSVDelimiter: "Input the CSV delimiter: delimiter of string type variables in CSV files, skip to use default value (\"). If you want to set empty string, please use non-interactive mode",
@@ -249,7 +249,7 @@ func StartCmd(h *internal.Helper) *cobra.Command {
249249
startCmd.MarkFlagsMutuallyExclusive(flag.S3RoleArn, flag.S3SecretAccessKey)
250250
startCmd.MarkFlagsRequiredTogether(flag.S3AccessKeyID, flag.S3SecretAccessKey)
251251

252-
startCmd.Flags().String(flag.GCSURI, "", "The GCS URI in gcs://<bucket>/<path> format. Required when source type is GCS.")
252+
startCmd.Flags().String(flag.GCSURI, "", "The GCS URI in gs://<bucket>/<path> format. Required when source type is GCS.")
253253
startCmd.Flags().String(flag.GCSServiceAccountKey, "", "The base64 encoded service account key of GCS.")
254254

255255
startCmd.Flags().String(flag.AzureBlobURI, "", "The Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format.")

internal/cli/serverless/export/create.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func CreateCmd(h *internal.Helper) *cobra.Command {
225225
return errors.New("empty S3 role arn")
226226
}
227227
case string(export.EXPORTGCSAUTHTYPEENUM_SERVICE_ACCOUNT_KEY):
228-
inputs := []string{flag.GCSURI, flag.GCSServiceAccountKey}
228+
inputs := []string{flag.GCSURI}
229229
textInput, err := ui.InitialInputModel(inputs, inputDescription)
230230
if err != nil {
231231
return err
@@ -234,7 +234,11 @@ func CreateCmd(h *internal.Helper) *cobra.Command {
234234
if gcsURI == "" {
235235
return errors.New("empty GCS URI")
236236
}
237-
gcsServiceAccountKey = textInput.Inputs[1].Value()
237+
areaInput, err := ui.InitialTextAreaModel(inputDescription[flag.GCSServiceAccountKey])
238+
if err != nil {
239+
return errors.Trace(err)
240+
}
241+
gcsServiceAccountKey = areaInput.Textarea.Value()
238242
if gcsServiceAccountKey == "" {
239243
return errors.New("empty GCS service account key")
240244
}
@@ -655,7 +659,7 @@ func CreateCmd(h *internal.Helper) *cobra.Command {
655659
createCmd.Flags().String(flag.CSVNullValue, CSVNullValueDefaultValue, "Representation of null values in CSV files.")
656660
createCmd.Flags().Bool(flag.CSVSkipHeader, CSVSkipHeaderDefaultValue, "Export CSV files of the tables without header.")
657661
createCmd.Flags().String(flag.S3RoleArn, "", "The role arn of the S3. You only need to set one of the s3.role-arn and [s3.access-key-id, s3.secret-access-key].")
658-
createCmd.Flags().String(flag.GCSURI, "", "The GCS URI in gcs://<bucket>/<path> format. Required when target type is GCS.")
662+
createCmd.Flags().String(flag.GCSURI, "", "The GCS URI in gs://<bucket>/<path> format. Required when target type is GCS.")
659663
createCmd.Flags().String(flag.GCSServiceAccountKey, "", "The base64 encoded service account key of GCS.")
660664
createCmd.Flags().String(flag.AzureBlobURI, "", "The Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format. Required when target type is AZURE_BLOB.")
661665
createCmd.Flags().String(flag.AzureBlobSASToken, "", "The SAS token of Azure Blob.")

internal/cli/serverless/export/ui.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ var inputDescription = map[string]string{
3333
flag.S3RoleArn: "Input your S3 role arn",
3434
flag.AzureBlobURI: "Input your Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format",
3535
flag.AzureBlobSASToken: "Input your Azure Blob SAS token",
36-
flag.GCSURI: "Input your GCS URI in gcs://<bucket>/<path> format",
36+
flag.GCSURI: "Input your GCS URI in gs://<bucket>/<path> format",
3737
flag.GCSServiceAccountKey: "Input your base64 encoded GCS service account key",
3838
flag.SQL: "Input the SELECT SQL statement",
3939
flag.TableFilter: "Input the table filter patterns (comma separated). Example: database.table,database.*,`database-1`.`table-1`",

internal/ui/text_area_model.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// Copyright 2024 PingCAP, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package ui
16+
17+
import (
18+
"fmt"
19+
20+
"github.com/charmbracelet/bubbles/textarea"
21+
tea "github.com/charmbracelet/bubbletea"
22+
"github.com/tidbcloud/tidbcloud-cli/internal/util"
23+
)
24+
25+
type TextAreaModel struct {
26+
Textarea textarea.Model
27+
Err error
28+
Interrupted bool
29+
}
30+
31+
func InitialTextAreaModel(placeholder string) (TextAreaModel, error) {
32+
ta := textarea.New()
33+
ta.Placeholder = placeholder
34+
ta.Focus()
35+
ta.SetWidth(80)
36+
ta.SetHeight(20)
37+
ta.ShowLineNumbers = false
38+
ta.CharLimit = 0
39+
40+
p := tea.NewProgram(TextAreaModel{Textarea: ta})
41+
model, err := p.Run()
42+
finalModel := model.(TextAreaModel)
43+
if err != nil {
44+
return finalModel, err
45+
}
46+
if finalModel.Interrupted {
47+
return finalModel, util.InterruptError
48+
}
49+
if finalModel.Err != nil {
50+
return finalModel, finalModel.Err
51+
}
52+
return finalModel, nil
53+
}
54+
55+
func (m TextAreaModel) Init() tea.Cmd {
56+
return textarea.Blink
57+
}
58+
59+
func (m TextAreaModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
60+
var cmds []tea.Cmd
61+
var cmd tea.Cmd
62+
63+
switch msg := msg.(type) {
64+
case tea.KeyMsg:
65+
switch msg.Type {
66+
case tea.KeyEsc:
67+
if m.Textarea.Focused() {
68+
m.Textarea.Blur()
69+
}
70+
case tea.KeyCtrlS:
71+
return m, tea.Quit
72+
case tea.KeyCtrlC:
73+
m.Interrupted = true
74+
return m, tea.Quit
75+
default:
76+
if !m.Textarea.Focused() {
77+
cmd = m.Textarea.Focus()
78+
cmds = append(cmds, cmd)
79+
}
80+
}
81+
82+
// We handle errors just like any other message
83+
case errMsg:
84+
m.Err = msg
85+
return m, nil
86+
}
87+
88+
m.Textarea, cmd = m.Textarea.Update(msg)
89+
cmds = append(cmds, cmd)
90+
return m, tea.Batch(cmds...)
91+
}
92+
93+
func (m TextAreaModel) View() string {
94+
return fmt.Sprintf(
95+
"%s\n\n%s\n\n",
96+
m.Textarea.View(),
97+
helpMessageStyle("Press Ctrl+S to save and quit"),
98+
)
99+
}

0 commit comments

Comments
 (0)