首页 >> 大全

AI 加持的代码编写实战:快速实现 Nginx 配置格式化工具

2023-08-12 大全 29 作者:考证青年

本篇文章聊聊如何使用 GPT 快速完成一个开源小项目,解决实际的问题,顺手点亮 上 Nginx 开源社区的贡献者图标。

“Talk is Cheap,Show you the Code。”

写在前面

整理了一篇本该上个月就发出的内容。

前段时间,有个投资人朋友,问了我好几会到底如何使用 GPT 或相关工具来写代码的,希望能有个“step by step”的教程,正巧前几天有这么一个例子,就写一篇文章吧。

其实,我之前已经写过很多篇关于 Nginx 的实践内容了,我很难说我不喜欢这款实践性极强的开源软件。上个月在折腾内部服务的时候,再次用到了 Nginx 这个老伙计,以及我曾经分享过很多次的 NJS。

为了更快的验证功能(偷懒不想写代码),我打开了 上 Nginx 官方社区的 nginx/njs- 寻找示例配置。

当我在代码编辑器里打开官方项目的配置时,映入眼帘的是方佛是从 90 年代到现在的内容:

不光是因为有“强迫症”(代码洁癖),更是因为我希望 Nginx 的配置文件都是简洁、美观,以及可靠的,如果没有靠谱好用的 Nginx 格式化工具,那么就做一个呗。

毕竟,Talk is Cheap。

完整项目,我已经上传到了 /nginx-,希望它能帮到你。

当然,也十分欢迎一键三连。

方案设计

动手之前,我们最好先做一个简单的规划,以及针对这个规划做一些适当的可行性调研。

社区已有项目调研

我简单翻阅了社区中有关于 Nginx 配置格式化相关的项目,包括其中一个已经坚持了 7 年的格式化开源软件 的代码和历史演进过程。

我发现在 社区中,Nginx 代码格式化相关的工具不多,但却分为了三种语言阵营,两种玩法。按照语言来分类:

按照处理方式来看,则是下面两类玩法:

第一种方法,相对比较“治标”,解决问题会更快一些,但可能会因为 Nginx 配置的演进越来越复杂,解析、格式化能力跟不上迭代,以及判断逻辑不够周全,导致格式化出错。

比如,/-nginx- 这个在 插件市场里被下载了二十万次的插件,就是采用这种方案(基于 JS 版本的 ),以至于有用户确实反馈,会“损坏”配置。

第二种方法,相对比较“治本”,解决问题更靠谱,但是需要完整的了解 Nginx 配置文件的定义,实现起来需要额外的一些时间。

况且,我也不太相信创建项目有一段时间的语法解析方案,对于现在的 Nginx 配置的支持能力,目前的 Nginx 配置丰富程度早已经不是早些年可比的了。

所以,这里我们先来实现一个能解决问题,但是不那么完美的方案吧。

使用 做方案交叉验证

当然,在实现之前,我们可以使用 等方法,来对我们想要做的事情,或者想法进行任务拆解或分析,来为我们“查缺补漏”。

类似的工具很多,社区里随便找一个用 跑起来就好。因为模型的结果有一定的随机性,所以我们可以反复尝试,以及适当调整 “”,让模型的回答更全面一些。 因为很多项目里使用的“提示咒语”默认都是英文,所以在执行之后,得到的结果也都是英文的结果。

这里我们可以使用 来进行偷懒,只需要把内容复制粘贴到 里,然后在上面添加一句要求:“将下面的内容翻译为中文”。

然后,我们稍等片刻,这些内容就变成了阅读更简单的母语内容啦。

最终方案设计

结合上文提到的各种内容,结合实现时间成本,我们考虑使用“基于字符串特征进行格式化处理”的方案来解决问题。

我期望工具能够开箱即用,没有任何依赖问题,所以我的基础技术栈选择的是 。

然而, 生态下,并没有类似 或者 生态的格式化工具库,所以我们需要手动实现一个格式化工具库,或者让社区的 或者 代码能够在我们的 程序中运行,内化为我们程序的一部分。

