Skip to content

Commit

Permalink
use TextArea model for service account key (#243)
Browse files Browse the repository at this point in the history
  • Loading branch information
zhangyangyu committed Sep 23, 2024
1 parent 3dccfb4 commit ae8f86a
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs/generate_doc/ticloud_serverless_export_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ ticloud serverless export create [flags]
--filter strings Specify the exported table(s) with table filter patterns. See https://docs.pingcap.com/tidb/stable/table-filter to learn table filter.
--force Create without confirmation. You need to confirm when you want to export the whole cluster in non-interactive mode.
--gcs.service-account-key string The base64 encoded service account key of GCS.
--gcs.uri string The GCS URI in gcs://<bucket>/<path> format. Required when target type is GCS.
--gcs.uri string The GCS URI in gs://<bucket>/<path> format. Required when target type is GCS.
-h, --help help for create
--parquet.compression string The parquet compression algorithm. One of ["GZIP" "SNAPPY" "ZSTD" "NONE"]. (default "ZSTD")
--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].
Expand Down
2 changes: 1 addition & 1 deletion docs/generate_doc/ticloud_serverless_import_start.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ ticloud serverless import start [flags]
--csv.trim-last-separator Specifies whether to treat separator as the line terminator and trim all trailing separators in the CSV file.
--file-type string The import file type, one of ["CSV" "SQL" "AURORA_SNAPSHOT" "PARQUET"].
--gcs.service-account-key string The base64 encoded service account key of GCS.
--gcs.uri string The GCS URI in gcs://<bucket>/<path> format. Required when source type is GCS.
--gcs.uri string The GCS URI in gs://<bucket>/<path> format. Required when source type is GCS.
-h, --help help for start
--local.concurrency int The concurrency for uploading file. (default 5)
--local.file-path string The local file path to import.
Expand Down
8 changes: 6 additions & 2 deletions internal/cli/serverless/dataimport/start/gcs.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ func (o GCSOpts) Run(cmd *cobra.Command) error {
authType = authTypeModel.(ui.SelectModel).Choices[authTypeModel.(ui.SelectModel).Selected].(imp.ImportGcsAuthTypeEnum)

if authType == imp.IMPORTGCSAUTHTYPEENUM_SERVICE_ACCOUNT_KEY {
inputs := []string{flag.GCSURI, flag.GCSServiceAccountKey}
inputs := []string{flag.GCSURI}
textInput, err := ui.InitialInputModel(inputs, inputDescription)
if err != nil {
return err
Expand All @@ -74,7 +74,11 @@ func (o GCSOpts) Run(cmd *cobra.Command) error {
if gcsUri == "" {
return errors.New("empty GCS URI")
}
accountKey = textInput.Inputs[1].Value()
areaInput, err := ui.InitialTextAreaModel(inputDescription[flag.GCSServiceAccountKey])
if err != nil {
return errors.Trace(err)
}
accountKey = areaInput.Textarea.Value()
if accountKey == "" {
return errors.New("empty GCS service account key")
}
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/serverless/dataimport/start/gcs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func (suite *GCSImportSuite) TestGCSImportArgs() {
clusterID := "12345"
importID := "imp-asdasd"
accountKey := "xasdas"
gcsUri := "gcs://xxx"
gcsUri := "gs://xxx"
t := time.Now()
fileType := imp.IMPORTFILETYPEENUM_CSV
csvFormat := &imp.CSVFormat{
Expand Down
4 changes: 2 additions & 2 deletions internal/cli/serverless/dataimport/start/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ var inputDescription = map[string]string{
flag.S3RoleArn: "Input your S3 role arn",
flag.AzureBlobURI: "Input your Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format",
flag.AzureBlobSASToken: "Input your Azure Blob SAS token",
flag.GCSURI: "Input your GCS URI in gcs://<bucket>/<path> format",
flag.GCSURI: "Input your GCS URI in gs://<bucket>/<path> format",
flag.GCSServiceAccountKey: "Input your base64 encoded GCS service account key",
flag.CSVSeparator: "Input the CSV separator: separator of each value in CSV files, skip to use default value (,)",
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",
Expand Down Expand Up @@ -249,7 +249,7 @@ func StartCmd(h *internal.Helper) *cobra.Command {
startCmd.MarkFlagsMutuallyExclusive(flag.S3RoleArn, flag.S3SecretAccessKey)
startCmd.MarkFlagsRequiredTogether(flag.S3AccessKeyID, flag.S3SecretAccessKey)

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

startCmd.Flags().String(flag.AzureBlobURI, "", "The Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format.")
Expand Down
10 changes: 7 additions & 3 deletions internal/cli/serverless/export/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func CreateCmd(h *internal.Helper) *cobra.Command {
return errors.New("empty S3 role arn")
}
case string(export.EXPORTGCSAUTHTYPEENUM_SERVICE_ACCOUNT_KEY):
inputs := []string{flag.GCSURI, flag.GCSServiceAccountKey}
inputs := []string{flag.GCSURI}
textInput, err := ui.InitialInputModel(inputs, inputDescription)
if err != nil {
return err
Expand All @@ -234,7 +234,11 @@ func CreateCmd(h *internal.Helper) *cobra.Command {
if gcsURI == "" {
return errors.New("empty GCS URI")
}
gcsServiceAccountKey = textInput.Inputs[1].Value()
areaInput, err := ui.InitialTextAreaModel(inputDescription[flag.GCSServiceAccountKey])
if err != nil {
return errors.Trace(err)
}
gcsServiceAccountKey = areaInput.Textarea.Value()
if gcsServiceAccountKey == "" {
return errors.New("empty GCS service account key")
}
Expand Down Expand Up @@ -655,7 +659,7 @@ func CreateCmd(h *internal.Helper) *cobra.Command {
createCmd.Flags().String(flag.CSVNullValue, CSVNullValueDefaultValue, "Representation of null values in CSV files.")
createCmd.Flags().Bool(flag.CSVSkipHeader, CSVSkipHeaderDefaultValue, "Export CSV files of the tables without header.")
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].")
createCmd.Flags().String(flag.GCSURI, "", "The GCS URI in gcs://<bucket>/<path> format. Required when target type is GCS.")
createCmd.Flags().String(flag.GCSURI, "", "The GCS URI in gs://<bucket>/<path> format. Required when target type is GCS.")
createCmd.Flags().String(flag.GCSServiceAccountKey, "", "The base64 encoded service account key of GCS.")
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.")
createCmd.Flags().String(flag.AzureBlobSASToken, "", "The SAS token of Azure Blob.")
Expand Down
2 changes: 1 addition & 1 deletion internal/cli/serverless/export/ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ var inputDescription = map[string]string{
flag.S3RoleArn: "Input your S3 role arn",
flag.AzureBlobURI: "Input your Azure Blob URI in azure://<account>.blob.core.windows.net/<container>/<path> format",
flag.AzureBlobSASToken: "Input your Azure Blob SAS token",
flag.GCSURI: "Input your GCS URI in gcs://<bucket>/<path> format",
flag.GCSURI: "Input your GCS URI in gs://<bucket>/<path> format",
flag.GCSServiceAccountKey: "Input your base64 encoded GCS service account key",
flag.SQL: "Input the SELECT SQL statement",
flag.TableFilter: "Input the table filter patterns (comma separated). Example: database.table,database.*,`database-1`.`table-1`",
Expand Down
99 changes: 99 additions & 0 deletions internal/ui/text_area_model.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Copyright 2024 PingCAP, Inc.
//
// 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 ui

import (
"fmt"

"github.com/charmbracelet/bubbles/textarea"
tea "github.com/charmbracelet/bubbletea"
"github.com/tidbcloud/tidbcloud-cli/internal/util"
)

type TextAreaModel struct {
Textarea textarea.Model
Err error
Interrupted bool
}

func InitialTextAreaModel(placeholder string) (TextAreaModel, error) {
ta := textarea.New()
ta.Placeholder = placeholder
ta.Focus()
ta.SetWidth(80)
ta.SetHeight(20)
ta.ShowLineNumbers = false
ta.CharLimit = 0

p := tea.NewProgram(TextAreaModel{Textarea: ta})
model, err := p.Run()
finalModel := model.(TextAreaModel)
if err != nil {
return finalModel, err
}
if finalModel.Interrupted {
return finalModel, util.InterruptError
}
if finalModel.Err != nil {
return finalModel, finalModel.Err
}
return finalModel, nil
}

func (m TextAreaModel) Init() tea.Cmd {
return textarea.Blink
}

func (m TextAreaModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmds []tea.Cmd
var cmd tea.Cmd

switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.Type {
case tea.KeyEsc:
if m.Textarea.Focused() {
m.Textarea.Blur()
}
case tea.KeyCtrlS:
return m, tea.Quit
case tea.KeyCtrlC:
m.Interrupted = true
return m, tea.Quit
default:
if !m.Textarea.Focused() {
cmd = m.Textarea.Focus()
cmds = append(cmds, cmd)
}
}

// We handle errors just like any other message
case errMsg:
m.Err = msg
return m, nil
}

m.Textarea, cmd = m.Textarea.Update(msg)
cmds = append(cmds, cmd)
return m, tea.Batch(cmds...)
}

func (m TextAreaModel) View() string {
return fmt.Sprintf(
"%s\n\n%s\n\n",
m.Textarea.View(),
helpMessageStyle("Press Ctrl+S to save and quit"),
)
}

0 comments on commit ae8f86a

Please # to comment.