如何终止Lua脚本的执行

在执行Lua脚本的过程中,判断了一个前置条件,如果这个条件不满足,那么后续的代码就都不执行了,比如一个场景的场景就是判断Neovim的版本,如果不是0.7.0,就不执行后面的配置,提示先更新Neovim的版本。关键的语法就是return end

1
2
3
if not is_directory_exists(install_path) then
do return end
end

References

如何在Lua中检测文件或者目录是否存在

检查目录是否存在

1
2
3
local is_directory_exists = function(dir)
return vim.fn.empty(vim.fn.glob(dir)) == 0
end

比如我们可以用来检测packer是否已经安装,如果没有安装,就用git clone下载安装

1
2
3
4
5
local install_path = fn.stdpath('data') .. '/site/pack/packer/start/packer.nvim'

if not is_directory_exists(install_path) then
-- do something
end

检查文件是否存在

1
2
3
4
5
6
7
8
9
local file_exists = function(name)
local file = io.open(name, "r")
if file ~= nil then
io.close(file)
return true
else
return false
end
end

比如可以用来判断packer是否已经编译,如果没有编译就执行同步进行编译:

1
2
3
4
5
local packer_compiled_path = fn.stdpath('config') .. '/plugin/packer_compiled.lua'

if not file_exists(packer_compiled_path) then
require('packer').sync()
end

References

在Lua中将两个字符串合并为一个字符串

官网的例子,已经非常直接了:

1
2
print("Hello " .. "World")  --> Hello World
print(0 .. 1) --> 01

再来一个实际例子,获取packer的安装地址,先确定neovim的数据目录是哪里:

1
2
:lua print(vim.fn.stdpath('data'))
$HOME/.local/share/nvim

packer的安装地址

1
local install_path = vim.fn.stdpath('data') .. '/site/pack/packer/start/packer.nvim'

在Google表格中查询一周以前对应日期的数据

在Google表格中有两列数据,第一列(B)是日期,第三列(D)是体重值,现在的诉求就是在E列计算当天的体重和一周前体重的差值。

获取一周以前日期对应的数值,就要利用到vlookup函数,比如调用方法:

1
=vlookup(B2-7, B:D,3, false)

vlookup有四个参数,第一个是要计算的值,B2在这里对应的是今天的日期,日期可以直接通过加减,得出一周以前的日期,B:D对应要查询的区域,要查询区域的第一列,对应要查询的值,3代表要匹配的结果,false在这里代表不要排序。

那最后差值的计算就简单了

1
=D2-vlookup(B2-7, B:D,3, false)

References

如何在Google表格中计算平均值的时候忽略N/A

如果要在Google Spreadsheets中计算平均值,可以使用average函数,这个函数会忽略所有的空值,但是如果要计算平均值的部分,有通过公式生成的结果,并且公式没有得出结果,是N/A的话,最后average的计算结果也会是N/A

要解决这个问题,我们需要在计算平均值的时候,将所有的N/A忽略掉,不能直接使用average函数,而要使用averageif函数:

1
=averageif(E:E, "<>#N/A")

References

用腾讯云的web函数操作cynosdb数据库

准备

  • 首先要有一个cynosdb数据库,在控制台直接可以购买,我选择的是serverless版本。
  • 要有一个VPC和一个子网,这样才能用云函数访问这个数据库。
  • 要创建一个vpc网关,但不用关联任何api,这样就有了apigw的参数

环境变量

1
2
3
4
5
$ node -v
v16.15.0

$ npm -v
8.8.0

初始化

1
mkdir myfunc && cd $_

serverless.yml

第一个级别是几个meta级别的属性

1
2
3
4
component: scf
name: componentInstanceName
app: appName
inputs:

inputs参数

肯定要把.env排除,node_modules不排除,而是改成npm install --production搞定。

1
2
3
4
src:
src: ./
exclude:
- .env

type只有两个类型:web和event,我们是用来做api,这里就是web

1
type: web

当类型是web的时候,可以设置entryFile参数,这样就不需要在代码里添加到scf_bootstrap文件了,会根据entryFile属性动态增加。

1
entryFile: app.js

Web函数只在广州、上海和北京的特定区才有,所以要指定区域

1
region: ap-guangzhou

运行环境只有几个特定的环境

1
runtime: Nodejs16.13

在超时这个事情上,我设置了三个级别,连接数据库最多1秒,初始化3秒,运行20秒。实际上这些也太高了。

1
2
timeout: 20
initTimeout: 3

因为将.env排除了,所以在app.js中是无法读取到.env中的变量的,在这里要转换一下。

1
2
3
4
5
6
environment:
variables:
DATABASE_HOST: ${env:DATABASE_HOST}
DATABASE_USER: ${env:DATABASE_USER}
DATABASE_PASSWORD: ${env:DATABASE_PASSWORD}
DATABASE_DATABASE: ${env:DATABASE_DATABASE}

对于api网关,最主要的是要指定serviceId,否则每次deploy都会创建新的,但这里也遗留一个问题,就算这样写,每一次都会有一个解绑和重新绑定的过程,觉得是可以省略的。另外method只要一个ANY,就可以满足所有情况了,如果在这里指定GET,反而需要每个路由单独设置。