相比较前者,后者的代码实现更少一些,实现速度更快一些,所以我们就用这个方式来玩吧。

实战:询问 GPT 如何实现基础功能

在前文中,我们提到了开源社区现在的各种实现,以及我们计划使用的方案。在实际 的时候,我们可以借助 来完成逻辑。

为了演示最低成本的实现,这里我们虽然能够使用 GPT-4,但是考虑到多数人还是有使用限制,我们用 GPT 3.5 来实现我们所需要的东西。

调整 版的格式化程序实现

虽然 版的格式化程序有用户吐槽,但其实,只要我们修正其中的“ cases”,程序还是能够使用的。完整代码在项目中的 /nginx-///.js,两百行出头。整体结构如下:

/*** - Soulteary Modify the JavaScript version for golang execution, under [Apache-2.0 license], 18/04/2023:*   - simplify the program, fix bugs, improve running speed, and allow running in golang*   - https://github.com/soulteary/nginx-formatter** History:* - Yosef Ported the JavaScript beautifier under [Apache-2.0 license], 24/08/2016*   - https://github.com/vasilevich/nginxbeautifier* - Slomkowski Created a beautifier for nginx config files with Python under [Apache-2.0 license], 24/06/2016*   - https://github.com/1connect/nginx-config-formatter (https://github.com/slomkowski/nginx-config-formatter)*//*** Grabs text in between two seperators seperator1 thetextIwant seperator2* @param {string} input String to seperate* @param {string} seperator1 The first seperator to use* @param {string} seperator2 The second seperator to use* @return {string}*/
function extractTextBySeperator(input, seperator1, seperator2) {
...
}/*** Grabs text in between two seperators seperator1 thetextIwant seperator2* @param {string} input String to seperate* @param {string} seperator1 The first seperator to use* @param {string} seperator2 The second seperator to use* @return {object}*/
function extractAllPossibleText(input, seperator1, seperator2) {
...
}/*** @param {string} single_line the whole nginx config* @return {string} stripped out string without multi spaces*/
function strip_line(single_line) {
...
}/*** @param {string} configContents the whole nginx config*/
function clean_lines(configContents) {
...
}function join_opening_bracket(lines) {
...
}function fold_empty_brackets(lines) {
...
}function add_empty_line_after_nginx_directives(lines) {
...
}function fixDollarVar(lines) {
...
}var options = { INDENTATION: "\t" };function perform_indentation(lines) {
...
}function FormatNginxConf(text, indentSize = 2, indentChar = " ") {
...
}

在实现的过程中,你有任何懒得动手的地方,都可以交给 ,比如张贴之前的老代码,询问它这段代码的含义:

尤其是对于陈旧的老代码(特别是别人写的),我们可以通过 来进行含义解读,并且要求它来一些代码的单元测试。这样可以极大的缩短我们在阅读代码上花费的时间。

_格式化代码的快捷键_怎么用代码格式化硬盘

当然,很多时候,它生成的内容是有问题的,需要我们进行仔细甄别或进行额外的测试验证。但即使如此,也会比我们从零到一自己搞来的快。

让 能够在 中运行

前文提到,因为 中没有类似 或者 类似的工具库,所以最快完成我们需求的方式,除了切换技术栈之外,就是将这些不同语言的程序,在 中直接运行。

这里我们询问下 :“如何在 中运行 代码”。

能够看到,在 的回答中,推荐我们使用 goja,并给出了最简单的实现。这个项目确实是一个有趣的项目,使用纯 Go 实现的 ECMA 5.1 解析引擎,能让我们在 中直接运行 代码。

当然,除了 goja 之外,参考我之前一个的开源项目/rss-can,我们也可以使用更强悍的 v8go 来实现这个功能,实际执行速度更快一些,但会让构建文件的体积稍大一些。

让程序能够一个文件解决战斗

前文提到,我们希望程序能够“一个文件走天下”,不需要带着一堆依赖、配置文件等乱七八糟的东西。

