98 lines
3.4 KiB
Go
98 lines
3.4 KiB
Go
// Copyright 2026 Alibaba Group
|
|
// 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 shortcut
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"time"
|
|
)
|
|
|
|
const maxAutoPageDelayMS = int64(math.MaxInt64) / int64(time.Millisecond)
|
|
|
|
// AutoPageControlFlags returns the shared item and pacing controls used by
|
|
// cursor-based shortcuts. Callers retain ownership of --page-all and their
|
|
// product-specific --page-limit defaults.
|
|
func AutoPageControlFlags() []Flag {
|
|
const evidence = "--max-items/--page-delay 仅与 --page-all 一起使用;值必须大于等于 0"
|
|
return []Flag{
|
|
{Name: "max-items", Type: FlagInt, Desc: "自动翻页最多返回条数(默认 0 表示不限制)。" + evidence},
|
|
{Name: "page-delay", Type: FlagInt, Desc: "自动翻页每页之间等待毫秒数(默认 0 表示不等待)。" + evidence},
|
|
}
|
|
}
|
|
|
|
// AutoPageControlConstraints publishes the runtime-only relationship between
|
|
// the pagination switch and its shared controls into Help and Schema.
|
|
func AutoPageControlConstraints() []Constraint {
|
|
return []Constraint{{
|
|
Kind: ConstraintCustom,
|
|
Flags: []string{"page-all", "max-items", "page-delay"},
|
|
Description: "--max-items/--page-delay 仅与 --page-all 一起使用;值必须大于等于 0",
|
|
}}
|
|
}
|
|
|
|
// ValidateAutoPageControls enforces the shared contract while preserving the
|
|
// historical behavior that defaulted controls do not activate pagination.
|
|
func ValidateAutoPageControls(rt *RuntimeContext) error {
|
|
if !rt.Bool("page-all") {
|
|
if rt.Changed("max-items") || rt.Changed("page-delay") {
|
|
return fmt.Errorf("--max-items/--page-delay 仅与 --page-all 一起使用")
|
|
}
|
|
return nil
|
|
}
|
|
if rt.Int("max-items") < 0 {
|
|
return fmt.Errorf("--max-items 必须大于等于 0")
|
|
}
|
|
delayMS := rt.Int("page-delay")
|
|
if delayMS < 0 {
|
|
return fmt.Errorf("--page-delay 必须大于等于 0")
|
|
}
|
|
if int64(delayMS) > maxAutoPageDelayMS {
|
|
return fmt.Errorf("--page-delay 不能大于 %d 毫秒", maxAutoPageDelayMS)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// AutoPageRequestSize caps the next lower-page request to the remaining item
|
|
// budget. A cursor returned for that request is therefore safe to resume from:
|
|
// the CLI did not intentionally discard a suffix of the lower page.
|
|
func AutoPageRequestSize(rt *RuntimeContext, pageSize, itemCount int) int {
|
|
maxItems := rt.Int("max-items")
|
|
if maxItems <= 0 {
|
|
return pageSize
|
|
}
|
|
remaining := maxItems - itemCount
|
|
if remaining > 0 && remaining < pageSize {
|
|
return remaining
|
|
}
|
|
return pageSize
|
|
}
|
|
|
|
// WaitAutoPageDelay waits between successful pages and remains cancellable so
|
|
// a throttled pagination run cannot ignore command cancellation.
|
|
func WaitAutoPageDelay(rt *RuntimeContext) error {
|
|
delayMS := rt.Int("page-delay")
|
|
if delayMS <= 0 {
|
|
return nil
|
|
}
|
|
timer := time.NewTimer(time.Duration(int64(delayMS)) * time.Millisecond)
|
|
defer timer.Stop()
|
|
select {
|
|
case <-rt.Command().Context().Done():
|
|
return rt.Command().Context().Err()
|
|
case <-timer.C:
|
|
return nil
|
|
}
|
|
}
|