MoreRSS

site iconDerobukal修改

博客名:御坂研究所,一个偏软件开发和技术实践的博客。
请复制 RSS 到你的阅读器,或快速订阅到 :

Inoreader Feedly Follow Feedbin Local Reader

Derobukal的 RSS 预览

Kotlin与Java对照手册

2025-04-24 22:21:27

Generated By AI

📗 1. 基本类型

类型 Kotlin 写法 Java 写法 简要说明
数字 Int, Long, Float, Double, Short, Byte int, long, float, double, short, byte Kotlin 数值类型映射到相应的原生/包装类型。
布尔 Boolean boolean 只能取 true/false,与数字不互通。
字符 Char char 单个 Unicode 字符,支持转义序列。
字符串 String String 不可变;支持多行文本块 """..."""
数组 Array<T>, IntArray T[] 提供原始类型专用数组如 IntArrayByteArray
无符号整型 UInt, ULong, UShort, UByte 编译时检查范围,运行时越界抛 IllegalArgumentException

📘 2. 语法对照

功能 Java 写法 Kotlin 写法 简要说明
变量定义 int x = 10; final String name = "Tom"; var x = 10 val name = "Tom" var 可变,val 只读;类型由编译器推断。
类 + 构造 public class P { P(String n) { ... } } class P(val name: String) 主构造中声明属性,自动生成字段 & 访问器。
数据类 手动写字段/构造/equals/toString data class User(val id: Int, val n: String) data 自动生成常用方法 & 解构组件。
函数定义 public int sum(int a, int b) { return a + b; } fun sum(a: Int, b: Int) = a + b 表达式函数可省略大括号和 return
空安全 if (s != null) len = s.length(); else len = 0; val len = s?.length ?: 0 String? 可空,?.?: 插入编译期空检查。
分支匹配 switch(x) { case 1: ... } when(x) { 1 -> ...; else -> ... } when 是表达式,支持范围 & 任意对象比较。
循环 & 集合 for(int i=0;i<10;i++)``list.stream().filter() for(i in 0 until 10)``list.filter{} 0 until 生成 IntRange;集合链式调用基于扩展函数。
单例 class S { private static S i=new S(); … } object S { fun foo() {} } object 编译时生成线程安全单例,无需额外样板。

✨ 3. 独有亮点

特性 示例 简要说明
默认 & 命名参数 fun g(msg: String = "Hi", name: String = "You") g(name="Tom") 编译器生成默认方法,命名参数避免重载歧义。
扩展函数 fun String.ex() = uppercase() 编译后为静态方法,第一个参数是接收者,调用如成员方法。
解构声明 val (x, y) = Point(1, 2) data class 自动生成 componentN(),一行取多值。
密封类 sealed class R; data class Ok(val d: String): R(); object Err: R() 限定子类范围,when 可做穷尽检查。
内联函数 inline fun <T> m(b: ()->T): T { … } 在调用处展开函数体,减少高阶函数的运行时开销。
集合构造器 listOf(1, 2), mutableListOf("A"), mapOf("a" to 1) 内建集合工厂函数,语法简洁;to 表示键值对。
数组构造器 arrayOf(1, 2), intArrayOf(1, 2) 支持泛型与原始类型数组,避免装箱。
表达式返回值 val max = if (a > b) a else b val result = try { … } catch { … } ifwhentry 都是表达式,可直接赋值。
区间语法 & 步进 for (i in 1..5), for (j in 1 until 5 step 2) .. 表闭区间,until 表半开,step 控制步长。
字符串模板 "Hello, $name" "Length: ${s.length}" $变量 可直接拼接,复杂表达式用 ${}
Lambda 尾随语法 list.filter { it > 0 }.map { it * 2 } 大括号可直接跟随函数调用,链式语法自然、简洁。

📚 4. 常用标准库函数

