news 2026/9/17 11:14:42

gogcli 中的 `gog maps distance`:在终端批量计算 Google 路线距离矩阵

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
gogcli 中的 `gog maps distance`:在终端批量计算 Google 路线距离矩阵

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-matrix
  • matrix

基本调用形式如下:

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

参数详解

专用参数

参数类型说明取值约束
--originsstring起点列表(必填)逗号分隔;源码中经splitCSV切分,空串被剔除
--destinationsstring终点列表(必填)逗号分隔;同上
--modestring出行方式driving|walking|bicycling|transit,大小写不敏感;缺省时不传该参数
--unitsstring距离单位metric|imperial,大小写不敏感;缺省时不传该参数
--languagestringBCP-47 语言代码任意字符串,原样透传为 API 的language参数
--regionstring区域偏好(region bias)任意字符串,透传为 API 的region参数

取值范围不是"文档约定",而是由命令运行时的归一化函数强制执行的。internal/cmd/maps.go 中的normalizeMapsModenormalizeMapsUnits只做小写化与白名单匹配:

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-onlyJSON 模式下只输出主结果
--selectJSON 模式下按点路径选取字段

输出格式

表格模式(默认)

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 --json

JSON 结构来自 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的执行链路可以概括为四层:

  1. 命令层:MapsDistanceCmd.Run 解析参数。它先用splitCSV切分--origins/--destinations,任一列表为空则报--origins and --destinations are required用法错误;随后归一化--mode--units,再创建客户端并调用client.DistanceMatrix

  2. 客户端构造: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 秒。

  3. 请求构造:MapsClient.DistanceMatrix 把切分后的起点/终点列表用|连接(strings.Join(trimNonEmpty(origins), "|"),这是 Google Distance Matrix API 要求的多值分隔符),再按需追加modeunitslanguageregion,最终通过doGet发起GET /distancematrix/json,API Key 作为key查询参数附带。

  4. 响应处理与错误映射doGet限制响应体最多读取 2 MiB(io.LimitReader),非 2xx 状态码直接报错。JSON 解析成功后,mapsStatusError做业务状态判定:

    if status == "" || status == "OK" || status == "ZERO_RESULTS" { return nil }

    也就是说OKZERO_RESULTS不算错误(后者会走"No distances"的空结果分支),而REQUEST_DENIEDOVER_QUERY_LIMIT等状态则携带error_message转为 CLI 错误返回。

API Key 从哪来

maps distance与 Places 系命令共用 Key 解析逻辑 placesAPIKey,优先级为:

  1. gogcli 配置文件中的places_api_key(可用gog config set places_api_key <key>写入);
  2. 环境变量GOG_PLACES_API_KEY
  3. 环境变量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 placesPlaces 文本搜索与详情

完整的命令索引见 docs/commands/README.md;这些命令参考页由make docs-commandsgog schema --json自动生成,请勿手工编辑。

【免费下载链接】gogcliGoogle Workspace in your terminal.项目地址: https://gitcode.com/GitHub_Trending/gogcl/gogcli

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 11:10:33

Java Web实习系统:JSP+Servlet+MySQL实战搭建与论文转化

简介&#xff1a;本资源是一篇面向高校计算机专业本科生与实习指导教师的毕业设计类论文&#xff0c;聚焦基于JSP与MySQL技术构建的实习实训管理系统&#xff0c;解决传统线下管理效率低、信息分散、流程不透明等痛点。论文完整覆盖需求分析、系统设计、数据库建模、JSP页面开发…

作者头像 李华
网站建设 2026/9/17 11:09:14

MySQL 8.0关键字与保留字避坑指南:从报错到规范

先从一个上周刚处理过的工单说起。业务同学建了一张客户反馈表&#xff0c;字段直接命名为desc&#xff0c;用来存描述内容。建表的时候一切正常&#xff0c;一到应用联调就报错&#xff1a;ERROR 1064&#xff0c;看错误日志定位到一条select desc from feedback ...&#xff…

作者头像 李华
网站建设 2026/9/17 11:07:58

Mac/Windows 部署 OpenClaw,模型通道接到 TaoToken 行不行?

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/17 11:06:16

青少年开源创新:AI与游戏开发的新力量

1. 青少年开源论坛&#xff1a;当00后开始改变世界第一次在COSCon青少年开源论坛现场&#xff0c;我完全被震撼了——台上演讲的是一群平均年龄不到16岁的孩子&#xff0c;他们展示的项目却让台下数百位资深开发者频频点头。有人用AI技术保护濒危方言&#xff0c;有人在Minecra…

作者头像 李华
网站建设 2026/9/17 11:06:11

CPU微架构:超标量与超线程,突破单指令流的两条路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华