初学rust,踩坑私有依赖
Tag rust, 依赖, git, on by view 164

最近尝试在一个项目中引用一个私有crate,这个crate是一个lib,然后存储在私有git仓库中,并且这个git平台不支持rust的crate-index.

  • 第一坑,引用git依赖

于是我在我的项目中这样引用外部依赖包

[package]
name = "las"
version = "0.1.1"
authors = ["...."]
edition = "2018"

[dependencies]
elasticsearch = { version = "8.5.0-alpha.1", default-features = false, features = [
    "rustls-tls",
] }
logwatcher = "0.1.1"
json = "*"
reqwest = { version = "0.11.12", default-features = false, features = [
    "blocking",
    "rustls-tls",
] }
toml = "0.8.6"
serde_derive = "1.0.177"
serde = "1.0.177"
serde_json = "1.0.104"
once_cell = "1.18.0"
futures = "0.3"
tokio = { version = "*", features = ["full"] }
uuid = { version = "1.4", features = ["v4", "fast-rng", "macro-diagnostics"] }
chrono = "0.4"
core_affinity = "0.8.0"
geoip = { git = "ssh://git@git.xxxx.com/xxxx/tgeoip.git", branch = "master", package = "geoip" }

nix = "0.26"
libc = "0.2.146"
clap = { version = "4.4.2", features = ["derive"] }
log4rs = { version = "1.2.0" }
log = { version = "0.4.20" }
[build-dependencies]
regex = "1.6.0"

需要注意的是,我git@git.xxxx.com:xxxx/tgeoip.git仓库中是一个workspace,里面有2个子项,一个是可执行bin项目,叫做regen,一个是外部可依赖包,叫做geoip(后续实践表明同一个workspace里面的子项引用就应该这么干,git路径是同一个,使用package指定子项的包名),我这样引入之后,发现死活拉取不了私有git依赖。报错没权限拉取,git鉴权失败

error: failed to get `geoip` as a dependency of package `las v0.1.1 (/data/code/rust/las)`

Caused by:
  failed to load source for dependency `geoip`

Caused by:
  Unable to update ssh://git@git.xxxx.com/xxxx/tgeoip.git?branch=master#e41c5279

Caused by:
  failed to clone into: /root/.cargo/git/db/tgeoip-9094aceea5940357

Caused by:
  failed to authenticate when downloading repository

  * attempted ssh-agent authentication, but no usernames succeeded: `git`

  if the git CLI succeeds then `net.git-fetch-with-cli` may help here
  https://doc.rust-lang.org/cargo/reference/config.html#netgit-fetch-with-cli

Caused by:
  no authentication methods succeeded

各方查询后,都是建议添加这个选项,我开始还没搞清楚加在哪儿,但是发现使用环境变量好使。各方尝试后:

添加到~/.cargo/config文件中,如下

[net]
git-fetch-with-cli = true

