Skip to content

Commit

Permalink
Merge pull request #36 from nao1215/feat/delete-tui
Browse files Browse the repository at this point in the history
Add text user interface for deleting s3 bucket
  • Loading branch information
nao1215 authored Jan 14, 2024
2 parents a01b622 + 8eb56bf commit 7ed38f2
Show file tree
Hide file tree
Showing 9 changed files with 481 additions and 50 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ localstack
/spare
/cfn
.envrc
/t-rec*
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/s3 v1.48.0
github.com/charmbracelet/bubbles v0.17.1
github.com/charmbracelet/bubbletea v0.25.0
github.com/charmbracelet/lipgloss v0.9.1
github.com/charmbracelet/log v0.3.1
github.com/fatih/color v1.16.0
github.com/google/go-cmp v0.6.0
Expand Down Expand Up @@ -48,7 +49,7 @@ require (
github.com/aws/smithy-go v1.19.0 // indirect
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
github.com/caarlos0/env/v9 v9.0.0 // indirect
github.com/charmbracelet/lipgloss v0.9.1 // indirect
github.com/charmbracelet/harmonica v0.2.0 // indirect
github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect
github.com/go-logfmt/logfmt v0.6.0 // indirect
github.com/google/subcommands v1.0.1 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ github.com/charmbracelet/bubbles v0.17.1 h1:0SIyjOnkrsfDo88YvPgAWvZMwXe26TP6drRv
github.com/charmbracelet/bubbles v0.17.1/go.mod h1:9HxZWlkCqz2PRwsCbYl7a3KXvGzFaDHpYbSYMJ+nE3o=
github.com/charmbracelet/bubbletea v0.25.0 h1:bAfwk7jRz7FKFl9RzlIULPkStffg5k6pNt5dywy4TcM=
github.com/charmbracelet/bubbletea v0.25.0/go.mod h1:EN3QDR1T5ZdWmdfDzYcqOCAps45+QIJbLOBxmVNWNNg=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss v0.9.1 h1:PNyd3jvaJbg4jRHKWXnCj1akQm4rh8dbEzN1p/u1KWg=
github.com/charmbracelet/lipgloss v0.9.1/go.mod h1:1mPmG4cxScwUQALAAnacHaigiiHB9Pmr+v1VEawJl6I=
github.com/charmbracelet/log v0.3.1 h1:TjuY4OBNbxmHWSwO3tosgqs5I3biyY8sQPny/eCMTYw=
Expand Down
43 changes: 43 additions & 0 deletions ui/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,20 @@ func Checkbox(label string, checked bool) string {
return fmt.Sprintf("[ ] %s", label)
}

// ToggleWidget represents a toggle.
func ToggleWidget(label string, now, enabled bool) string {
if now {
if enabled {
return ColorFg("▶ [x] "+label, "212")
}
return ColorFg("▶ [ ] "+label, "212")
}
if enabled {
return ColorFg(" [x] "+label, "212")
}
return fmt.Sprintf(" [ ] %s", label)
}

// Split splits a string into multiple lines.
// Each line has a maximum length of 80 characters.
func Split(s string) []string {
Expand Down Expand Up @@ -103,3 +117,32 @@ func (c *Choice) Decrement() {
c.Choice = c.Max
}
}

// Toggle represents a toggle.
type Toggle struct {
Enabled bool
}

// NewToggle returns a new toggle.
func NewToggle() *Toggle {
return &Toggle{
Enabled: false,
}
}

// Toggle toggles the toggle.
func (t *Toggle) Toggle() {
t.Enabled = !t.Enabled
}

// ToggleSets represents a set of toggles.
type ToggleSets []*Toggle

// NewToggleSets returns a new toggle sets.
func NewToggleSets(n int) ToggleSets {
ts := make([]*Toggle, 0, n)
for i := 0; i < n; i++ {
ts = append(ts, NewToggle())
}
return ts
}
113 changes: 113 additions & 0 deletions ui/s3hub/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package s3hub

import (
"context"
"crypto/rand"
"fmt"
"math/big"
"time"

tea "github.com/charmbracelet/bubbletea"
"github.com/nao1215/rainbow/app/di"
"github.com/nao1215/rainbow/app/domain/model"
"github.com/nao1215/rainbow/app/usecase"
"github.com/nao1215/rainbow/ui"
"golang.org/x/sync/errgroup"
"golang.org/x/sync/semaphore"
)

// fetchS3BucketMsg is the message that is sent when the user wants to fetch the list of the S3 buckets.
type fetchS3BucketMsg struct {
buckets model.BucketSets
}

// fetchS3BucketListCmd fetches the list of the S3 buckets.
func fetchS3BucketListCmd(ctx context.Context, app *di.S3App) tea.Cmd {
return tea.Cmd(func() tea.Msg {
output, err := app.S3BucketLister.ListS3Buckets(ctx, &usecase.S3BucketListerInput{})
if err != nil {
return ui.ErrMsg(err)
}
return fetchS3BucketMsg{
buckets: output.Buckets,
}
})
}

type deleteS3BucketMsg struct {
deletedBucket model.Bucket
}

// deleteS3BucketCmd deletes the S3 bucket.
// TODO: refactor
func deleteS3BucketCmd(ctx context.Context, app *di.S3App, bucket model.Bucket) tea.Cmd {
d, err := rand.Int(rand.Reader, big.NewInt(500))
if err != nil {
return func() tea.Msg {
return ui.ErrMsg(fmt.Errorf("failed to start deleting s3 bucket: %w", err))
}
}
delay := time.Millisecond * time.Duration(d.Int64())

return tea.Tick(delay, func(t time.Time) tea.Msg {
output, err := app.S3ObjectsLister.ListS3Objects(ctx, &usecase.S3ObjectsListerInput{
Bucket: bucket,
})
if err != nil {
return err
}

if len(output.Objects) != 0 {
eg, ctx := errgroup.WithContext(ctx)
sem := semaphore.NewWeighted(model.MaxS3DeleteObjectsParallelsCount)
chunks := divideIntoChunks(output.Objects, model.S3DeleteObjectChunksSize)

for _, chunk := range chunks {
chunk := chunk // Create a new variable to avoid concurrency issues
// Acquire semaphore to control the number of concurrent goroutines
if err := sem.Acquire(ctx, 1); err != nil {
return err
}

eg.Go(func() error {
defer sem.Release(1)
if _, err := app.S3ObjectsDeleter.DeleteS3Objects(ctx, &usecase.S3ObjectsDeleterInput{
Bucket: bucket,
S3ObjectSets: chunk,
}); err != nil {
return err
}
return nil
})
}

if err := eg.Wait(); err != nil {
return err
}
}

_, err = app.S3BucketDeleter.DeleteS3Bucket(ctx, &usecase.S3BucketDeleterInput{
Bucket: bucket,
})
if err != nil {
return ui.ErrMsg(err)
}
return deleteS3BucketMsg{
deletedBucket: bucket,
}
})
}

// divideIntoChunks divides a slice into chunks of the specified size.
func divideIntoChunks(slice []model.S3ObjectIdentifier, chunkSize int) [][]model.S3ObjectIdentifier {
var chunks [][]model.S3ObjectIdentifier

for i := 0; i < len(slice); i += chunkSize {
end := i + chunkSize
if end > len(slice) {
end = len(slice)
}
chunks = append(chunks, slice[i:end])
}
return chunks
}
2 changes: 1 addition & 1 deletion ui/s3hub/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (m *s3hubCreateBucketModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}

if m.choice == s3hubCreateBucketBucketNameChoice {
if m.state != s3hubCreateBucketStateCreated && m.choice == s3hubCreateBucketBucketNameChoice {
var cmd tea.Cmd
m.bucketNameInput, cmd = m.bucketNameInput.Update(msg)
return m, cmd
Expand Down
Loading

0 comments on commit 7ed38f2

Please sign in to comment.