函数 用法示例 简要说明
let user?.let { print(it.name) } 非空时执行块,it 引用原对象。
apply User().apply { age = 18 } 在对象上执行块并返回该对象,常用于初始化。
also list.also { println("init") } 执行副作用并返回对象,常用于日志 / 调试。
run val r = run { compute(); result } 无接收者的作用域块,返回最后一行结果。
with with(cfg) { load(); validate() } 对象上下文块,this 指向接收者,返回结果。
takeIf str.takeIf { it.isNotBlank() } 条件为真返回对象,否则返回 null
sequence sequenceOf(1,2,3).map { … } 惰性集合处理,适合大规模数据管道。

🧩 5. 类型系统对比

功能 Java 写法 Kotlin 写法 简要说明
泛型 List<String> List<String> 支持协变 / 逆变(out / in)和 reified 泛型函数。
类型别名 typealias Name = String 简化复杂类型声明。
枚举类 enum Color { RED, GREEN } enum class Color { RED, GREEN } 支持在枚举中定义属性 & 方法。
内联类 @JvmInline value class USD(val amount: Int) 编译时包装或展开,零开销封装。

🔍 6. 类型检测与转换

功能 Java 写法 Kotlin 写法 简要说明
类型检查 if (obj instanceof String) if (obj is String) is 后自动智能转换,无需显式强转。
安全转换 (String) obj obj as String / obj as? String as? 安全转换失败返回 null
基本转换 Integer.parseInt(str) str.toInt(), toDouble(), toLong() 通过扩展函数提供常见类型转换。

🔄 7. 控制流程 & 异常

功能 Java 写法 Kotlin 写法 简要说明
条件 & 循环 if, switch, for, while, do-while if, when, for, while, do-while when 可做表达式,替代 switch
返回 & 跳转 return, break, continue, throw 同 Java 支持在 lambda 中局部返回,如 return@label
异常处理 try-catch-finally, checked exception try-catch-finally,无 checked exception Kotlin 不区分受检异常,简化错误处理。

📦 8. 包与导入

功能 Java 写法 Kotlin 写法 简要说明
包声明 package com.example; package com.example 不需要分号。
导入 import java.util.List; import java.util.List 支持导入顶层函数和属性。
别名导入 import foo.Bar as Baz 解决命名冲突或简化引用。

⚙️ 9. 面向对象相关

功能 Java 写法 Kotlin 写法 简要说明
接口默认实现 default void f() {} 接口中可直接写方法体 接口内方法可有实现,无需关键字。
抽象类 abstract class Shape { … } abstract class Shape { … } 抽象成员不需再加 abstract 前缀。
继承 & 覆写 class A extends B { @Override … } class A : B() { override fun … } : 表示继承,override 必显式标注。
可见性修饰符 public/protected/private public/protected/private/internal internal 表示同模块内可见。
内部类 class Outer { class Inner {} } class Outer { inner class Inner {} } 默认是静态嵌套,加 inner 变为非静态内部类。

🧵 10. 协程 vs 多线程

场景 Java 写法(线程/异步) Kotlin 写法(协程) 简要说明
启动任务 new Thread(() -> work()).start(); GlobalScope.launch { work() } 协程更轻量、省资源,适合大规模并发。
异步返回值 Future<Integer> f = exec.submit(...); val result = async { compute() }.await() 内建 async/await,语义更清晰。
延迟执行 Thread.sleep(1000) delay(1000) 非阻塞挂起,不占用线程。
结构化并发 手动管理线程池和生命周期 coroutineScope { … } 协程作用域自动管理生命周期,避免泄漏。

📦 11. 集合操作对比

功能 Java 写法(Stream) Kotlin 写法(扩展函数) 简要说明
过滤 list.stream().filter(x -> x > 0).collect(...) list.filter { it > 0 } 语法简洁,链式调用更直观。
映射 list.stream().map(x -> x * 2).collect(...) list.map { it * 2 } Lambda 简洁,扩展函数无额外依赖。
分组 Collectors.groupingBy(...) list.groupBy { it.key } 直接返回 Map<K, List<V>>,更易读。
排序 list.sort(Comparator.comparing(...)) list.sortedBy { it.prop } 函数式排序,链式可读性好。
聚合 reduce, sum, collect reduce, sumOf, fold 内建多种聚合函数,常用时无需额外导入。

