go.temporal.io/server/tools/tdbg/util.go

322 LOC · 68 covered · 254 uncovered · 23 ranges · 81 concepts · 13 introducers · 39 tests

File neighbourhood

The centred file is linked to every concept that introduces one of its ranges, every test that runs code from the file, and the gray connector concepts standing between those tests and the file's own introducer concepts. Undirected links join concepts to every file where they introduce source and concepts to the tests they introduce; arrows show specialization between the displayed concepts and bridge only concepts omitted from this view. Concept colors match the source ranges below; connector concepts have no source color and are shown in gray.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the file

In the embedded map, ordinary wheel input scrolls the page; use the visible controls to zoom and drag to pan. Open the full-screen map for canvas navigation: wheel pans, Ctrl/Command plus wheel zooms, and arrow keys pan when this region is focused. On touch screens, open the full-screen map to pan or pinch. If JavaScript or WebGL is unavailable, use the related-file, concept, and source links on this page.

Focused file, its introducer and connector concepts, their introduced files, and tests that run code from the filego.temporal.io/server/common/codec/jsonpb.go · 147 LOCcodec/jsonpb.gogo.temporal.io/server/tools/tdbg/commands.go · 1307 LOCtdbg/commands.gogo.temporal.io/server/tools/tdbg/dlq_service.go · 165 LOCtdbg/dlq_service.gogo.temporal.io/server/tools/tdbg/dlq_v2_service.go · 473 LOCtdbg/dlq_v2_service.gogo.temporal.io/server/tools/tdbg/tdbg_commands.go · 1028 LOCtdbg/tdbg_commands.godlq_v2_service.go ×10 · 57 introduced LOCdlq_v2_service.go ×10dlq_v2_service.go ×3 · 12 introduced LOCdlq_v2_service.go ×3dlq_v2_service.go ×2 · 11 introduced LOCdlq_v2_service.go ×2task_queue_commands.go ×12 · 75 introduced LOCtask_queue_commands.go ×…task_queue_commands.go ×5 · 44 introduced LOCtask_queue_commands.go ×…dlq_v2_service.go ×2 · 4 introduced LOCdlq_v2_service.go ×2task_queue_commands.go ×9 · 58 introduced LOCtask_queue_commands.go ×…util.go ×3 · 17 introduced LOCutil.go ×3util.go ×5 · 35 introduced LOCutil.go ×5dlq_v2_service.go ×2 · 3 introduced LOCdlq_v2_service.go ×2util.go ×1 · 2 introduced LOCutil.go ×1dlq_v2_service.go ×12 · 42 introduced LOCdlq_v2_service.go ×12dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1commands.go ×2 · 7 introduced LOCcommands.go ×2dlq_v2_service.go ×1 · 1 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1TestMigrateSchedule_FromVisibility_Execute, TestMigrateSchedule_FromVisibility_Workers · 0 introduced LOCTestMigrateSchedule_From…dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×2 · 20 introduced LOCdlq_v2_service.go ×2TestMigrateSchedule_FromVisibility_DryRun · 0 introduced LOCTestMigrateSchedule_From…TestMigrateSchedule_Stdin_OutputLog · 0 introduced LOCTestMigrateSchedule_Stdi…commands.go ×1 · 1 introduced LOCcommands.go ×1TestMigrateSchedule_Stdin_Workers · 0 introduced LOCTestMigrateSchedule_Stdi…commands.go ×3 · 11 introduced LOCcommands.go ×3dlq_service.go ×1 · 6 introduced LOCdlq_service.go ×1dlq_v2_service.go ×1 · 3 introduced LOCdlq_v2_service.go ×1commands.go ×2 · 4 introduced LOCcommands.go ×2dlq_service.go ×1 · 1 introduced LOCdlq_service.go ×1dlq_v2_service.go ×2 · 4 introduced LOCdlq_v2_service.go ×2dlq_v2_service.go ×2 · 5 introduced LOCdlq_v2_service.go ×2TestMigrateSchedule_Stdin_DryRun · 0 introduced LOCTestMigrateSchedule_Stdi…dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×2 · 25 introduced LOCdlq_v2_service.go ×2dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1TestMigrateSchedule_FromVisibility_CustomQuery · 0 introduced LOCTestMigrateSchedule_From…commands.go ×4 · 13 introduced LOCcommands.go ×4dlq_v2_service.go ×1 · 9 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×2 · 11 introduced LOCdlq_v2_service.go ×2commands.go ×2 · 2 introduced LOCcommands.go ×2dlq_v2_service.go ×1 · 2 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×1 · 11 introduced LOCdlq_v2_service.go ×1commands.go ×11 · 44 introduced LOCcommands.go ×11dlq_service.go ×2 · 5 introduced LOCdlq_service.go ×2dlq_v2_service.go ×1 · 8 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×1 · 4 introduced LOCdlq_v2_service.go ×1commands.go ×9 · 45 introduced LOCcommands.go ×9dlq_v2_service.go ×1 · 1 introduced LOCdlq_v2_service.go ×1dlq_v2_service.go ×1 · 7 introduced LOCdlq_v2_service.go ×1commands.go ×5 · 28 introduced LOCcommands.go ×5dlq_v2_service.go ×1 · 7 introduced LOCdlq_v2_service.go ×1commands.go ×2 · 10 introduced LOCcommands.go ×2dlq_service.go ×1 · 2 introduced LOCdlq_service.go ×1commands.go ×1 · 2 introduced LOCcommands.go ×1commands.go ×2 · 4 introduced LOCcommands.go ×2commands.go ×3 · 8 introduced LOCcommands.go ×3commands.go ×1 · 3 introduced LOCcommands.go ×1commands.go ×1 · 2 introduced LOCcommands.go ×1commands.go ×1 · 1 introduced LOCcommands.go ×1commands.go ×2 · 4 introduced LOCcommands.go ×2commands.go ×2 · 7 introduced LOCcommands.go ×2commands.go ×1 · 2 introduced LOCcommands.go ×1commands.go ×1 · 2 introduced LOCcommands.go ×1commands.go ×3 · 18 introduced LOCcommands.go ×3commands.go ×1 · 2 introduced LOCcommands.go ×1commands.go ×1 · 1 introduced LOCcommands.go ×1commands.go ×1 · 2 introduced LOCcommands.go ×1commands.go ×1 · 1 introduced LOCcommands.go ×1commands.go ×4 · 15 introduced LOCcommands.go ×4commands.go ×1 · 3 introduced LOCcommands.go ×1commands.go ×1 · 3 introduced LOCcommands.go ×1util.go ×3 · 6 introduced LOCutil.go ×3util.go ×2 · 4 introduced LOCutil.go ×2TestStringToEnum_MapNonExisting · 0 introduced LOCTestStringToEnum_MapNonE…util.go ×1 · 2 introduced LOCutil.go ×1util.go ×2 · 2 introduced LOCutil.go ×2util.go ×1 · 1 introduced LOCutil.go ×1util.go ×1 · 2 introduced LOCutil.go ×1util.go ×1 · 2 introduced LOCutil.go ×1util.go ×1 · 2 introduced LOCutil.go ×1GetDLQTasks_error · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/GetDLQTasks_errorGetDLQTasks_errorGetDLQTasks_on_empty_queue · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/GetDLQTasks_on_empty_queueGetDLQTasks_on_empty_que…invalid_output_file_name · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/invalid_output_file_nameinvalid_output_file_namelast_message_ID_is_less_than_first_possible_message_ID · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/last_message_ID_is_less_than_first_possible_message_IDlast_message_ID_is_less_…last_message_ID_is_less_than_first_possible_message_ID#01 · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/last_message_ID_is_less_than_first_possible_message_ID#01last_message_ID_is_less_…list_no_queues · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/list_no_queueslist_no_queueslist_queues,_paginated · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/list_queues,_paginatedlist_queues,_paginatedmerge_client_err · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/merge_client_errmerge_client_errmerge_without_last_message_ID · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/merge_without_last_message_IDmerge_without_last_messa…merge_without_last_message_ID_-_empty_DLQ · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/merge_without_last_message_ID_-_empty_DLQmerge_without_last_messa…merge_without_last_message_ID_-_error_while_finding · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/merge_without_last_message_ID_-_error_while_findingmerge_without_last_messa…purge_client_err · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/purge_client_errpurge_client_errpurge_without_last_message_ID · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/purge_without_last_message_IDpurge_without_last_messa…purge_without_last_message_ID#01 · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/purge_without_last_message_ID#01purge_without_last_messa…zero_max_message_count · introduced test · go.temporal.io/server/tools/tdbg/TestDLQCommand_V2/zero_max_message_countzero_max_message_countTestMigrateSchedule_FromVisibility_CustomQuery · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_CustomQueryTestMigrateSchedule_From…TestMigrateSchedule_FromVisibility_DefaultQueryToChasm · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_DefaultQueryToChasmTestMigrateSchedule_From…TestMigrateSchedule_FromVisibility_DryRun · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_DryRunTestMigrateSchedule_From…TestMigrateSchedule_FromVisibility_Execute · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_ExecuteTestMigrateSchedule_From…TestMigrateSchedule_FromVisibility_OutputLog · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_OutputLogTestMigrateSchedule_From…TestMigrateSchedule_FromVisibility_RejectsScheduleID · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_RejectsScheduleIDTestMigrateSchedule_From…TestMigrateSchedule_FromVisibility_Workers · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_FromVisibility_WorkersTestMigrateSchedule_From…TestMigrateSchedule_RejectsQueryWithoutFromVisibility · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_RejectsQueryWithoutFromVisibilityTestMigrateSchedule_Reje…TestMigrateSchedule_RejectsWorkersWithScheduleID · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_RejectsWorkersWithScheduleIDTestMigrateSchedule_Reje…TestMigrateSchedule_Stdin_DryRun · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_Stdin_DryRunTestMigrateSchedule_Stdi…TestMigrateSchedule_Stdin_Execute · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_Stdin_ExecuteTestMigrateSchedule_Stdi…TestMigrateSchedule_Stdin_OutputLog · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_Stdin_OutputLogTestMigrateSchedule_Stdi…TestMigrateSchedule_Stdin_Workers · introduced test · go.temporal.io/server/tools/tdbg/TestMigrateSchedule_Stdin_WorkersTestMigrateSchedule_Stdi…TestScheduleStatus_Basic · introduced test · go.temporal.io/server/tools/tdbg/TestScheduleStatus_BasicTestScheduleStatus_BasicTestScheduleStatus_CountError · introduced test · go.temporal.io/server/tools/tdbg/TestScheduleStatus_CountErrorTestScheduleStatus_Count…TestScheduleStatus_DefaultsToDefaultNamespace · introduced test · go.temporal.io/server/tools/tdbg/TestScheduleStatus_DefaultsToDefaultNamespaceTestScheduleStatus_Defau…TestDescribeTaskQueuePartition · introduced test · go.temporal.io/server/tools/tdbg/TestTaskQueueCommandSuite/TestDescribeTaskQueuePartitionTestDescribeTaskQueuePar…TestForceUnloadTaskQueuePartition · introduced test · go.temporal.io/server/tools/tdbg/TestTaskQueueCommandSuite/TestForceUnloadTaskQueuePartitionTestForceUnloadTaskQueue…TestGetTaskQueueUserData · introduced test · go.temporal.io/server/tools/tdbg/TestTaskQueueCommandSuite/TestGetTaskQueueUserDataTestGetTaskQueueUserDataTestStringToEnum_MapCaseInsensitive · introduced test · go.temporal.io/server/tools/tdbg/TestUtilSuite/TestStringToEnum_MapCaseInsensitiveTestStringToEnum_MapCase…TestStringToEnum_MapEmptyEnum · introduced test · go.temporal.io/server/tools/tdbg/TestUtilSuite/TestStringToEnum_MapEmptyEnumTestStringToEnum_MapEmpt…TestStringToEnum_MapEmptyValue · introduced test · go.temporal.io/server/tools/tdbg/TestUtilSuite/TestStringToEnum_MapEmptyValueTestStringToEnum_MapEmpt…TestStringToEnum_MapNonExisting · introduced test · go.temporal.io/server/tools/tdbg/TestUtilSuite/TestStringToEnum_MapNonExistingTestStringToEnum_MapNonE…TestParseDLQMessages · introduced test · go.temporal.io/server/tools/tdbg/tdbgtest/TestParseDLQMessagesTestParseDLQMessagesFocused file · go.temporal.io/server/tools/tdbg/util.go · 322 LOCtdbg/util.go