然后再次执行cargo build无需环境变量即可。(前提是你本地已经配置好了访问ssh://git@git.xxxx.com/xxxx/tgeoip.git的ssh key)

  • 第二坑,外部依赖包要申明为rlib

我在这个bin项目中引用geoip,发现一直报错

failed to resolve: use of undeclared crate or module `geoip`

百思不得其解,最后发现是我依赖包申明类型的问题,我Cargo.toml申明的是

[package]
....

[lib]
name = "geoip"
crate-type = ["staticlib", "cdylib"]

[dependencies]
bincode = "1.3.3"
serde = { version = "1.0.193", features = ["derive"] }

实际lib应该申明rlib类型,才能被正常引用,改为如下,更新依赖,就没报错了

[package]
....

[lib]
name = "geoip"
crate-type = ["staticlib", "cdylib", "rlib"]

[dependencies]
bincode = "1.3.3"
serde = { version = "1.0.193", features = ["derive"] }

Git团队开发中PR工作模式的反思
Tag git, pr, 工作流, on by view 3279

在公司团队协作用了大半年的Git了,PR工作模式也用了半年。由一个用Git装逼的假老手成长为真正用Git进行团队协作开发的老油条。这其中也有一些值得反思的东西。我很崇拜PR的工作模式,因为它基本上是优秀的开源软件工作模式的代表,众多的开发者自发的给开源项目发送PR,以前总是盼望着自己的开源项目会有人发送PR,若是接收到PR就像是收到别人的礼物一般高兴。

我之前赞同的PR工作模式是这样的,开发者拿到开发需求之后,在自己的分支开发,然后向主仓库的相关分支发送PR,之后由测试人员在测试机上拉取主仓库相关分支的代码,然后fetch PR所在仓库分支的代码合并(merge)到本地主仓库相关分支,进行测试,测试完毕通过之后才合并PR到分支。我这一想法的灵感来源于 travis-ci 单元测试的工作模式:开发人员发送PR,travis-ci自动进行单元测试,PR管理者参考PR在 travis-ci 上单元测试的结果进行初步判定是否可以合并。但是我忽略了一点,测试人员并非是 travis-ci 上的单元测试。在工作的过程中往往是这样的:

开发人员初步开发出某个功能,然后经过自己的初步测试,发送PR到主仓库,测试人员看到有PR了,需要测试了,于是开始测试,但是测试有问题,于是开发人员就必须继续修改提交,然后再次测试,还有一些问题被发现依然存在,继续开发……可是,你突然发现,你的PR被合并了或者是被关闭了,因为要下班了;或者是要下班了,PR管理员会问这个PR能否合并,测试人员暂时没发现新的问题,于是测试人员告诉PR管理员“没有问题”,于是PR被合并了。或者没有上面的“PR管理员的询问”,但不管怎样,最后的结果往往是PR被草草的合并了。于是,没有充分测试的PR进入了仓库,甚至进入了发布分支,最终的结果可想而知。

在这个过程中,人们往往没有意识到其实是被PR给影响到了。因为开发者一个PR创立之后,在他会有一个潜意识希望PR被合并,测试人员同样也有这么一个潜意识,因为测试PR就是他的工作之一,他也希望PR被合并,对于PR管理员来说同样也有这么一个潜意识,希望PR被处理,不管是合并还是关闭。就是这些潜意识推动这个PR尽早被合并。

我个人感觉正确的做法应该是当测试人员测试充分之后再发起PR,避免这些潜意识促使PR过早的被合并。事实上,不管PR是否存在,测试人员都能够从开发者的分支上拉取到开发者的代码合并到主仓库,PR不过是一个形式而已,给合并者带来方便。但是那些错误的理解了PR的人们往往会搞出诸多莫名其妙的东西,比如PR用来人工做代码审核,比如搞个CheckList让人工去查代码中哪儿写得不规范,这些应该是让 Sonar 自动扫描PR中存在的不规范,谁又会有时间去为别人的PR人工做Sonar该做的事情。经过测试人员的充分测试之后,开发者创建PR,这时单元测试测试一遍,然后Sonar扫描一遍,后两者自动化测试通过之后代码才能入库。

总之,测试人员功能测试通过之后开发者才能创建PR,自动化工具进行单元测试和Sonar扫描通过后,PR管理员才能允许合并。这才是比较靠谱的PR工作流。


用github登录,oauth开发
Tag github, oauth, on by view 8838

最近做的oj项目的网站子项目中要使用到“用github登录”这一功能,也就是oauth,于是研究了一番。

github的oauth验证的过程如下:

用户访问登录验证接入口

https://github.com/login/oauth/authorize?client_id=xxxxxxxxxxxxxxxxxx&scope=user,public_repo     

其中client_id由开发者在github网站上申请,无限制。
registor_github_oauth.png
申请成功后,获取client_id和client_secret
get_github_oauth_id_secret.png

用户访问上面的url之后,github会让其跳转到你预定的url,并且带上code参数,例如

http://oj.duguying.net/oauth/github?code=xxxxxxxxxxxxxxxxxx 
   

然后,开发者可以通过code,client_id以及client_secret这三个参数获取用户的access_token即用户身份标识,请求如下

https://github.com/login/oauth/access_token?client_id=xxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxx&code=xxxxxxxxxxxxxxxxxxx 

这个请求将会返回如下内容 

access_token=xxxxxxxxxxxxxxxxxxxxxxxxx&scope=public_repo%2Cuser&token_type=bearer 

有了access_token之后,只需要通过如下请求就可以获取用户信息

https://api.github.com/user?access_token=xxxxxxxxxxxxxxxxxxxxxxxxx 

返回的信息将会是json格式。注意整个请求过程中都是使用GET请求。只要理解了oauth验证过程,如此就很容易编程实现了。

最后,附上我自己用golang实现的github的oauth验证库https://github.com/gogather/oauth