持续更新中…

参考:

https://book.kotlincn.net/text/d-basics.html

ComfyUI的操作与使用

2025-03-31 19:21:10

简单起见,又或者是没有N卡或者显卡的配置比较低,可以使用腾讯云HAI直接搭建ComfyUI服务。

入门使用

可以先clear掉当前的workflow,之后右键新建模块。

首先需要新建一个采样器(KSampler),采样器的配置如下:

参数 说明
seed 0 随机种子,控制生成结果的随机性。相同种子会产生相同结果
control_after_generate randomize 生成后种子控制方式:randomize(随机化)、increment(递增)、decrement(递减)、fixed(固定)
steps 20 采样步数,通常15-30步较为合适。步数越多质量越好但耗时更长
cfg 8.000 CFG引导强度,控制AI对提示词的遵循程度。范围1-20,推荐7-12
sampler_name euler 采样算法:euler、euler_a、dpm_2、dpm_2_ancestral、lms、ddim等
scheduler normal 调度器类型:normal、karras、exponential、sgm_uniform等
denoise 1.000 去噪强度,1.0为完全去噪,0.0为不去噪。图生图时可调节此值

采样器的model可以选择Load Checkpoint。
positive是正向提示词,negative是反向提示词,都可以选择CLIPTextEncode。为了方便区分,可以给prompt修改一个有意义的标题。
latent_image可以设置图片的选项,例如EmptyLatentImage。
LATENT可以选择VAE Decode模块,然后可以添加一个图片预览模块。

多图合并,使用同一个背景

输出大小设置为图片背景总大小。
图片正向prompt输出拖拽,然后添加Conditioning(Set Area)节点,在其中设置图片的大小和图片在背景画布中的位置。
使用ConditioningCombine节点,合并多个Conditioning节点,之后把合并节点的输出连接到KSample。
但是,如果是单纯两个prompt直接连到采样器,两张图片会很割裂。解决办法是再新建一个prompt,之后把两张图片的输出和这个prompt使用一个combine进行合并,之后合并结果再输出到采样器。

模型

CheckPoints(检查点模型)是Stable Diffusion的核心基础模型,包含了完整的图像生成能力。它是一个预训练的神经网络模型,决定了生成图像的整体风格、质量和特征。

常用CheckPoints模型类型:

模型类型 特点 适用场景 推荐模型
SD 1.5系列 经典基础模型,兼容性好 入门学习,插件丰富 v1-5-pruned-emaonly.ckpt
SDXL系列 更高分辨率,质量更好 高质量出图 sd_xl_base_1.0.safetensors
写实人像 专注真实人物生成 人像摄影、写实风格 realisticVisionV60B1_v51VAE.safetensors
动漫二次元 卡通动漫风格 动漫插画、角色设计 anything-v5-PrtRE.safetensors
艺术绘画 艺术风格强烈 创意艺术、概念设计 dreamshaper_8.safetensors
建筑风景 专注场景和建筑 建筑设计、风景画 architectureExterior_v40.safetensors

模型文件格式:.ckpt:早期格式,文件较大;.safetensors:更安全的格式,加载速度快,推荐使用;.pt:PyTorch原生格式

使用LoRA模型:在主模型的MODEL节点拖拽,可以新增LoRA节点,之后把LoRA的模型替代主模型连接到采样器上面。同样的,主模型的CLIP需要连接到LoRA上面,之后把正向prompt连接到LoRA就可以了(反向prompt还是连接在CheckPoint的CLIP上面)。

参考

一口气学ComfyUI系列教程

ComfyUI简介

2025-03-31 06:47:59