Graph controls are ready.

Interactive rendering requires JavaScript and WebGL. Use the related-file, concept, and source links on this page while the interactive map is unavailable.

1 package tdbg
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "io"
8 "os"
9 "reflect"
10 "regexp"
11 "strconv"
12 "strings"
13 "time"
14
15 "github.com/fatih/color"
16 "github.com/olekukonko/tablewriter"
17 "github.com/urfave/cli/v2"
18 "go.temporal.io/api/workflowservice/v1"
19 "go.temporal.io/server/chasm"
20 "go.temporal.io/server/common/codec"
21 "go.temporal.io/server/common/collection"
22 "go.temporal.io/server/common/namespace"
23 "google.golang.org/protobuf/proto"
24 )
25
26 var envKeysForUserName = []string{
27 "USER",
28 "LOGNAME",
29 "HOME",
30 }
31
32 > func getCurrentUserFromEnv() string { commands.go ×5
33 > for _, n := range envKeysForUserName {
34 > if len(os.Getenv(n)) > 0 {
35 > return os.Getenv(n)
36 > }
37 }
38 return "unknown"
39 }
40
41 > func prettyPrintJSONObject(c *cli.Context, o any) { util.go ×3
42 > var b []byte
43 > var err error
44 > if pb, ok := o.(proto.Message); ok {
45 > encoder := codec.NewJSONPBIndentEncoder(" ")
46 > b, err = encoder.Encode(pb)
47 > } else {
48 b, err = json.MarshalIndent(o, "", " ")
49 }
50
51 > if err != nil { util.go ×3
52 fmt.Fprintf(c.App.ErrWriter, "Error when trying to pretty-print: %v\n%v\n", err, o)
53 return
54 }
55
56 > _, _ = c.App.Writer.Write(b) util.go ×3
57 > _, _ = c.App.Writer.Write([]byte("\n"))
58 }
59
60 > func getRequiredOption(c *cli.Context, optionName string) (string, error) { util.go ×2
61 > value := c.String(optionName)
62 > if len(value) == 0 {
63 return "", fmt.Errorf("option is required: %s", optionName)
64 }
65 > return value, nil util.go ×2
66 }
67
68 func parseTime(timeStr string, defaultValue time.Time, now time.Time) (time.Time, error) {
69 if len(timeStr) == 0 {
70 return defaultValue, nil
71 }
72
73 // try to parse
74 parsedTime, err := time.Parse(defaultDateTimeFormat, timeStr)
75 if err == nil {
76 return parsedTime, nil
77 }
78
79 // treat as raw unix time
80 resultValue, err := strconv.ParseInt(timeStr, 10, 64)
81 if err == nil {
82 return time.Unix(0, resultValue).UTC(), nil
83 }
84
85 // treat as time range format
86 parsedTime, err = parseTimeRange(timeStr, now)
87 if err != nil {
88 return time.Time{}, fmt.Errorf("cannot parse time '%s', use UTC format '2006-01-02T15:04:05', "+
89 "time range or raw UnixNano directly. See help for more details: %s", timeStr, err)
90 }
91 return parsedTime, nil
92 }
93
94 // parseTimeRange parses a given time duration string (in format X<time-duration>) and
95 // returns parsed timestamp given that duration in the past from current time.
96 // All valid values must contain a number followed by a time-duration, from the following list (long form/short form):
97 // - second/s
98 // - minute/m
99 // - hour/h
100 // - day/d
101 // - week/w
102 // - month/M
103 // - year/y
104 // For example, possible input values, and their result:
105 // - "3d" or "3day" --> three days --> time.Now().UTC().Add(-3 * 24 * time.Hour)
106 // - "2m" or "2minute" --> two minutes --> time.Now().UTC().Add(-2 * time.Minute)
107 // - "1w" or "1week" --> one week --> time.Now().UTC().Add(-7 * 24 * time.Hour)
108 // - "30s" or "30second" --> thirty seconds --> time.Now().UTC().Add(-30 * time.Second)
109 // Note: Duration strings are case-sensitive, and should be used as mentioned above only.
110 // Limitation: Value of numerical multiplier, X should be in b/w 0 - 1e6 (1 million), boundary values excluded i.e.
111 // 0 < X < 1e6. Also, the maximum time in the past can be 1 January 1970 00:00:00 UTC (epoch time),
112 // so giving "1000y" will result in epoch time.
113 func parseTimeRange(timeRange string, now time.Time) (time.Time, error) {
114 match, err := regexp.MatchString(defaultDateTimeRangeShortRE, timeRange)
115 if !match { // fallback on to check if it's of longer notation
116 _, err = regexp.MatchString(defaultDateTimeRangeLongRE, timeRange)
117 }
118 if err != nil {
119 return time.Time{}, err
120 }
121
122 re, _ := regexp.Compile(defaultDateTimeRangeNum)
123 idx := re.FindStringSubmatchIndex(timeRange)
124 if idx == nil {
125 return time.Time{}, fmt.Errorf("cannot parse timeRange %s", timeRange)
126 }
127
128 num, err := strconv.Atoi(timeRange[idx[0]:idx[1]])
129 if err != nil {
130 return time.Time{}, fmt.Errorf("cannot parse timeRange %s", timeRange)
131 }
132 if num >= 1e6 {
133 return time.Time{}, fmt.Errorf("invalid time-duation multiplier %d, allowed range is 0 < multiplier < 1000000", num)
134 }
135
136 dur, err := parseTimeDuration(timeRange[idx[1]:])
137 if err != nil {
138 return time.Time{}, fmt.Errorf("cannot parse timeRange %s", timeRange)
139 }
140
141 res := now.Add(time.Duration(-num) * dur) // using server's local timezone
142 epochTime := time.Unix(0, 0).UTC()
143 if res.Before(epochTime) {
144 res = epochTime
145 }
146 return res, nil
147 }
148
149 // parseTimeDuration parses the given time duration in either short or long convention
150 // and returns the time.Duration
151 // Valid values (long notation/short notation):
152 // - second/s
153 // - minute/m
154 // - hour/h
155 // - day/d
156 // - week/w
157 // - month/M
158 // - year/y
159 // NOTE: the input "duration" is case-sensitive
160 func parseTimeDuration(duration string) (dur time.Duration, err error) {
161 switch duration {
162 case "s", "second":
163 dur = time.Second
164 case "m", "minute":
165 dur = time.Minute
166 case "h", "hour":
167 dur = time.Hour
168 case "d", "day":
169 dur = day
170 case "w", "week":
171 dur = week
172 case "M", "month":
173 dur = month
174 case "y", "year":
175 dur = year
176 default:
177 err = fmt.Errorf("unknown time duration %s", duration)
178 }
179 return
180 }
181
182 > func newContext(c *cli.Context) (context.Context, context.CancelFunc) { util.go ×3
183 > return newContextWithTimeout(c, defaultContextTimeout)
184 > }
185
186 > func newContextWithTimeout(c *cli.Context, timeout time.Duration) (context.Context, context.CancelFunc) { util.go ×3
187 > if c.IsSet(FlagContextTimeout) {
188 timeout = time.Duration(c.Int(FlagContextTimeout)) * time.Second
189 }
190
191 > return context.WithTimeout(c.Context, timeout) util.go ×3
192 }
193
194 > func StringToEnum(search string, candidates map[string]int32) (int32, error) { util.go ×1
195 > if search == "" {
196 > return 0, nil util.go ×1
197 > }
198
199 > var candidateNames []string util.go ×1
200 > for key, value := range candidates {
201 > if strings.EqualFold(key, search) { util.go ×2
202 > return value, nil util.go ×1
203 > }
204 > candidateNames = append(candidateNames, key) util.go ×2
205 }
206
207 > return 0, fmt.Errorf("could not find corresponding candidate for %s. Possible candidates: %q", search, candidateNames) util.go ×1
208 }
209
210 // paginate creates an interactive CLI mode to control the printing of items
211 func paginate[V any](c *cli.Context, paginationFn collection.PaginationFn[V], pageSize int) error {
212 more := c.Bool(FlagMore)
213 isTableView := !c.Bool(FlagPrintJSON)
214 iter := collection.NewPagingIterator(paginationFn)
215
216 var pageItems []any
217 for iter.HasNext() {
218 item, err := iter.Next()
219 if err != nil {
220 return err
221 }
222
223 pageItems = append(pageItems, item)
224 if len(pageItems) == pageSize || !iter.HasNext() {
225 if isTableView {
226 if err := printTable(pageItems, c.App.Writer); err != nil {
227 return err
228 }
229 } else {
230 prettyPrintJSONObject(c, pageItems)
231 }
232
233 if !more || !showNextPage(c.App.Writer) {
234 break
235 }
236 pageItems = pageItems[:0]
237 }
238 }
239
240 return nil
241 }
242
243 var exportRgx = regexp.MustCompile("^[A-Z]")
244
245 > func printTable(items []any, writer io.Writer) error { dlq_v2_service.go ×12
246 > if len(items) == 0 {
247 > return nil util.go ×1
248 > }
249
250 > e := reflect.ValueOf(items[0]) util.go ×5
251 > for e.Type().Kind() == reflect.Pointer {
252 e = e.Elem()
253 }
254
255 > var fields []string util.go ×5
256 > var exportedFields []int
257 > t := e.Type()
258 > for i := 0; i < e.NumField(); i++ {
259 > if exportRgx.MatchString(t.Field(i).Name) {
260 > fields = append(fields, t.Field(i).Name)
261 > exportedFields = append(exportedFields, i)
262 > }
263 }
264
265 > table := tablewriter.NewWriter(writer) util.go ×5
266 > table.SetBorder(false)
267 > table.SetColumnSeparator("|")
268 > table.SetHeader(fields)
269 > table.SetHeaderLine(false)
270 > for i := range items {
271 > item := reflect.ValueOf(items[i])
272 > for item.Type().Kind() == reflect.Pointer {
273 item = item.Elem()
274 }
275 > var columns []string util.go ×5
276 > for _, j := range exportedFields {
277 > col := item.Field(j)
278 > columns = append(columns, fmt.Sprintf("%v", col.Interface()))
279 > }
280 > table.Append(columns)
281 }
282 > table.Render() util.go ×5
283 > table.ClearRows()
284 >
285 > return nil
286 }
287
288 func showNextPage(wr io.Writer) bool {
289 fmt.Fprintf(wr, "Press %s to show next page, press %s to quit: ",
290 color.GreenString("Enter"), color.RedString("any other key then Enter"))
291 var input string
292 _, _ = fmt.Scanln(&input)
293 return strings.Trim(input, " ") == ""
294 }
295
296 func getNamespaceID(c *cli.Context, clientFactory ClientFactory, nsName namespace.Name) (namespace.ID, error) {
297 wfClient := clientFactory.WorkflowClient(c)
298
299 ctx, cancel := newContext(c)
300 defer cancel()
301
302 nsResponse, err := wfClient.DescribeNamespace(ctx, &workflowservice.DescribeNamespaceRequest{
303 Namespace: nsName.String(),
304 })
305 if err != nil {
306 return namespace.EmptyID, err
307 }
308
309 return namespace.ID(nsResponse.NamespaceInfo.GetId()), nil
310 }
311
312 func getArchetype(c *cli.Context) chasm.Archetype {
313 if c.IsSet(FlagArchetypeID) {
314 return ""
315 }
316
317 archetype := c.String(FlagArchetype)
318 if archetype != "" {
319 return archetype
320 }
321 return chasm.WorkflowArchetype
322 }