Skip to content

Commit

Permalink
Wrap up pretty printer
Browse files Browse the repository at this point in the history
  • Loading branch information
csweichel committed Nov 3, 2023
1 parent 094f8ca commit 46081a3
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 119 deletions.
51 changes: 28 additions & 23 deletions components/local-app/cmd/organization-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,14 @@ package cmd

import (
"context"
"fmt"
"reflect"
"time"

"github.com/bufbuild/connect-go"
v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1"
"github.com/gitpod-io/local-app/pkg/common"
"github.com/gitpod-io/local-app/pkg/prettyprint"
"github.com/spf13/cobra"
)

var orgListOutputField string

// listOrganizationCommand lists all available organizations
var listOrganizationCommand = &cobra.Command{
Use: "list",
Expand All @@ -36,28 +32,37 @@ var listOrganizationCommand = &cobra.Command{
return err
}

orgData := orgs.Msg.GetTeams()

if orgListOutputField != "" {
orgListOutputField = common.CapitalizeFirst(orgListOutputField)
for _, org := range orgData {
val := reflect.ValueOf(org).Elem()
if fieldVal := val.FieldByName(orgListOutputField); fieldVal.IsValid() {
fmt.Printf("%v\n", fieldVal.Interface())
} else {
return fmt.Errorf("Field '%s' is an invalid field for organizations", orgListOutputField)
}
}
return nil
}
w := prettyprint.Writer{Out: cmd.OutOrStdout(), Field: listOrganizationOpts.Format.Field}
return w.Write(tabularTeam(orgs.Msg.GetTeams()))
},
}

outputOrgs(orgData)
type tabularTeam []*v1.Team

return nil
},
// Header implements prettyprint.Tabular.
func (tabularTeam) Header() []string {
return []string{"id", "name"}
}

// Row implements prettyprint.Tabular.
func (orgs tabularTeam) Row() []map[string]string {
res := make([]map[string]string, 0, len(orgs))
for _, org := range orgs {
res = append(res, map[string]string{
"id": org.Id,
"name": org.Name,
})
}
return res
}

var _ prettyprint.Tabular = &tabularTeam{}

var listOrganizationOpts struct {
Format formatOpts
}

func init() {
orgCmd.AddCommand(listOrganizationCommand)
listOrganizationCommand.Flags().StringVarP(&orgListOutputField, "field", "f", "", "output a specific field of the organizations")
addFormatFlags(listOrganizationCommand, &listOrganizationOpts.Format)
}
13 changes: 11 additions & 2 deletions components/local-app/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/gitpod-io/gitpod/components/public-api/go/client"
"github.com/gitpod-io/local-app/pkg/auth"
"github.com/gitpod-io/local-app/pkg/config"
"github.com/gitpod-io/local-app/pkg/prettyprint"
"github.com/spf13/cobra"
)

Expand All @@ -26,9 +27,9 @@ var rootCmd = &cobra.Command{
Use: "gitpod",
Short: "A CLI for interacting with Gitpod",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
var logger = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelInfo}))
var logger = slog.New(&prettyprint.Handler{LogLevel: slog.LevelInfo})
if rootOpts.Verbose {
logger = slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelDebug}))
logger = slog.New(&prettyprint.Handler{LogLevel: slog.LevelDebug})
}
slog.SetDefault(logger)

Expand Down Expand Up @@ -94,3 +95,11 @@ func getGitpodClient(ctx context.Context) (*client.Gitpod, error) {

return res, nil
}

type formatOpts struct {
Field string
}

func addFormatFlags(cmd *cobra.Command, opts *formatOpts) {
cmd.Flags().StringVarP(&opts.Field, "field", "f", "", "Only print the specified field")
}
84 changes: 28 additions & 56 deletions components/local-app/cmd/workspace-get.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,73 +12,45 @@ import (

"github.com/bufbuild/connect-go"
v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1"
"github.com/gitpod-io/local-app/pkg/common"
"github.com/olekukonko/tablewriter"
"github.com/gitpod-io/local-app/pkg/prettyprint"
"github.com/spf13/cobra"
)

// stopWorkspaceCommand stops to a given workspace
var workspaceGetOpts struct {
Format formatOpts
}

var workspaceGetCmd = &cobra.Command{
Use: "get <workspace-id>",
Short: "Retrieves metadata of a given workspace",
Args: cobra.ExactArgs(1),
Args: cobra.MinimumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
workspaceID := args[0]

ctx, cancel := context.WithTimeout(cmd.Context(), 30*time.Second)
defer cancel()

gitpod, err := getGitpodClient(ctx)
if err != nil {
return err
}

slog.Debug("Attempting to retrieve workspace info...")
ws, err := gitpod.Workspaces.GetWorkspace(ctx, connect.NewRequest(&v1.GetWorkspaceRequest{WorkspaceId: workspaceID}))
if err != nil {
return err
}

wsInfo := ws.Msg.GetResult()
repository := common.GetWorkspaceRepo(wsInfo)
phase := common.HumanizeWorkspacePhase(wsInfo)

createdAt := wsInfo.Status.Instance.CreatedAt
createdTime := time.Unix(createdAt.Seconds, 0)

data := &common.WorkspaceDisplayData{
Id: wsInfo.WorkspaceId,
Url: common.GetWorkspaceUrl(wsInfo),
Repository: repository,
Branch: common.GetWorkspaceBranch(wsInfo),
Status: phase,
CreatedAt: createdTime,
// todo: LastActive, Created, WorkspaceClass (API implementation pending), RepoUrl (API implementation also pending)
for _, workspaceID := range args {
ctx, cancel := context.WithTimeout(cmd.Context(), 30*time.Second)
defer cancel()

gitpod, err := getGitpodClient(ctx)
if err != nil {
return err
}

slog.Debug("Attempting to retrieve workspace info...")
ws, err := gitpod.Workspaces.GetWorkspace(ctx, connect.NewRequest(&v1.GetWorkspaceRequest{WorkspaceId: workspaceID}))
if err != nil {
return err
}

w := prettyprint.Writer{Out: os.Stdout, LongFormat: true, Field: workspaceGetOpts.Format.Field}
err = w.Write(tabularWorkspaces([]*v1.Workspace{ws.Msg.GetResult()}))
if err != nil {
return err
}
}

outputInfo(data)

return err
return nil
},
}