ComfyUI 是一个基于节点工作流的现代化 Stable Diffusion 图形用户界面。与传统的WebUI不同,ComfyUI采用节点连接的方式来构建图像生成工作流,让用户能够更精确地控制整个生成过程。

Stable Diffusion 是一款开源的 AI 图像生成技术,基于扩散模型构建。用户可以通过 Stable Diffusion WebUIComfyUI 等开源工具来运行它,只需下载相应的模型文件(通常为 .ckpt.safetensors 格式)即可开始使用。

核心概念

ComfyUI中的图像生成涉及三个关键组件,在CheckpointLoader中进行设置:

  • CLIP:将文本提示转化为主模型可以理解的向量形式
  • 主模型(Main MODEL):执行实际的图像生成计算
  • VAE(变分自编码器):将主模型的潜在空间格式转化为最终可视的图片

安装和配置

1. 下载和安装

GitHub 下载对应版本,解压后运行:

  • run_nvidia_gpu.bat(推荐NVIDIA GPU用户)
  • ./python_embeded/python -s ComfyUI/main.py --windows-standalone-build

2. 安装管理器和插件

下载 ComfyUI-Manager 放到 ComfyUI/custom_nodes 文件夹,然后在Manager的Custom Node Manager中安装所需插件(需要科学上网)。

3. 下载模型

将模型文件放置到 ComfyUI/models 文件夹中:

  • Checkpoint模型checkpoints 文件夹
  • LoRA模型loras 文件夹
  • VAE模型vae 文件夹

推荐入门模型:SD 1.5

模型资源网站:

4. 网络配置

如果遇到网络连接问题,可以使用SwitchHosts添加以下配置:

1
2
3
4
185.199.108.133 raw.githubusercontent.com
185.199.108.133 user-images.githubusercontent.com
185.199.108.133 avatars2.githubusercontent.com
185.199.108.133 avatars1.githubusercontent.com

扩展功能

ComfyUI_StoryDiffusion

通过Custom Node Manager安装,然后执行以下命令安装依赖:

1
2
./python_embeded/python.exe -m pip install -r ../ComfyUI_windows_portable/ComfyUI/custom_nodes/ComfyUI_StoryDiffusion/requirements.txt
./python_embeded/python.exe -m pip install opencv-python

API操作

HTTP API方式

  1. 启用开发者选项
  2. 将设置好的Workflow导出为API格式
  3. 创建任务:
    1
    2
    3
    curl -X POST 'http://127.0.0.1:8188/prompt' \
    -H 'Content-Type: application/json' \
    -d '{"prompt": API文件的内容}'
  4. 查询结果:curl -X GET 'http://127.0.0.1:8188/history/{prompt_id}'
  5. 获取图片:http://127.0.0.1:8188/view?filename=ComfyUI_00003_.png&subfolder&type=output

WebSocket方式

更简单的实时通信方式:

1
2
3
4
5
// 建立连接
ws://127.0.0.1:8188/ws?clientId=23333

// 提交任务
{"client_id": "23333", "prompt": "API文件的内容"}

提示:如果不想折腾本地环境,可以考虑使用腾讯云等平台提供的按时计费ComfyUI服务。

参考资料

官方资源

学习教程

利用whisper为视频自动生成字幕

2025-01-02 18:37:24

whisper是一个由openai开发的通用语言识别模型,我们可以使用它来为视频自动创建字幕。

环境安装

为了加速,我们需要使用GPU来进行计算,因此需要安装基于CUDA的pytorch。首先我们需要安装Miniconda,这里安装的时候直接点击下一步即可。

安装完毕之后,我们需要创建一个新的环境,这里我们创建一个名为whisper的环境:

conda create -n whisper python=3.8conda activate whisper

1. 安装CUDA

安装好了Miniconda之后,我们需要安装CUDA,执行nvidia-smi