我们都知道 能够编译成一个文件,但是一般情况下只能处理 Go 文件的编译构建。那么如何将 变成 的一部分呢?如果是你我的老读者,你一定会想起我曾经提到的 go embed 嵌入方案。

如果你没有了解过这个技术方案,我推荐你看一下 资源嵌入方案,了解它的来龙去脉、几种方案的性能几何。

不过,这里我们想实现具体功能,并且越快越好,我们不妨直接问问 :“如何在 里使用 Embed ,嵌入一个 JS 文件。”

使用追问,完成我们要的代码

比如,在上面的章节中,我们询问如何在 中运行 代码。

结合实际需要,我们应该需要构建一个 Go 的格式化函数,接受一些必要的参数,比如:原始配置内容、缩进数量、缩进符。

那么我们可以在具体的会话中,追加问题:

一般情况下, 的表现是可以的:

类似上面提到的具体代码实现,我们在写工具的过程中会有许多许多。

但是并非每次生成的代码,都能够派上用场,以及并非每次的代码都是正确的,这时,我们可以基于已经生成好的代码,进行多轮对话,让 的答案,能够接近我们的需求,如果答的不对,我们可以让他重新生成。如果多次重新生成依旧不能让你满意,那么大概率是问题提的不够贴近,我们需要适当调整问题。

优化程序生成的代码

就上面的代码而言,虽然能够满足需求,但是写的未免太过于啰嗦。而默认生成的代码一般都是直白的逻辑呈现,并且因为我们的提问都比较简单,所以都有一些啰嗦。

