白盒检测工具之代码统计

AST-Framework 产品的白盒工具在进行代码分析之前,需要做一些前置的数据采集用于后续项目基本信息的输出,包括:项目使用的编程语言、项目使用的开发框架、代码行数等信息。经过调研,发现了一款成熟度很高的代码统计工具 Tokei,本文将重点介绍如何在 AST-Framework 产品的 sast-plugin 插件中集成 Tokei,实现项目的代码统计。

Tokei 官方文档及用法

Tokei 是一个用于统计代码文件数据的开源工具,通过 Tokei 可以查看代码仓库中文件的数量、文件总行数、代码行数、注释行数和空行数量。Tokei 从2015年开源至今,项目已经非常成熟,拥有 7k 的star,支持 217 种语言、统计结果准确度、统计速度等指标都非常优秀,下面介绍 tokei 的基本用法。

安装方法

MacOS 通过 brew install tokei 命令安装 tokei 工具,然后执行 tokei <dir> 获取<dir>目录中代码文件的统计数据,包括:每种语言的文件数、总行数、代码行数、评论行数和空行数。

更多操作系统的安装方法及手动安装方法请访问官方文档🔗

配置文件

Tokei 的配置文件为tokei.toml.tokeirc,默认从执行tokei命令的目录、用户的HOME目录或配置文件目录中搜索并使用配置文件,搜索顺序为从左到右。配置文件格式如下:

1
2
3
4
5
6
7
8
# The width of the terminal output in columns.
columns = 80
# Sort languages based on the specified column.
sort = "lines"
# If set, tokei will only show the languages in `types`.
types = ["Python"]
# Any doc strings (e.g. `"""hello"""` in python) will be counted as comments.
treat_doc_strings_as_comments = true

使用方法

基本用法

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
USAGE:
tokei [FLAGS] [OPTIONS] [--] [input]...

FLAGS:
-f, --files Will print out statistics on individual files.
-h, --help Prints help information
--hidden Count hidden files.
-l, --languages Prints out supported languages and their extensions.
--no-ignore Don't respect ignore files (.gitignore, .ignore, etc.). This implies --no-ignore-parent,
--no-ignore-dot, and --no-ignore-vcs.
--no-ignore-dot Don't respect .ignore and .tokeignore files, including those in parent directories.
--no-ignore-parent Don't respect ignore files (.gitignore, .ignore, etc.) in parent directories.
--no-ignore-vcs Don't respect VCS ignore files (.gitignore, .hgignore, etc.), including those in parent
directories.
-V, --version Prints version information
-v, --verbose Set log output level:
1: to show unknown file extensions,
2: reserved for future debugging,
3: enable file level trace. Not recommended on multiple files

OPTIONS:
-c, --columns <columns> Sets a strict column width of the output, only available for terminal output.
-e, --exclude <exclude>... Ignore all files & directories matching the pattern.
-i, --input <file_input> Gives statistics from a previous tokei run. Can be given a file path, or "stdin" to
read from stdin.
-o, --output <output> Outputs Tokei in a specific format. Compile with additional features for more format
support. [possible values: cbor, json, yaml]
-s, --sort <sort> Sort languages based on column [possible values: files, lines, blanks, code, comments]
-t, --type <types> Filters output by language type, separated by a comma. i.e. -t=Rust,Markdown

ARGS:
<input>... The path(s) to the file or directory to be counted.

查看特定项目的代码文件统计数据

用法:tokei <target code dir>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ tokei .
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
Java 168 8956 6373 1358 1225
XML 15 862 784 6 72
-------------------------------------------------------------------------------
Markdown 4 39 0 27 12
|- Java 1 28 25 0 3
|- Shell 2 4 4 0 0
(Total) 71 29 27 15
===============================================================================
Total 187 9857 7157 1391 1309
===============================================================================

查看多个项目的代码文件统计数据

用法:tokei <dir1> <dir2> <dir3>tokei <dir1>,<dir2>,<dir3>

1
2
3
4
5
6
7
8
9
10
$ tokei AstApi AstSpy
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
Java 4 288 116 124 48
Markdown 1 2 0 2 0
XML 2 38 32 0 6
===============================================================================
Total 7 328 148 126 54
===============================================================================

查看排除特定目录/文件后的代码文件统计数据

很多时候我们并不需要统计一些类型的文件,比如:Java 编译后生成的 .class 文件、Python 运行后创建的 .pyc 文件等,在 git 代码仓库中,可以通过 .gitignore 文件进行排除。