$ nvidia-smiThu Jan  2 11:49:53 2025+-----------------------------------------------------------------------------------------+| NVIDIA-SMI 560.94                 Driver Version: 560.94         CUDA Version: 12.6     ||-----------------------------------------+------------------------+----------------------+| GPU  Name                  Driver-Model | Bus-Id          Disp.A | Volatile Uncorr. ECC || Fan  Temp   Perf          Pwr:Usage/Cap |           Memory-Usage | GPU-Util  Compute M. ||                                         |                        |               MIG M. ||=========================================+========================+======================||   0  NVIDIA GeForce GTX 1060 6GB  WDDM  |   00000000:01:00.0  On |                  N/A ||  0%   39C    P8             10W /  120W |     505MiB /   6144MiB |      0%      Default ||                                         |                        |                  N/A |+-----------------------------------------+------------------------+----------------------+

通过这个命令可以看到Driver Version: 560.94CUDA Version: 12.6,因此我们需要安装12.6版本的CUDA,更加详细的版本对照表在这里。在安装的时候可以选择自定义安装选项,一般来说只要勾选CUDA下的 Development和Runtime即可。

安装完毕之后执行命令nvcc -V查看CUDA版本:

$ nvcc -Vnvcc: NVIDIA (R) Cuda compiler driverCopyright (c) 2005-2024 NVIDIA CorporationBuilt on Thu_Sep_12_02:55:00_Pacific_Daylight_Time_2024Cuda compilation tools, release 12.6, V12.6.77Build cuda_12.6.r12.6/compiler.34841621_0

2. 安装cuDNN

根据自己下载的CUDA来选择对应版本的cuDNN,下载地址在这里。下载完毕之后解压到CUDA的安装目录下,一般来说是C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA{版本号},如果有重名的文件直接替换即可。

之后进入extras\demo_suite目录,执行如下命令:

bandwidthTest.exedeviceQuery.exe

如果出现了PASS的字样,说明安装成功。

3. 安装pytorch

切换到我们之前创建的whisper环境,使用如下命令安装CUDA版本的pytorch:

pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

安装之后执行python命令进入python环境,执行如下代码:

1
2
import torch
torch.cuda.is_available()

如果显示True则说明CUDA版本的pytorch安装成功。

4. 安装whisper

切换到我们之前创建的whisper环境,执行如下命令安装whisper:

pip install -U openai-whisperpip install setuptools-rust

安装完毕之后执行如下命令就可以使用whisper了:

whisper 'C:/Users/raymond/Desktop/voice.aac' --language zh --model turbo

如上命令表示对C:/Users/raymond/Desktop/voice.aac文件进行中文语言的识别,使用turbo模型。第一次执行该命令会下载模型文件,模型文件较大,下载时请确保网络通畅。执行结果如下

[00:00.000 --> 00:03.060] 提到肉毒毒素[00:03.060 --> 00:04.540] 你会想到什么[00:04.540 --> 00:10.820] 你真的了解它吗[00:10.820 --> 00:12.540] 2017年[00:12.540 --> 00:14.180] 肉毒毒素以万能药标签[00:14.180 --> 00:15.500] 登上时代周刊方面[00:15.500 --> 00:17.280] 目前它在全球[00:17.280 --> 00:18.960] 已被应用于几十种适应症[00:18.960 --> 00:20.560] 仅在2019年[00:20.560 --> 00:23.000] 接受注射的就已超过620万例[00:23.000 --> 00:24.880] 但不要忘了[00:24.880 --> 00:26.780] 肉毒毒素更是一种神经毒素[00:26.780 --> 00:29.000] 还曾被当作生化武器使用... 省略 ...

生成字幕

我们可以使用ffmpeg将音频从视频中提取出来,然后使用whisper生成字幕,最后使用ffmpeg将字幕添加到视频中。

使用如下命令提取音频:

ffmpeg -i input.mp4 -vn -acodec copy output.aac

然后使用whisper生成字幕,我们先在pycharm中创建一个test-whisper项目,并且把python解释器设置为Miniconda创建的whisper环境。创建一个main.py文件,写入如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import whisper
from whisper.utils import get_writer