所以,我们需要针对 GPT 生成的内容做一些优化,比如上面提到的比较关键的 函数(位于项目位置 /nginx-///.go):

package formatterimport ("fmt""github.com/dop251/goja"
)func Formatter(s string, indent int, char string) (string, error) {if s == "" {return "", nil}vm := goja.New()v, err := vm.RunString(fmt.Sprintf("%s;FormatNginxConf(`%s`, %d, `%s`)", JS_FORMATTER, s, indent, char))if err != nil {return "", err}return v.String(), nil
}

当然,在过程中你也可以咨询 ,具体的细节优化,函数使用。

实战:完善程序阶段

当我们把程序的核心功能实现完毕之后,剩下的就都是比较通用的边边角角的功能或者“质量保证”相关的测试啦。

编写一般功能,都比较简单,使用下面的句式即可完成任务:

这里就不多做展开,浪费篇幅了,我们聊聊比较典型的单元测试。

使用 GPT 完成单元测试

应该不会有太多工程师对于写测试感兴趣,尤其是程序频繁变动的前提下,我们写的测试越多,可能随着项目变化变成废代码的可能性也就越高。

但是,如果不需要我们动手,这个事情就能完成呢?

比如,我们将上面的代码直接粘贴到 中,要求他完成单元测试。

如果是上下文不够明确、缺少 注释的函数,一般会生成比较泛的代码,如果你愿意完善注释或者多提供一些上下文,那么你将得到覆盖率 80~90%,甚至完全覆盖的测试代码。

实战:编写效率提升

除了和 聊天,笨笨的复制粘贴代码之外,是否还有更偷懒的方式写代码呢?

答案是有的,借助离线和在线的语言模型即可。

本地代码补全模型的使用

关于离线模型做代码补全,是一个老话题了,如果你追求更快的实时性,以及和代码工具的贴合程度。就个人体验来说,我暂时还推荐 。

至于其他的工具,建议感兴趣的同学自己试试看,包括性能、生成结果、代码 IDE 的兼容性等等,感觉差距还是挺明显的。

我使用了三年左右,本地模型尺寸拢共 1.2G,如果一周写代码的时间比较多,至少能够帮助我节约 13~30% 的输出时间。

# pwd
/Users/soulteary/Library/Application Support/TabNine/models# ls
29b87067.tabninemodel b8373e4b.tabninemodel ce94127b.tabninemodel
# du -hs *
241M	29b87067.tabninemodel
685M	b8373e4b.tabninemodel
256M	ce94127b.tabninemodel# du -hs .
1.2G	.

不过, 的上限取决于你让它见过的代码有多少,以及有多好,培养好的模型,和喂电子宠物差不多,需要时间。

怎么用代码格式化硬盘__格式化代码的快捷键

在线代码补全模型的使用

如果你想开箱即用,并且代码没有那么敏感,那么在线代码补全,会更适合你。

这里唯一推荐的是:/,如果你的网络通畅,一般情况下你的代码补全都能够在 1s~2s 内完成。

默认情况下,你可能需要花一些小钱,来订阅这个功能。很幸运,我的账号有资格直接使用它。

网上应该有很多对于 的介绍了,我这里介绍两个实际使用时的小技巧。

在实际的程序编写中,我们会打开很多不同的文件,但是如果我们要生成的代码只和某个或者某几个文件相关,可以考虑关闭其他的文件。

如果我们想针对某段具体的内容进行代码生成,在生成之前,可以顺手复制粘贴一下我们想作为上下文进行代码生成的内容。在生成代码的时候,能省一些事情。

实战:收尾工作

编码工作完成之后,我们还需要做一些内容的收尾。

比如,编写中英双语的项目文档,以及设计项目的 Logo。

使用 GPT 完成开源项目的文档

这里和前文中使用 一样,我们可以多次提交内容,让 帮助我们写出项目的框架。

然后我们根据实际情况,把文档中的内容进行替换即可。

至于英文文档,只需要和上文中将 “Auto GPT 内容翻译中文”一样,反过来,让 将内容翻译成英文即可。

是不是简单省事。

使用 完成项目图标

编写项目最难的部分之一,就是为项目设计一个 Logo。不过现在有了 SD、 ,这件事变的太简单了。

我们只需要对它下命令:“帮助我设计一个 Logo,Logo 的内容是…”

当然,在实际的使用中,如果我们将 改写为英文,对于模型而言,生成的效果会更好一些。

如果你经常使用 等图文模型,可以试试使用之前在 热榜上待了很久的,我另外一个开源项目:《八十行代码实现开源的 、 “咒语”作图工具》。

其他

好了,文章的基本内容,到这里就聊完了。

我们来聊聊开源社区里的趣事。

开源社区里的趣事

其实去年的时候,在 Nginx 社区里,有一个老外曾留下一个 issue,包含了几个去掉配置中多余空格的修改。

我当时看到了这个提交,觉得因为没有提供一致性的标准或可复现的工具,这个属于水 PR。于是,留了一条评论 “这个变更似乎没有必要,或许提供一个通用的格式化工具,对于开发者而言更有价值。”

但是,不论是这个变更提交者,还是项目相关维护者都没有继续进行回复。于是,这个 issue 就挂了一年之久。正巧借着这个机会,就用 来解决这个事情吧。

目前,我已经用这个小工具完成了 Nginx 官方配置仓库中的“内容翻修”,以及点亮了 Nginx 开源社区的贡献者图标记录。

最后

终于将这篇待在草稿箱里一个月的文章整理了出来,希望接下来,随着业务的正常发展,我能够有更多的时间来分享如何“为了不折腾而折腾”的事情。

–EOF

我们有一个小小的折腾群,里面聚集了一些喜欢折腾的小伙伴。

在不发广告的情况下,我们在里面会一起聊聊软硬件、、编程上的一些问题,也会在群里不定期的分享一些技术资料。

喜欢折腾的小伙伴,欢迎阅读下面的内容,扫码添加好友。

关于“交友”的一些建议和看法

添加好友时,请备注实名和公司或学校、注明来源和目的,否则不会通过审核。

关于折腾群入群的那些事

本文使用「署名 4.0 国际 (CC BY 4.0)」许可协议,欢迎转载、或重新修改使用,但需要注明来源。 署名 4.0 国际 (CC BY 4.0)

关于我们

最火推荐

小编推荐

联系我们


版权声明:本站内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 88@qq.com 举报,一经查实,本站将立刻删除。备案号:桂ICP备2021009421号
Powered By Z-BlogPHP.
复制成功
微信号:
我知道了