gogcli 中的gog maps distance:在终端批量计算 Google 路线距离矩阵
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
本文围绕 gogcli 的命令参考页 gog-maps-distance.md 展开,完整覆盖gog maps distance的用法、参数与输出格式,并结合 internal/cmd/maps.go 与 internal/googleapi/maps.go 的源码实现,讲解该命令如何解析 CSV 起终点、校验出行方式与单位、构造 Distance Matrix API 请求,以及如何将结果渲染为 TSV 表格或 JSON——读完你可以直接在脚本与 CI 中批量查询多点间的旅行距离与耗时。
命令概览
gog maps distance是 gog maps 子命令族的一员(maps另有别名map),用于获取"旅行距离与耗时矩阵"(travel distance and duration matrix),即一次请求返回多个起点到多个终点的距离/耗时组合。它支持两个别名:
distance-matrixmatrix
基本调用形式如下:
gog maps (map) distance (distance-matrix,matrix) --origins=STRING --destinations=STRING [flags]两个必填参数均接收逗号分隔的地址列表,例如:
gog maps distance \ --origins="Barcelona,Madrid" \ --destinations="Blanes,Girona" \ --mode=driving \ --units=metric参数详解
专用参数
| 参数 | 类型 | 说明 | 取值约束 |
|---|---|---|---|
--origins | string | 起点列表(必填) | 逗号分隔;源码中经splitCSV切分,空串被剔除 |
--destinations | string | 终点列表(必填) | 逗号分隔;同上 |
--mode | string | 出行方式 | driving|walking|bicycling|transit,大小写不敏感;缺省时不传该参数 |
--units | string | 距离单位 | metric|imperial,大小写不敏感;缺省时不传该参数 |
--language | string | BCP-47 语言代码 | 任意字符串,原样透传为 API 的language参数 |
--region | string | 区域偏好(region bias) | 任意字符串,透传为 API 的region参数 |
取值范围不是"文档约定",而是由命令运行时的归一化函数强制执行的。internal/cmd/maps.go 中的normalizeMapsMode与normalizeMapsUnits只做小写化与白名单匹配:
func normalizeMapsMode(raw string) (string, error) { v := strings.TrimSpace(strings.ToLower(raw)) switch v { case "": return "", nil case "driving", "walking", "bicycling", "transit": return v, nil default: return "", usagef("invalid --mode %q (expected driving, walking, bicycling, or transit)", raw) } }一个值得注意的实现细节:参数校验发生在建立 API 客户端之前(即先校验--mode/--units,再解析 API Key),因此传错取值时不会消耗任何 API 配额。测试 TestMapsDistanceRejectsInvalidUnitsBeforeAPIKey 专门验证了这一点——在未设置任何 API Key 的情况下传入--units=parsecs,命令即返回invalid --units错误而非"缺少 Key"错误。
全局参数
gog maps distance与所有 gogcli 命令共享一组根级参数(完整列表见 命令参考页 的 Flags 表)。与脚本化使用本命令最相关的几个:
| 参数 | 说明 |
|---|---|
-j/--json/--machine | 以 JSON 输出到 stdout,适合脚本处理 |
-p/--plain/--tsv | 输出稳定、可解析的 TSV 文本,无颜色 |
--account(-a) | 指定账号邮箱、别名或auto |
--access-token | 直接使用给定 access token(绕过本地存储的 refresh token,约 1 小时过期) |
--quota-project | 计费到指定 GCP 项目(X-Goog-User-Project) |
--dry-run(-n) | 不实际发起变更,仅打印将要执行的动作 |
--readonly | 运行时拦截变更类 API 请求 |
--results-only | JSON 模式下只输出主结果 |
--select | JSON 模式下按点路径选取字段 |
输出格式
表格模式(默认)
internal/cmd/maps.go 中的writeMapsDistance决定默认输出:遍历响应中的每一行(对应一个起点)、每个元素(对应一个终点),打印五行制表符分隔的记录:
ORIGIN DESTINATION STATUS DISTANCE DURATION其中起点/终点名称取自响应的origin_addresses/destination_addresses解析后的地址列表,通过indexString按索引安全取值(越界时输出空串)。当响应为空或没有任何行时,向 stderr 打印No distances。
JSON 模式
加上--json后,writeMapsDistance直接把整个响应对象包进distanceMatrix键输出:
gog maps distance --origins=Barcelona --destinations=Blanes,Girona --mode=driving --jsonJSON 结构来自 internal/googleapi/maps.go 定义的反序列化类型:
type MapsDistanceMatrixResponse struct { Status string `json:"status,omitempty"` ErrorMessage string `json:"error_message,omitempty"` OriginAddresses []string `json:"origin_addresses,omitempty"` DestAddresses []string `json:"destination_addresses,omitempty"` Rows []MapsDistanceMatrixRow `json:"rows,omitempty"` } type MapsDistanceMatrixRow struct { Elements []MapsDistanceMatrixElement `json:"elements,omitempty"` } type MapsDistanceMatrixElement struct { Status string `json:"status,omitempty"` Distance MapsTextValue `json:"distance,omitempty"` Duration MapsTextValue `json:"duration,omitempty"` }其中MapsTextValue同时保留人类可读文本与原始数值:
type MapsTextValue struct { Text string `json:"text,omitempty"` Value int64 `json:"value,omitempty"` }因此脚本中做数值比较(如"哪条路线最短")应使用distance.value(米)与duration.value(秒),而text仅用于展示。
源码级实现:从命令到 HTTP 请求
gog maps distance的执行链路可以概括为四层:
命令层:MapsDistanceCmd.Run 解析参数。它先用
splitCSV切分--origins/--destinations,任一列表为空则报--origins and --destinations are required用法错误;随后归一化--mode与--units,再创建客户端并调用client.DistanceMatrix。客户端构造:newMapsClient 从配置读取 API Key(见下文),并用环境变量
GOG_MAPS_BASE_URL覆盖默认端点:return googleapi.NewMapsClient(apiKey, googleapi.WithMapsBaseURL(os.Getenv("GOG_MAPS_BASE_URL"))), nil默认端点在 internal/googleapi/maps.go 定义为
https://maps.googleapis.com/maps/api,HTTP 客户端超时为 10 秒。请求构造:MapsClient.DistanceMatrix 把切分后的起点/终点列表用
|连接(strings.Join(trimNonEmpty(origins), "|"),这是 Google Distance Matrix API 要求的多值分隔符),再按需追加mode、units、language、region,最终通过doGet发起GET /distancematrix/json,API Key 作为key查询参数附带。响应处理与错误映射:
doGet限制响应体最多读取 2 MiB(io.LimitReader),非 2xx 状态码直接报错。JSON 解析成功后,mapsStatusError做业务状态判定:if status == "" || status == "OK" || status == "ZERO_RESULTS" { return nil }也就是说
OK与ZERO_RESULTS不算错误(后者会走"No distances"的空结果分支),而REQUEST_DENIED、OVER_QUERY_LIMIT等状态则携带error_message转为 CLI 错误返回。
API Key 从哪来
maps distance与 Places 系命令共用 Key 解析逻辑 placesAPIKey,优先级为:
- gogcli 配置文件中的
places_api_key(可用gog config set places_api_key <key>写入); - 环境变量
GOG_PLACES_API_KEY; - 环境变量
GOOGLE_PLACES_API_KEY。
三者均未设置时,命令会直接给出可操作的报错提示:"Google Maps/Places API key required. Set GOG_PLACES_API_KEY, GOOGLE_PLACES_API_KEY, or run 'gog config set places_api_key '"。
端点可覆盖与测试方式
GOG_MAPS_BASE_URL允许把整个 Maps 端点重定向到任意 HTTP 服务,这使得离线开发与测试成为可能。internal/cmd/maps_test.go 中的 Directions/Geocode 用例就用httptest.NewServer模拟/directions/json、/geocode/json端点,并断言请求中确实携带了key查询参数:
t.Setenv("GOG_MAPS_BASE_URL", srv.URL)distance参数层的用例(如 TestMapsDistanceRejectsInvalidUnitsBeforeAPIKey)则证明了"先本地校验、后消耗配额"的行为契约。
实战要点与常见错误
- 地址格式:
--origins/--destinations中每个元素可传地址文本、"lat,lng"坐标或 Place ID——这正是 Google Distance Matrix API 接受的形式;gogcli 本身只做切分、去空白与|拼接,不做地址解析,因此地址合法性由 Google 服务端裁定(反映在元素级status中,如NOT_FOUND)。 - 矩阵规模:行数等于起点数,每行元素数等于终点数;批量查询时注意起点/终点数量相乘后的元素总量,避免触发 Google 配额限制(
OVER_QUERY_LIMIT会直接作为错误抛出,见上文状态映射逻辑)。 - 单位语义:
--units只影响distance.text的展示单位(km/mi),distance.value始终为米;duration.value始终为秒。脚本逻辑请始终基于value字段。 - 典型报错速查:
--origins and --destinations are required:CSV 切分后为空(例如只传了逗号)。invalid --mode ... (expected driving, walking, bicycling, or transit):出行方式不在白名单。invalid --units ... (expected metric or imperial):单位不在白名单。maps API error OVER_QUERY_LIMIT: ...:Google 配额/限流,属服务端业务状态而非网络错误。
相关命令
gog maps distance是 maps 子命令族中"批量矩阵"定位的成员,单点对单点的场景可改用同族命令(见 gog-maps.md):
| 命令 | 用途 |
|---|---|
| gog maps directions | 两点间路线(含summary与逐段legs) |
| gog maps geocode | 地址转坐标 |
| gog maps reverse-geocode | 坐标转地址 |
| gog maps places | Places 文本搜索与详情 |
完整的命令索引见 docs/commands/README.md;这些命令参考页由make docs-commands从gog schema --json自动生成,请勿手工编辑。
【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考