root = 'E:/'

# 使用turbo模型
model = whisper.load_model('turbo')
prompt = '如果使用了中文,请使用简体中文来表示文本内容'

# 选择声音文件,识别中文,并且打印详细信息
result = model.transcribe(root + 'output.aac', language='zh', initial_prompt=prompt, verbose=True)
print(result['text'])

# 保存字幕文件
writer = get_writer('srt', root)
writer(result, 'output.srt')

如上代码表示使用turbo模型,识别中文,打印详细信息,并且保存字幕文件。执行完毕之后我们可以在E:/目录下看到生成的字幕文件。

最后我们使用ffmpeg将字幕添加到视频中:

ffmpeg -i input.mp4 -i output.srt -c:s mov_text -c:v copy -c:a copy output.mp4

之后我们在播放这个视频的时候就会有字幕了。

参考

video-subtitle-generator
基于Anaconda的pytorch-cuda
CUDA与cuDNN的安装与配置
ffmpeg视频合并、格式转换、截图

ffmpeg笔记

2024-06-18 18:13:25

合并一个文件夹内的所有视频
1
2
3
4
5
find *.mp4 | sed 's:\ :\\\ :g'| sed 's/^/file /' > fl.txt
ffmpeg -f concat -i fl.txt -c copy output.mp4
// 忽略错误信息
ffmpeg -safe 0 -f concat -i fl.txt -c copy output.mp4
rm fl.txt

参考资源

视频压缩
1
2
3
4
5
6
// 视频使用h.264编码,声音使用aac编码
ffmpeg -i input.mp4 -vcodec h264 -acodec aac output.mp4
// 视频使用h.265编码,压缩到更小文档
ffmpeg -i input.mp4 -vcodec libx265 -crf 28 output.mp4
// 视频使用h.264编码,保留更好的质量
ffmpeg -i input.mp4 -vcodec libx264 -crf 20 output.mp4

crf越小,视频质量越高;crf越大,视频文件越小

编码参数也可以简写,从-vcodec-acodec改为-c:v-c:a

1
2
3
ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
ffmpeg -i input.mp4 -c:v libx265 -crf 28 output.mp4
ffmpeg -i input.mp4 -c:v libvpx-vp9 -crf 31 -b:v 0 output.mkv

参考资源

其中AVC/H264HEVC/H265都是软件编码,速度很慢。可以选择英伟达的硬件编码:hevc_nvenc与h264_nvenc,它们使用硬件加速,速度很快。

参考资源

使用英伟达显卡进行编码:

1
ffmpeg -i video.mp4 -c:v hevc_nvenc -crf 28 output.mp4

将视频从H.264转码到H.265,花了55分钟,视频体积从3.8GB减小到430MB,效果立竿见影。转码命令:ffmpeg -i 1.mp4 -c:v libx265 -vtag hvc1 -c:a copy 1_hevc.mp4

在win10可以用scoop安装ffmpeg,更新Windows上面通过scoop安装的所有程序
scoop list | foreach { scoop update $_.Name }

将视频以同样的编码,按照指定时间进行裁剪

1
ffmpeg -ss 00:05 -to 08:53.500 -i ./input.mp4 -c copy video.mp4

利用ffmpeg快速剪辑视频

1
ffmpeg -ss 07:18 -to 13:45 -i ./aaa.mkv -c copy bbb.mkv
  • -ss表示开始时间
  • -to表示结束时间
  • -i是输入文档
  • -c表示使用被剪辑视频一样的编码
  • bbb是输出文档的名称

合并视频和声音,视频使用原始编码,声音改为aac编码

1
ffmpeg -i 1.mp4 -i 1.opus -c:v copy -c:a aac output.mp4

将PNG格式图片转为JPG格式图片

1
ffmpeg -i image.png -preset ultrafast image.jpg

修改图片的尺寸