tokei 作为一款成熟的工具,支持复用已有的排除策略,直接排除代码无关或我们不关注的目录/文件,tokei 在扫描时,解析.gitignore.ignore 文件并使用文件中定义的排除策略,此外,也支持通过命令行参数( --exclude )的方式额外指定排除策略,语法与 gitignore 语法相同。

1
2
3
4
5
6
7
8
9
$ tokei IastEngine --exclude .classs
===============================================================================
Language Files Lines Code Comments Blanks
===============================================================================
Java 28 1715 1175 325 215
XML 1 116 111 0 5
===============================================================================
Total 29 1831 1286 325 220
===============================================================================

统计结果排序

tokei 默认按照编程语言进行排序,也支持通过 --sort 参数指定排序字段,12.0.0 版本支持的排序字段包括:blanks, code, comments, lines

1
$ tokei ./IastEngine --sort code

查看每个文件的统计数据

tokei 默认输出用户指定目录或文件的代码统计结果,白盒做应用框架预分析时,不仅需要知道项目中使用的语言分布,还需要知道都有哪些文件,方便直接根据特征解析文件,提取使用的框架。我们可以通过--files 参数来返回每个文件的结果,同时拿到语言分析和对应的代码文件路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$ tokei ./foo --files
=====================================================================================================================
Language Files Lines Code Comments Blanks
=====================================================================================================================
Apache Velocity 19 10018 9558 25 435
---------------------------------------------------------------------------------------------------------------------
./src/site/xdoc/manual/customloglevels.xml.vm 347 340 0 7
---------------------------------------------------------------------------------------------------------------------
XML 584 54251 43766 9010 1475
---------------------------------------------------------------------------------------------------------------------
./log4j-taglib/pom.xml 205 184 20 1
---------------------------------------------------------------------------------------------------------------------
YAML 10 322 284 1 37
---------------------------------------------------------------------------------------------------------------------
./log4j-spring-boot/src/test/resources/application.yml 5 5 0 0
=====================================================================================================================
Total 3083 388247 245182 103556 39509
======================================================================================================================

统计结果输出值文件

tokei 支持将统计结果输出至文件中,目前支持的文件格式包括:jsonyamlcbor,可通过 --output 参数指定输出的数据格式

1
2
3
$ tokei ./foo --output json
$ tokei ./foo --output yaml
$ tokei ./foo --output cbor

sast-plugin集成tokei工具

sast-plugin 中只需要调用 tokei 命令,将结果转换为 golang 对象即可,代码示例如下:

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package statistic

import (
"bytes"
"os/exec"

"gopkg.in/yaml.v3"
)

type CodeStatistic struct {
Total struct {
Blanks int `yaml:"blanks"`
Children struct {
Java []struct {
Name string `yaml:"name"`
Stats struct {
Blanks int `yaml:"blanks"`
Blobs struct {
} `yaml:"blobs"`
Code int `yaml:"code"`
Comments int `yaml:"comments"`
} `yaml:"stats"`
} `yaml:"Java"`
Markdown []struct {
Name string `yaml:"name"`
Stats struct {
Blanks int `yaml:"blanks"`
Blobs struct {
} `yaml:"blobs"`
Code int `yaml:"code"`
Comments int `yaml:"comments"`
} `yaml:"stats"`
} `yaml:"Markdown"`
} `yaml:"children"`
Code int `yaml:"code"`
Comments int `yaml:"comments"`
Inaccurate bool `yaml:"inaccurate"`
Reports []interface{} `yaml:"reports"`
} `yaml:"Total"`
}

func StatisticalCode(codeDir string) (*CodeStatistic, error) {
var stdout, stderr bytes.Buffer
cmd := exec.Command("tokei", codeDir, "--output", "json")
cmd.Stdout = &stdout // 标准输出
cmd.Stderr = &stderr // 标准错误
cmd.Run()

codeStatistic = CodeStatistic{}
yaml.Unmarshal(stdout.Bytes(), &codeStatistic)
return nil
}

相关链接

进击的DevSecOps,持续分享SAST/IAST/RASP的技术原理及甲方落地实践。如果你对 SAST、IAST、RASP方向感兴趣,可以扫描下方二维码关注公众号,获得更及时的内容推送。

owefsad wechat
进击的DevSecOps,持续分享SAST/IAST/RASP的技术原理及甲方落地实践。如果你对 SAST、IAST、RASP方向感兴趣,可以扫描下方二维码关注公众号,获得更及时的内容推送。
0%