func outputInfo(info *common.WorkspaceDisplayData) {
table := tablewriter.NewWriter(os.Stdout)
table.SetColWidth(50)
table.SetBorder(false)
table.SetColumnSeparator(":")
table.Append([]string{"ID", info.Id})
table.Append([]string{"URL", info.Url})
// Class
table.Append([]string{"Status", info.Status})
// Repo URL
table.Append([]string{"Repo", info.Repository})
table.Append([]string{"Branch", info.Branch})
table.Append([]string{"Created", info.CreatedAt.Format(time.RFC3339)})
// Last Active (duration)
table.Render()
}

func init() {
workspaceCmd.AddCommand(workspaceGetCmd)
addFormatFlags(workspaceGetCmd, &workspaceGetOpts.Format)
}
63 changes: 25 additions & 38 deletions components/local-app/cmd/workspace-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,20 @@ package cmd

import (
"context"
"fmt"
"os"
"reflect"
"time"

"github.com/bufbuild/connect-go"
v1 "github.com/gitpod-io/gitpod/components/public-api/go/experimental/v1"
"github.com/gitpod-io/local-app/pkg/common"
"github.com/gitpod-io/local-app/pkg/config"
"github.com/olekukonko/tablewriter"
"github.com/gitpod-io/local-app/pkg/prettyprint"
"github.com/spf13/cobra"
)

var wsListOutputField string
var workspaceListOpts struct {
Format formatOpts
}

// workspaceListCmd lists all available workspaces
var workspaceListCmd = &cobra.Command{
Expand Down Expand Up @@ -49,46 +49,33 @@ var workspaceListCmd = &cobra.Command{
return err
}

table := tablewriter.NewWriter(os.Stdout)
table.SetHeader([]string{"Repo", "Branch", "Workspace ID", "Status"})
table.SetBorder(false)
table.SetColumnSeparator("")
table.SetHeaderAlignment(tablewriter.ALIGN_LEFT)
table.SetHeaderLine(false)

for _, workspace := range workspaces.Msg.GetResult() {
repository := common.GetWorkspaceRepo(workspace)
branch := common.GetWorkspaceBranch(workspace)
w := prettyprint.Writer{Out: os.Stdout, Field: workspaceListOpts.Format.Field}
_ = w.Write(tabularWorkspaces(workspaces.Msg.GetResult()))

wsData := common.WorkspaceDisplayData{
Repository: repository,
Branch: branch,
Id: workspace.WorkspaceId,
Status: common.HumanizeWorkspacePhase(workspace),
}
return nil
},
}

if wsListOutputField != "" {
wsListOutputField = common.CapitalizeFirst(wsListOutputField)
val := reflect.ValueOf(wsData)
if fieldVal := val.FieldByName(wsListOutputField); fieldVal.IsValid() {
fmt.Printf("%v\n", fieldVal.Interface())
} else {
return fmt.Errorf("Field '%s' is an invalid field for workspaces", wsListOutputField)
}
} else {
table.Append([]string{wsData.Repository, wsData.Branch, wsData.Id, wsData.Status})
}
}
type tabularWorkspaces []*v1.Workspace

if wsListOutputField == "" {
table.Render()
}
func (tabularWorkspaces) Header() []string {
return []string{"repository", "branch", "workspace", "status"}
}

return nil
},
func (wss tabularWorkspaces) Row() []map[string]string {
res := make([]map[string]string, 0, len(wss))
for _, ws := range wss {
res = append(res, map[string]string{
"repository": common.GetWorkspaceRepo(ws),
"branch": common.GetWorkspaceBranch(ws),
"workspace": ws.WorkspaceId,
"status": common.HumanizeWorkspacePhase(ws),
})
}
return res
}

func init() {
workspaceCmd.AddCommand(workspaceListCmd)
workspaceListCmd.Flags().StringVarP(&wsListOutputField, "field", "f", "", "output a specific field of the workspaces")
addFormatFlags(workspaceListCmd, &workspaceListOpts.Format)
}
43 changes: 43 additions & 0 deletions components/local-app/pkg/prettyprint/handler.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.
// Licensed under the GNU Affero General Public License (AGPL).
// See License.AGPL.txt in the project root for license information.

package prettyprint

import (
"context"
"fmt"
"log/slog"
)

var _ slog.Handler = &Handler{}

type Handler struct {
Attrs []slog.Attr
LogLevel slog.Level
}

// Enabled implements slog.Handler.
func (h *Handler) Enabled(ctx context.Context, lvl slog.Level) bool {
return lvl >= h.LogLevel
}

// Handle implements slog.Handler.
func (h *Handler) Handle(ctx context.Context, req slog.Record) error {
fmt.Printf("[%s] %s\n", req.Level, req.Message)
return nil
}

// WithAttrs implements slog.Handler.
func (h *Handler) WithAttrs(attrs []slog.Attr) slog.Handler {
h.Attrs = append(h.Attrs, attrs...)
return &Handler{
Attrs: attrs,
LogLevel: h.LogLevel,
}
}

// WithGroup implements slog.Handler.
func (h *Handler) WithGroup(name string) slog.Handler {
return h
}
Loading

0 comments on commit 46081a3

Please sign in to comment.