1
2
ffmpeg -i image.jpeg -vf scale=413:626 2寸.jpeg
ffmpeg -i image.jpeg -vf scale=390:567 1寸.jpeg

将一个音频重复10次

1
ffmpeg -stream_loop 10 -i input.m4a -c copy output.m4a

如何参与Apache顶级开源项目

2024-01-24 19:27:14

我们在日常工作中经常会使用到很多的开源项目,开源也是一个在工作和学习中都离不开的内容。一般来说,开源项目可以选择直接开源,也可以选择捐赠给某些基金会,例如Linux FoundationCNCFASF等等。以ASF为例,如果一个项目想要成为顶级项目,则需要先通过孵化器孵化,孵化结束毕业才能成为顶级项目。最近我因为一些原因参与了云原生网关APISIX开源项目,这里做一下介绍。

搭建环境

首先我们需要下载源代码并且构建开发流程,根据官网介绍,我们把项目代码fork到自己的仓库并clone到本地,随后在本地仓库中将原始的项目设置为上游upstream,之后新建分支进行开发即可

~ git clone [email protected]:RitterHou/apisix.git~ cd apisix~ git remote -v~ git remote add upstream https://github.com/apache/apisix.git~ git config --global user.name "derobukal"~ git config --global user.email "[email protected]"~ git fetch upstream~ git checkout master~ git rebase upstream/master~ git push origin master~ git checkout -b issue-10484~ cd ..

根据官方教程,我们还需要安装APISIX的开发环境注1

~ export https_proxy="http://192.168.65.100:7890"~ export http_proxy="http://192.168.65.100:7890"~ wget https://raw.githubusercontent.com/apache/apisix/master/utils/install-dependencies.sh~ APISIX_RUNTIME='1.1.1' bash install-dependencies.sh~ cd apisix~ make deps~ sudo mkdir /usr/local/apisix~ sudo mkdir /usr/local/apisix/logs~ sudo chown raymond:raymond /usr/local/apisix -R~ sudo make install

以及安装和启动etcd

~ ETCD_VERSION='3.4.18' wget https://github.com/etcd-io/etcd/releases/download/v${ETCD_VERSION}/etcd-v${ETCD_VERSION}-linux-amd64.tar.gz && tar -xvf etcd-v${ETCD_VERSION}-linux-amd64.tar.gz && cd etcd-v${ETCD_VERSION}-linux-amd64 && sudo cp -a etcd etcdctl /usr/bin/~ cd ..~ etcd

最简单的PR

搭建好了环境之后,就可以修改代码并提交PR了。一般来说开源项目都会有多种类型的改动,以apisix为例,它限制了PR可以为固定的几种类型

featfixdocsstylerefactorperftestbuildcichorerevertchange

包含了文档修改、新功能、bug修复等等,我们选择比较简单的文档修改作为第一个PR。我在使用APISIX的过程中,发现它证书相关的文档中存在一个错误

在上图中,这里的地址不应该是/hello而应该是/get,因此我们可以在本地仓库新建一个分支并对这个问题作出修改。修改后我们将这次改动提交(为了使提交更加的清晰和安全,建议合并commit并对commit进行签名)并push到我们自己的远程仓库,随后在GitHub上面创建一个针对原始仓库的Pull Request。一般项目在创建一个PR的时候都会有模板信息,照着模板信息进行填写即可,填写完毕就可以提交PR并等待项目的成员进行处理了

修复issue中的问题

在APISIX中有着很多的ISSUE

我们可以关注这些ISSUE看有没有自己能解决的问题。一般来说,带有good first issue标签的都是比较简单并且适合新人的,我们可以优先从这些issue中寻找自己能解决的问题

在确定了issue之后,我们可以请求管理员将这个issue分配给自己,防止别人也会去解决这个问题从而浪费时间。当然,有的时候issue即使已经被分配给别人了,但是如果他一直没有解决这个问题,我们仍然可以请求将这个issue分配给自己

搭建测试环境

