摘要:檢查的執(zhí)行邏輯自定義檢查規(guī)則創(chuàng)建創(chuàng)建執(zhí)行檢查根據(jù)中的打印報(bào)告省略部分代碼上面代碼的邏輯就是執(zhí)行檢查的主要過(guò)程。增量代碼檢查的實(shí)現(xiàn)輸出檢查報(bào)告根據(jù)上面代碼的邏輯,是檢查輸出結(jié)果的過(guò)程。
背景Lint是Google提供的一個(gè)靜態(tài)代碼檢查工具,可以掃描出代碼中潛在的問(wèn)題,并且會(huì)對(duì)開(kāi)發(fā)人員做出提示。而且除了Android原生提供的幾百種Lint規(guī)則以外,還可以使用Lint框架的API自定義Lint規(guī)則。
自定義Lint規(guī)則可以根據(jù)項(xiàng)目需求制定不同的掃描規(guī)則。比如:編碼規(guī)范、代碼風(fēng)格、特定問(wèn)題檢查等。
有了自定義檢查規(guī)則,提交代碼的時(shí)候可以規(guī)范代碼編寫(xiě)。但是還有一個(gè)問(wèn)題,新的代碼使用新的規(guī)范,但如何解決項(xiàng)目中老代碼風(fēng)格?對(duì)于老代碼,不可能每行代碼都要修改。這個(gè)時(shí)候就要有針對(duì)性的檢查,那就是使用增量檢查。
增量代碼檢查有以下幾個(gè)好處
避免修改“祖?zhèn)鳌贝a的一些問(wèn)題。如果全量掃描,之前老代碼的問(wèn)題一大堆就會(huì)暴露出來(lái), 這樣就大大增加了工作量,開(kāi)發(fā)人員也沒(méi)有那么多的精力全部修改;
增加了一些代碼規(guī)范的強(qiáng)制性。增量掃描代碼,如果代碼有問(wèn)題,就會(huì)滾,可以強(qiáng)制開(kāi)發(fā)人 員規(guī)范代碼;
實(shí)現(xiàn)Lint增量代碼檢查工具這里L(fēng)int增量代碼檢查工具是以Gradle插件的方式實(shí)現(xiàn)的。只需要在項(xiàng)目中引用插件便可使用Lint工具。主要實(shí)現(xiàn)的功能是在git提交場(chǎng)景下,每次提交代碼都會(huì)檢查新增的代碼(以行為單位)。如果代碼中存在不符合Lint自定義規(guī)則的代碼,就回滾本次提交。
增量代碼檢查流程Lint增量代碼檢查工具使用git hooks(post-commit) + Lint框架實(shí)現(xiàn)。
git hooks:是用來(lái)響應(yīng)git的操作的腳本,相當(dāng)于一個(gè)回調(diào)。執(zhí)行特定的git操作會(huì)出發(fā)特定的git hooks腳本執(zhí)行。
Lint框架:是實(shí)現(xiàn)Lint掃描的基礎(chǔ)。利用Lint框架提供的API執(zhí)行Lint掃描。
提交(git commit)本次修改代碼(通過(guò)git diff命令找出提交的文件);
觸發(fā)git hooks(post-commit)腳本執(zhí)行。在腳本中執(zhí)行Lint檢查任務(wù)(該任務(wù)是gradle任務(wù))開(kāi)始Lint檢查;
創(chuàng)建LintRequest(主要作用是指定Lint將要掃描的文件);
獲取增量代碼(通過(guò)git diff找出修改的行號(hào));
開(kāi)始Lint檢查;
檢查完畢輸出結(jié)果,如果有不符合規(guī)則的代碼,將回退本次提交。
看完上面的流程,可能會(huì)覺(jué)得不明所以。這里針對(duì)各個(gè)步驟做出詳細(xì)解析。在實(shí)現(xiàn)Lint增量代碼檢查的過(guò)程中,首要的步驟就是獲取將要提交的增量代碼。目前的解決方案是通過(guò)git命令獲取相關(guān)數(shù)據(jù)。
目前的方案是通過(guò)使用post-commit腳本觸發(fā)檢查流程。post-commit腳本是在git commit之后執(zhí)行。
獲取增量文件
git diff --name-only --diff-filter=ACMRTUXB HEAD~1 HEAD~0
通過(guò)git diff命令獲取本次提交的文件。
/**
* 通過(guò)Git命令獲取需要檢查的文件
*
* @param project gradle.Project
* @return 文件列表
*/
List getCommitChange(Project project) {
ArrayList filterList = new ArrayList<>()
try {
//此命令獲取本次提交的文件 在git commit之后執(zhí)行
String command = "git diff --name-only --diff-filter=ACMRTUXB HEAD~1 HEAD~0"
String changeInfo = command.execute(null, project.getRootDir()).text.trim()
if (changeInfo == null || changeInfo.empty) {
return filterList
}
String[] lines = changeInfo.split("
")
return lines.toList()
} catch (Exception e) {
e.printStackTrace()
return filterList
}
}
獲取增量代碼
這是關(guān)鍵的一步,因?yàn)檫@一步要獲取增量代碼所在的具體行號(hào),通過(guò)使用這些行號(hào)數(shù)據(jù)實(shí)現(xiàn)增量檢查的效果。
git diff --unified=0 --ignore-blank-line --ignore-all-space HEAD~1 HEAD filepath
filepath就是增量文件的相對(duì)路徑。
數(shù)據(jù)準(zhǔn)備完畢以后,剩下的工作就要交給Lint框架了。接下來(lái)開(kāi)始執(zhí)行Lint檢查操作。
/**
* 通過(guò)git diff獲取已提交文件的修改,包括文件的添加行的行號(hào)、刪除行的行號(hào)、修改行的行號(hào)
*
* @param filePath 文件路徑
* @param project Project對(duì)象
* @param startIndex 修改開(kāi)始的下表數(shù)組
* @param endIndex 修改結(jié)束的下表數(shù)組
*/
void getFileChangeStatus(String filePath, Project project, List startIndex, List endIndex) {
try {
String command = "git diff --unified=0 --ignore-blank-lines --ignore-all-space HEAD~1 HEAD " + filePath
String changeInfo = command.execute(null, project.getRootDir()).text.trim()
String[] changeLogs = changeInfo.split("@@")
String[] indexArray
for (int i = 1; i < changeLogs.size(); i += 2) {
indexArray = changeLogs[i].trim().split(" ")
try {
int start, end
String[] startArray = null
if (indexArray.length > 1) {
startArray = indexArray[1].split(",")
}
if (startArray != null && startArray.length > 1) {
start = Integer.parseInt(startArray[0])
end = Integer.parseInt(startArray[0]) + Integer.parseInt(startArray[1])
} else {
start = Integer.parseInt(startArray[0])
end = start + 1
}
startIndex.add(start)
endIndex.add(end)
} catch (NumberFormatException e) {
e.printStackTrace()
startIndex.add(0)
endIndex.add(0)
}
}
} catch (Exception e) {
e.printStackTrace()
}
}
Lint框架中的主要類說(shuō)明:
LintCliClient:Lint客戶端,作用是集成lint檢查的操作、相關(guān)配置以及l(fā)int檢查的入口。
LintCliFlags:Lint標(biāo)志位管理類,提供了Lint操作的標(biāo)志位。Lint代碼檢查工具主要使用了該類中生成日志的配置,通過(guò)加入不同實(shí)現(xiàn)的報(bào)告生成類可以實(shí)現(xiàn)不同的輸出格式(比如TXT、XML、HTML等)。
LintRequest:執(zhí)行Lint操作時(shí)的一個(gè)請(qǐng)求類,主要作用是存儲(chǔ)Lint將要掃描的文件。在Lint工具中重寫(xiě)LintRequest初始化方法可以實(shí)現(xiàn)增量文件的檢查。
LintDriver:執(zhí)行Lint規(guī)則檢查邏輯的類。
IssueRegistry:自定義Lint規(guī)則管理類。用于添加Lint自定義規(guī)則。
上述對(duì)于Lint框架中類的介紹是在實(shí)現(xiàn)Lint增量代碼檢查中主要用到的類。
創(chuàng)建LintRequest
class LintToolClient extends LintCliClient {
@Override
/**
* 通過(guò)重寫(xiě)createLintRequest方法創(chuàng)建LintRequest
*/
protected LintRequest createLintRequest(List files) {
LintRequest request = super.createLintRequest(files)
for (Project project : request.getProjects()) {
for (File file : files) {
project.addFile(file)
}
}
return new LintRequest(this, files)
}
}
上面的代碼就是LintRequest的創(chuàng)建過(guò)程,通過(guò)重寫(xiě)LintCliClient中的createLintRequest方法。其中參數(shù)files就是將要檢查的文件。
Lint檢查的執(zhí)行邏輯
/*LintCliClient*/
public int run(@NonNull IssueRegistry registry, @NonNull List files) throws IOException {
assert !flags.getReporters().isEmpty();
this.registry = registry; //Lint自定義檢查規(guī)則
LintRequest lintRequest = createLintRequest(files); //創(chuàng)建LintRequest
driver = createDriver(registry, lintRequest); //創(chuàng)建LintDriver
addProgressPrinter();
validateIssueIds();
driver.analyze(); //執(zhí)行Lint檢查
Collections.sort(warnings);
int baselineErrorCount = 0;
int baselineWarningCount = 0;
int fixedCount = 0;
LintBaseline baseline = driver.getBaseline();
if (baseline != null) {
baselineErrorCount = baseline.getFoundErrorCount();
baselineWarningCount = baseline.getFoundWarningCount();
fixedCount = baseline.getFixedCount();
}
Stats stats = new Stats(errorCount, warningCount,
baselineErrorCount, baselineWarningCount, fixedCount);
boolean hasConsoleOutput = false;
//根據(jù)LintCliFlags中的Reports打印Lint報(bào)告
for (Reporter reporter : flags.getReporters()) {
reporter.write(stats, warnings);
if (reporter instanceof TextReporter && ((TextReporter)reporter).isWriteToConsole()) {
hasConsoleOutput = true;
}
}
//............省略部分代碼..............
return flags.isSetExitCode() ");
上面代碼的邏輯就是Lint執(zhí)行檢查的主要過(guò)程。可以看到,在代碼中先傳入自定義的Lint規(guī)則IssueRegistry,然后創(chuàng)建LintRequest,接下就開(kāi)始執(zhí)行Lint檢查,最后將結(jié)果輸出。結(jié)果輸出到添加在LintCliFlags的Reports中。
增量代碼檢查的實(shí)現(xiàn)
//輸出Lint檢查報(bào)告
for (Reporter reporter : flags.getReporters()) {
reporter.write(stats, warnings);
if (reporter instanceof TextReporter && ((TextReporter)reporter).isWriteToConsole()) {
hasConsoleOutput = true;
}
}
根據(jù)上面代碼的邏輯,是Lint檢查輸出結(jié)果的過(guò)程。增量代碼檢查的實(shí)現(xiàn)就是重寫(xiě)Reporter類,在重寫(xiě)的類中實(shí)現(xiàn)自定義的輸出規(guī)則,這里的實(shí)現(xiàn)方法就是使用上文中通過(guò)git命令獲取的文件修改行號(hào)進(jìn)行過(guò)濾,從而實(shí)現(xiàn)增量檢查的效果。
總結(jié)上面描述了Lint增量代碼檢查工具的實(shí)現(xiàn)過(guò)程,實(shí)現(xiàn)增量代碼檢查的關(guān)鍵就是獲取文件修改的精確位置,以便在輸出結(jié)果是進(jìn)行過(guò)濾。
增量代碼檢查相較于常規(guī)的Lint檢查,好處就是能夠避免老代碼的與新規(guī)則的沖突,同時(shí)結(jié)合git使用能夠在提交代碼時(shí)增加一些強(qiáng)制性。
最后,Lint增量代碼工具中使用的是Lint的自定義規(guī)則。這些還可以作為原生的Lint規(guī)則的擴(kuò)展,在代碼編寫(xiě)的階段使用,效果跟原聲Lint規(guī)則一致。
對(duì)Lint增量代碼工具的實(shí)現(xiàn)感興趣的同學(xué),可以在github上獲取源碼,感興趣的可以star一下。
Lint增量代碼檢查工具鏈接
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/7213.html
摘要:通過(guò)團(tuán)隊(duì)的全力全策,美團(tuán)外賣的平均率從千分之三降到了萬(wàn)分之二,最優(yōu)值萬(wàn)一左右率統(tǒng)計(jì)方式次數(shù)。美團(tuán)外賣自年創(chuàng)建以來(lái),業(yè)務(wù)就以指數(shù)級(jí)的速度發(fā)展。目前美團(tuán)外賣日完成訂單量已突破萬(wàn),成為美團(tuán)點(diǎn)評(píng)最重要的業(yè)務(wù)之一。 面試中常常問(wèn)到的是Android的性能優(yōu)化以及Crash處理。 今天我們來(lái)學(xué)習(xí)一下啊美團(tuán)App的Crash處理。更多參考《Android性能優(yōu)化:手把手帶你全面實(shí)現(xiàn)內(nèi)存優(yōu)化》 原為地...
閱讀 580·2021-11-25 09:44
閱讀 2670·2021-11-24 09:39
閱讀 2348·2021-11-22 15:29
閱讀 3554·2021-11-15 11:37
閱讀 3423·2021-09-24 10:36
閱讀 2559·2021-09-04 16:41
閱讀 1028·2021-09-03 10:28
閱讀 1930·2019-08-30 15:55