1
2
3
4
5
6
7
8
9
10
events:
- apigw:
parameters:
serviceId: service-XXXXXXXX
protocols:
- https
environment: release
endpoints:
- path: /
method: ANY

一定要设置vpc,这样才能从云函数中访问同一个vpc的数据库。vpcId可以在私有网络控制台中看到,subnetId可以在子网控制台中看到。

1
2
3
vpcConfig:
vpcId: vpc-XXXXXXXX
subnetId: subnet-XXXXXXXX

下面是一个完整版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
component: scf
name: thinking
app: notes

inputs:
src:
src: ./src
exclude:
- .env
type: web
entryFile: app.js
region: ap-guangzhou
runtime: Nodejs16.13
timeout: 20
initTimeout: 3
environment:
variables:
DATABASE_HOST: ${env:DATABASE_HOST}
DATABASE_USER: ${env:DATABASE_USER}
DATABASE_PASSWORD: ${env:DATABASE_PASSWORD}
DATABASE_DATABASE: ${env:DATABASE_DATABASE}
events:
- apigw:
parameters:
serviceId: ${env:APIGW_SERVICE_ID}
protocols:
- https
endpoints:
- path: /
method: ANY
vpcConfig:
vpcId: ${env:VPC_ID}
subnetId: ${env:SUBNET_ID}

准备.env文件

1
2
3
4
5
6
7
8
DATABASE_HOST=
DATABASE_USER=
DATABASE_PASSWORD=
DATABASE_DATABASE=

VPC_ID=
SUBNET_ID=
APIGW_SERVICE_ID=

然后创建src目录

1
2
mkdir src && cd $_
npm init -y

安装express和mysql

1
npm install express mysql

app.js

对于express来说,都是基础用法,这里最重要的点,是必须运行在9000端口号上,其他的都不行。

1
2
3
4
5
6
7
8
9
10
11
12
13
const express = require('express')
const app = express()
const port = 9000

app.get('/', (req, res) => {
})

app.post('/notes', function(req, res) {
})

app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})

如果要返回json数据,只要基于res对象操作就可以

1
2
3
4
5
res.send([
{
foo: "bar"
}
])

数据库操作

引入

1
const mysql = require('mysql');

创建数据库连接,这里用到了env中定义的变量,总体的思路就是先连接,连接成功操作,然后关闭。

1
2
3
4
5
6
7
8
9
10
11
12
const connection = mysql.createConnection({
connectTimeout: 1000,
host : process.env.DATABASE_HOST,
user : process.env.DATABASE_USER,
password : process.env.DATABASE_PASSWORD,
database : process.env.DATABASE_DATABASE
});

connection.connect(function() {
connection.query();
connection.end();
});

查询一个表,喜欢iu需要用query执行SELECT,results是查询结果,fields对应字段列表

1
2
connection.query('SELECT * from notes', function (error, results, fields) {
});

数据库连接如果失败,对应的error对象有以下关键信息:

  • error.stack 错误堆栈
  • error.code 错误代码
  • error.errno 一个数值类的错误代码
  • error.fatal 是否是一个致命错误
  • error.sql 出错的时候,执行的SQL命令
  • error.sqlMessage 错误提示

部署

最后一步就是将云函数部署到服务器

1
sls deploy

References

setting-default-branch-name-for-git-init

当用git init初始化一个项目的时候,现在会有以下提示:

1
2
3
4
5
6
7
8
9
10
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch name
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m name

这其实涉及到社区里对于master和slave的嫌弃,这个提示中已经说的很详细了,默认创建的项目分支名称还是master,但是我们可以用下面的方式改名:

1
git branch -m main

当然更直接的,就是加一个全局设置,以后git初始化就都是新的分支名称了,这个设置功能是从2.28版本加进来的。

1
git config --global init.defaultBranch main

通过--list参数,或者只查询这一个属性,都可以确认是不是已经设置成功

1
2
git config --list
git config init.defaultBranch

References

基于curl判断当前网络是否处于封锁状态

curl是一个超级厉害的网络工具,我们可以基于curl抓取远程的文件,同时我们也可以基于curl判断当前网络的连接情况,判断是否被封锁。

具体是下面这个命令:

1
curl --location --head --connect-timeout 3 --verbose https://google.com

--location可以缩写为-L,因为网站有跳转,可以跳转到最终的页面。
--head可以缩写为大写的-I,只显示请求头,我们只是用来判断,显示头部信息就足够了。
--connect-timeout设置了一个超时时间,如果网络被屏蔽,这个参数就发挥作用了,直接中断请求。
--verbose可以显示更多的信息。

最后注意这里要使用https://google.com,而不是google.com,如果是后者,实际测试超时时间会无效,一直处于连接状态。

References

如何在git中同时推送commit和tag?

一直有一个困惑,就是执行git push命令的时候,只能将所有的commits推送到服务端,如果要想把tags也推送上去,需要再执行一个git push --tags命令。这样很麻烦。

发现git有一个参数--follow-tags可以解决这个困惑,带上这个参数,可以把这个commit对应的tag一起推送上去。

1
git push --follow-tags

如果每一次都这样操作,其实也很麻烦,毕竟这个参数很长,我们可以在全局打开这个配置开关:

1
git config --global push.followTags true

References