对于issue-10484,因为涉及到代码更改,因此需要执行测试。APISIX使用了test-nginx框架来执行测试,官方有关于如何进行测试的介绍

我们需要安装测试框架注2

sudo cpan Test::Nginx

并下载依赖测试模块

➜  apisix git:(issue-10484) git clone https://github.com/api7/test-toolkit/ t/toolkit

修改完代码之后可以执行相关的测试

~ PATH=/usr/local/openresty/nginx/sbin:/usr/bin PERL5LIB=.:$PERL5LIB FLUSH_ETCD=1 prove -Itest-nginx/lib -r t/admin/ssl2.tt/admin/ssl2.t .. ok    All tests successful.Files=1, Tests=52, 11 wallclock secs ( 0.06 usr  0.01 sys +  3.61 cusr  1.05 csys =  4.73 CPU)Result: PASS

如果测试没有问题就可以提交PR了。

通过CI的测试

apisix使用GitHub的workflow进行CI执行测试,以redhat-ci.yaml为例,它会在多个平台上执行多个文件夹内的测试。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
jobs:
test_apisix:
name: run ci on redhat ubi
runs-on: ubuntu-20.04
timeout-minutes: 90
strategy:
fail-fast: false
matrix:
events_module:
- lua-resty-worker-events
- lua-resty-events
test_dir:
- t/plugin/[a-k]*
- t/plugin/[l-z]*
- t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misc
- t/node t/pubsub t/router t/script t/secret t/stream-node t/utils t/xds-library

如上所示,GitHub action中的matrix默认会对其下面的的多个选项进行合并,例如redhat-ci.yamlevents_moduletest_dir组合起来就会构成8个执行脚本

lua-resty-worker-events t/plugin/[a-k]*lua-resty-worker-events t/plugin/[l-z]*lua-resty-worker-events t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misclua-resty-worker-events t/node t/pubsub t/router t/script t/secret t/stream-node t/utils t/xds-librarylua-resty-events t/plugin/[a-k]*lua-resty-events t/plugin/[l-z]*lua-resty-events t/admin t/cli t/config-center-yaml t/control t/core t/debug t/discovery t/error_page t/misclua-resty-events t/node t/pubsub t/router t/script t/secret t/stream-node t/utils t/xds-library

github的CI会对这些所有的任务执行测试。如果测试执行失败了,需要重点关注失败的日志,并在本地调试直到可以通过测试。如果遇到数据不对的问题,可以重新对数据进行初始化

apisix quit && apisix init && apisix init_etcd && apisix start

社区交流

在代码提交并创建了PR之后,我们可能会收到一些反馈,这时候我们就需要针对这些反馈作出回应。以#10771为例

我在提交了代码之后,管理员认为需要将aes_encrypt_pkeyaes_decrypt_pkey方法中的field字段去掉。我一开始在写代码的时候就发现这个字段去掉会导致数据加解密过程中ssldata的行为不一致,可能导致错误。不过管理员让我放心删,没问题,本着信任的态度我就把参数删除掉了

但是删除掉了之后测试却怎么也跑不过,我因为非常信任社区管理员也没有怀疑是因为ssldata逻辑不一致导致的,而是从其它地方入手进行排查。最终花了大量的时间经过了很多**的排查之后,发现其实就是因为ssldata的行为逻辑不一致导致的。我随后询问了管理员,并且把field参数加了回来

field参数加回来之后,所有的test cases就都能跑过了

所有测试用例通过,一段时间之后PR被review没有问题,就会被合并到master分支了

参考

Revolution OS
S04E00-吴晟:开源项目进入 Apache 孵化器意味着什么
Apache 是如何运作的?
新手如何快速参与开源项目
如何从小白成长为 Apache Committer?

  1. 在执行install-dependencies.sh脚本的时候,会下载golang的依赖,比如gRPC-Go,这里需要保证网络能够顺畅访问golang的官方仓库。

  2. 为了保证test-nginx正常安装,需要网络顺畅,能够正常访问相关资源。