add kiro skills

This commit is contained in:
Rongsong Shen 2026-05-21 03:41:57 +00:00
parent e5fde7b55f
commit 86fe35e671
53 changed files with 8406 additions and 166 deletions

View file

@ -146,6 +146,7 @@ func (p *HostsPagePrinter) formatRows(hosts *models.HostsResponse, truncatFlag b
truncatFlag = false
}
for _, host := range hosts.Data.Rows {
isUnavail := host.HostStatus == "UNAVAIL"
row := make([]string, 0, len(p.fieldFormats))
for _, format := range p.fieldFormats {
width := p.columnWidths[format.name]
@ -156,17 +157,41 @@ func (p *HostsPagePrinter) formatRows(hosts *models.HostsResponse, truncatFlag b
case models.HEADER_HOST_STATUS:
row = appendOrDefault(row, FormatStringField(host.HostStatus, width, truncatFlag, true), "-")
case models.HEADER_HOST_HOST_TYPE:
row = appendOrDefault(row, FormatStringField(host.HostType, width, truncatFlag, true), "-")
if isUnavail {
row = append(row, FormatStringField("UNKNOWN", width, truncatFlag, true))
} else {
row = appendOrDefault(row, FormatStringField(host.HostType, width, truncatFlag, true), "-")
}
case models.HEADER_HOST_NCPUS:
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumCPUs), "0")
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumCPUs), "0")
}
case models.HEADER_HOST_MAX_SLOT:
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.MaxSlot), "0")
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.MaxSlot), "0")
}
case models.HEADER_HOST_NUM_RUN:
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumRun), "0")
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumRun), "0")
}
case models.HEADER_HOST_NUM_SSUSP:
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumSSusp), "0")
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumSSusp), "0")
}
case models.HEADER_HOST_NUM_USUSP:
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumUSusp), "0")
if isUnavail {
row = append(row, FormatStringField("-", width, truncatFlag, true))
} else {
row = appendOrDefault(row, fmt.Sprintf("%"+align+"*d", width, host.NumUSusp), "0")
}
}
}
rows = append(rows, row)
@ -188,6 +213,7 @@ func (p *HostsPagePrinter) printJsonPage(hosts *models.HostsResponse) {
func printHostsVerboseOutput(hosts *models.HostsResponse) {
for _, host := range hosts.Data.Rows {
isUnavail := host.HostStatus == "UNAVAIL"
fmt.Printf("HOST %s\n", host.HostName)
// table 1
headers := models.HostDetailHeaders
@ -199,19 +225,43 @@ func printHostsVerboseOutput(hosts *models.HostsResponse) {
case models.HEADER_HOST_STATUS:
val = host.HostStatus
case models.HEADER_HOST_CPUF:
val = fmt.Sprintf("%.2f", host.CPUFactor)
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%.2f", host.CPUFactor)
}
case models.HEADER_HOST_JLU:
val = "-"
case models.HEADER_HOST_MAX:
val = fmt.Sprintf("%d", host.MaxSlot)
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.MaxSlot)
}
case models.HEADER_HOST_NJOBS:
val = fmt.Sprintf("%d", host.NumRun)
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumRun)
}
case models.HEADER_HOST_RUN:
val = fmt.Sprintf("%d", host.NumRun)
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumRun)
}
case models.HEADER_HOST_SSUSP:
val = fmt.Sprintf("%d", host.NumSSusp)
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumSSusp)
}
case models.HEADER_HOST_USUSP:
val = fmt.Sprintf("%d", host.NumUSusp)
if isUnavail {
val = "-"
} else {
val = fmt.Sprintf("%d", host.NumUSusp)
}
case models.HEADER_HOST_RSV:
val = "-"
case models.HEADER_HOST_DISPT_WINDOW:
@ -234,8 +284,14 @@ func printHostsVerboseOutput(hosts *models.HostsResponse) {
// table2
headers2 := append([]string{""}, models.HostLoadSchedulingHeaders...)
totalVals := []string{"Total", "0.0", "0.0", "0.0", "1%", "0.0", "33", "1", "1137", "51G", "3.9G", "6.8G", "8", "0.0"}
reserveVals := []string{"Reserved", "0.0", "0.0", "0.0", "0%", "0.0", "0", "0", "0", "0M", "0M", "0M", "-", "-"}
var totalVals, reserveVals []string
if isUnavail {
totalVals = []string{"Total", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"}
reserveVals = []string{"Reserved", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-", "-"}
} else {
totalVals = []string{"Total", "0.0", "0.0", "0.0", "1%", "0.0", "33", "1", "1137", "51G", "3.9G", "6.8G", "8", "0.0"}
reserveVals = []string{"Reserved", "0.0", "0.0", "0.0", "0%", "0.0", "0", "0", "0", "0M", "0M", "0M", "-", "-"}
}
widths2 := make([]int, len(headers2))
for i := range headers2 {

View file

@ -0,0 +1,103 @@
package output
import (
"strings"
"testing"
"xcecli/models"
)
func makeHostsResponse(hosts ...models.XCEHost) *models.HostsResponse {
r := &models.HostsResponse{}
r.Data.Rows = hosts
r.Data.Count = len(hosts)
return r
}
func TestFormatRows_UnavailShowsDashes(t *testing.T) {
host := models.XCEHost{
HostName: "pc13v",
HostStatus: "UNAVAIL",
NumCPUs: 16,
MaxSlot: 32,
NumRun: 5,
NumSSusp: 2,
NumUSusp: 1,
HostType: "*6_64-linux-gnu",
}
resp := makeHostsResponse(host)
p := NewHostsPagePrinter()
p.PrepareForPrinting(resp)
rows := p.formatRows(resp, false)
if len(rows) != 1 {
t.Fatalf("expected 1 row, got %d", len(rows))
}
row := rows[0]
// Build a map from trimmed value by column header index.
headers := p.fieldFormats
vals := make(map[string]string, len(headers))
for i, f := range headers {
vals[f.name] = strings.TrimSpace(row[i])
}
for _, col := range []string{
models.HEADER_HOST_NCPUS,
models.HEADER_HOST_MAX_SLOT,
models.HEADER_HOST_NUM_RUN,
models.HEADER_HOST_NUM_SSUSP,
models.HEADER_HOST_NUM_USUSP,
} {
if vals[col] != "-" {
t.Errorf("UNAVAIL host: %s = %q, want \"-\"", col, vals[col])
}
}
if vals[models.HEADER_HOST_HOST_TYPE] != "UNKNOWN" {
t.Errorf("UNAVAIL host: HOST_TYPE = %q, want \"UNKNOWN\"", vals[models.HEADER_HOST_HOST_TYPE])
}
}
func TestFormatRows_AvailableShowsValues(t *testing.T) {
host := models.XCEHost{
HostName: "pc14v",
HostStatus: "OK",
NumCPUs: 16,
MaxSlot: 32,
NumRun: 5,
NumSSusp: 2,
NumUSusp: 1,
HostType: "linux",
}
resp := makeHostsResponse(host)
p := NewHostsPagePrinter()
p.PrepareForPrinting(resp)
rows := p.formatRows(resp, false)
if len(rows) != 1 {
t.Fatalf("expected 1 row, got %d", len(rows))
}
row := rows[0]
headers := p.fieldFormats
vals := make(map[string]string, len(headers))
for i, f := range headers {
vals[f.name] = strings.TrimSpace(row[i])
}
checks := map[string]string{
models.HEADER_HOST_NCPUS: "16",
models.HEADER_HOST_MAX_SLOT: "32",
models.HEADER_HOST_NUM_RUN: "5",
models.HEADER_HOST_NUM_SSUSP: "2",
models.HEADER_HOST_NUM_USUSP: "1",
models.HEADER_HOST_HOST_TYPE: "linux",
}
for col, want := range checks {
if vals[col] != want {
t.Errorf("OK host: %s = %q, want %q", col, vals[col], want)
}
}
}

View file

@ -5,6 +5,19 @@ import (
"time"
)
// parseJobTime parses a time string in RFC3339 or "2006-01-02 15:04:05" format.
func parseJobTime(s string) (time.Time, error) {
if s == "" {
return time.Time{}, fmt.Errorf("empty time string")
}
for _, layout := range []string{time.RFC3339Nano, time.RFC3339, "2006-01-02 15:04:05"} {
if t, err := time.Parse(layout, s); err == nil {
return t, nil
}
}
return time.Time{}, fmt.Errorf("cannot parse time %q", s)
}
// unixToTime converts a Unix-second timestamp to time.Time.
// Returns (time, true) for ts > 0; (zero, false) for unset/zero values.
func unixToTime(ts int64) (time.Time, bool) {