Emerge (或emerge-viz )是一種互動式程式碼分析工具,用於收集有關軟體專案的原始程式碼結構、指標、依賴性和複雜性的見解。您可以掃描專案的原始程式碼,計算指標結果和統計數據,產生具有圖形結構(例如依賴關係圖或文件系統圖)的互動式Web應用程序,並以某些文件格式匯出結果。 Emerge 目前支援以下語言的解析: C
、 C++
、 Groovy
、 Java
、 JavaScript
、 TypeScript
、 Kotlin
、 ObjC
、 Ruby
、 Swift
、 Python
、 Go
。結構、著色和聚類的計算是基於力導向圖模擬和 Louvain 模組化相結合的想法。 emerge 主要以 Python 3 編寫,並在 macOS、linux 和現代 Web 瀏覽器(即最新的 Safari、Chrome、Firefox、Edge)上進行了測試。
出現(/ɪˈməːdʒ/)
- 從某物中出來或從某物後面出現
- 出名,尤其是透過檢查某事或提出相關問題而出名
該專案的主要目標是創建一個免費/開源工具,任何對軟體開發、架構、指標和視覺化感興趣的人都可以輕鬆使用該工具,以收集有關這些主題的更多見解。它應該促進/支持透過使用探索性方法來更好地理解給定的軟體專案。
C
、 C++
、 Groovy
、 Java
、 JavaScript
、 TypeScript
、 Kotlin
、 ObjC
、 Ruby
、 Swift
、 Python
Groovy
、 Java
、 Kotlin
、 Swift
git-based
指標(SLOC、空白複雜度、變更耦合)SwiftUI
和Composable
聲明性 UI 實體的提取git-based
指標視覺化,例如程式碼流失在預先建置的 Docker 容器中使用 emerge 的最簡單方法。唯一的先決條件是擁有 Docker 引擎。例如 Docker 桌面。
像這樣準備你的工作資料夾
config.yml
?export
?source
運行分析的命令是:
docker run --rm -v <YOUR_WORKING_FOLDER_PATH>:/tmp/emerge achtelik/emerge:2.0.0 /tmp/emerge/config.yml
最後一個參數是 Docker 容器內 config.yml 的路徑。
⚡您可以忽略執行結束時的 Pyperclip 錯誤。
如果您使用上面的建議,請注意您的analyses.source_directory
和export.directory
路徑必須以/tmp/emerge
開頭。這是必要的,因為您的分析是在 Docker 容器內執行的。
例如:
---
project_name: java_project_example
loglevel: info
analyses:
- analysis_name: full java check
source_directory: /tmp/emerge/source
.
.
.
export:
- directory: /tmp/emerge/export
.
.
.
Docker 容器本身就是路徑獨立的。請隨意使用您自己的磁碟區安裝和專案配置路徑。
基本上有兩種安裝emerge的方法。如果您熟悉pip
(建議使用pyenv
、 virtualenv
和virtualenvwrapper
的虛擬環境,但不是必要的),您可以簡單地透過以下步驟安裝最新版本的 emerge 。
建議的方法是使用虛擬環境,您可以使用以下範例來執行此操作:
pyenv install 3.10.0
pyenv virtualenv 3.10.0 venv-3.10.0
pyenv activate venv-3.10.0
您可以簡單地使用pip
安裝 emerge 。
在 Ubuntu 20.04+ 上,請確保安裝了graphviz
和graphviz-dev
軟體包,即
apt-get install graphviz graphviz-dev
使用以下命令安裝新套件:
pip install emerge-viz
或如果已經安裝,只需更新:
pip install -U emerge-viz
然後像這樣簡單地執行它:
(emerge) user@host ~ % emerge
usage: emerge [-h] [-c YAMLCONFIG] [-v] [-d] [-e] [-a LANGUAGE]
? Welcome to emerge x.y.z (yyyy-mm-dd hh:mm:ss)
options:
-h, --help show this help message and exit
-c YAMLCONFIG, --config YAMLCONFIG
set yaml config file
-v, --verbose set logging level to INFO
-d, --debug set logging level to DEBUG
-e, --error set logging level to ERROR
-a LANGUAGE, --add-config LANGUAGE
add a new config from a template, where LANGUAGE is one of [JAVA, SWIFT, C, CPP, GROOVY, JAVASCRIPT,
TYPESCRIPT, KOTLIN, OBJC, RUBY, PY, GO]
您可以從命令列建立一個簡單的臨時專案配置,然後只需調整必要的來源/匯出路徑
(emerge) user@host tmp % pwd
/Users/user1/tmp
(emerge) user@host tmp % emerge -a java
✅ created config file from template: /Users/user1/tmp/java-template.yaml
然後只需調整必要的路徑( analyses/source_directory
和export/directory
):
(emerge) user@host tmp % cat java-template.yaml
---
project_name: java_project_example
loglevel: info
analyses:
- analysis_name: full java check
source_directory: /Users/user1/emerge/project/source
only_permit_languages:
- java
only_permit_file_extensions:
- .java
file_scan:
- number_of_methods
- source_lines_of_code
- dependency_graph
- fan_in_out
- louvain_modularity
- tfidf
entity_scan:
- dependency_graph
- source_lines_of_code
- number_of_methods
- fan_in_out
- louvain_modularity
- tfidf
export:
- directory: /Users/user1/emerge/project/export
- graphml
- json
- tabular_file
- tabular_console_overall
- d3
(emerge) user@host tmp %
之後,您可以簡單地開始掃描
(emerge) user@host tmp % emerge -c java-template.yaml
2021-12-04 21:18:15 analysis I starting to analyze java_project_example
2021-12-04 21:18:15 analysis I ⏩ performing analysis 1/1: full java check
2021-12-04 21:18:15 analysis I starting to create filesystem graph in full java check
2021-12-04 21:18:15 analysis I ⏩ starting scan at directory: ...
...
...
...
2021-12-04 21:18:27 analysis I ✅ all your generated/exported data can be found here: /Users/user1/tmp/java
2021-12-04 21:18:27 analysis I ✅ copy the following path to your browser and start your web app: file:///Users/user1/tmp/java/html/emerge.html
2021-12-04 21:18:27 analysis I ✅ total runtime of analysis: 00:00:10 + 154 ms
現在只需將上述file://
路徑複製到任何現代 Web 瀏覽器並以互動方式公開您配置的程式碼庫
您可以按照以下說明克隆此存儲庫並安裝它:
git clone https://github.com/glato/emerge.git
graphviz
包 brew install graphviz
如果您在 Apple Silicon Mac 上遇到以下錯誤
pygraphviz/graphviz_wrap.c:2711:10: fatal error: ' graphviz/cgraph.h ' file not found
# include "graphviz/cgraph.h"
^~~~~~~~~~~~~~~~~~~
1 error generated.
您需要執行以下命令一次來更新新的自製環境的 pygraphviz 包含目錄
pip install --global-option=build_ext --global-option= " -I $( brew --prefix graphviz ) /include/ " --global-option= " -L $( brew --prefix graphviz ) /lib/ " pygraphviz
請在此處查看該問題的上下文。
檢查您的 macOS 上是否安裝了最新的 Python 3。我建議安裝/使用 Homebrew 中的 Python 3。建立 Python 3 虛擬環境(可選在專案結構內)
cd emerge
pip3 install virtualenv
virtualenv -p python3 venv
安裝所需的套件並建立 Python 3 虛擬環境(可以選擇在專案結構中)
apt-get install python3-venv python3-dev graphviz graphviz-dev
cd emerge
python3 -m venv venv
source venv/bin/activate
使用 pip 安裝專案所需的所有依賴項
pip install -r requirements.txt
安裝wheel套件,然後使用pip安裝專案所需的所有依賴項
pip install wheel
pip install -r requirements.txt
從克隆的項目根目錄執行以下命令:
python -m unittest discover -v -s ./emerge -p "test_*.py"
否則執行腳本run_tests.py
:
python run_tests.py
如果您在執行測試時遇到任何問題,請檢查此解決方法。
emerge
作為獨立工具運行 (emerge) user@host emerge % python emerge.py
usage: emerge.py [-h] [-c YAMLCONFIG] [-v] [-d] [-e] [-a LANGUAGE]
? Welcome to emerge x.y.z (yyyy-mm-dd hh:mm:ss)
options:
-h, --help show this help message and exit
-c YAMLCONFIG, --config YAMLCONFIG
set yaml config file
-v, --verbose set logging level to INFO
-d, --debug set logging level to DEBUG
-e, --error set logging level to ERROR
-a LANGUAGE, --add-config LANGUAGE
add a new config from a template, where LANGUAGE is one of [JAVA, SWIFT, C, CPP, GROOVY, JAVASCRIPT,
TYPESCRIPT, KOTLIN, OBJC, RUBY, PY, GO]
讓我們快速嘗試在自己的程式碼庫上執行emerge
python emerge.py -c configs/emerge.yaml
這應該會產生類似的輸出:
... analysis I starting to analyze emerge
... analysis I ⏩ performing analysis 1/1: self-check
... analysis I starting to create filesystem graph in self-check
... analysis I ⏩ starting scan at directory: .
... ...
... analysis I the following statistics were collected in self-check
+-------------------------------------+-------------------+
| statistic name | value |
+-------------------------------------+-------------------+
| scanning_runtime | 00:00:00 + 61 ms |
| scanned_files | 32 |
| skipped_files | 176 |
| parsing_hits | 313 |
| parsing_misses | 141 |
| extracted_file_results | 32 |
| file_results_creation_runtime | 00:00:00 + 538 ms |
| number-of-methods-metric-runtime | 00:00:00 + 4 ms |
| source-lines-of-code-metric-runtime | 00:00:00 + 11 ms |
| louvain-modularity-metric-runtime | 00:00:00 + 161 ms |
| fan-in-out-metric-runtime | 00:00:00 + 4 ms |
| total_runtime | 00:00:00 + 786 ms |
+-------------------------------------+-------------------+
... analysis I the following overall metrics were collected in self-check
+----------------------------------------------+----------------------------+
| metric name | value |
+----------------------------------------------+----------------------------+
| avg-number-of-methods-in-file | 13.0 |
| avg-sloc-in-file | 151.41 |
| total-sloc-in-files | 4845 |
| louvain-communities-dependency-graph | 3 |
| louvain-modularity-dependency-graph | 0.21 |
| louvain-biggest-communities-dependency-graph | 0.49, 0.46, 0.05, 0.0, 0.0 |
| avg-fan-in-dependency-graph | 5.55 |
| avg-fan-out-dependency-graph | 5.55 |
| max-fan-in-dependency-graph | 29 |
| max-fan-in-name-dependency-graph | typing |
| max-fan-out-dependency-graph | 19 |
| max-fan-out-name-dependency-graph | emerge/appear.py |
+----------------------------------------------+----------------------------+
... analysis I ✅ all your generated/exported data can be found here: /Users/user1/tmp/python
... analysis I ✅ copy the following path to your browser and start your web app: file:///Users/user1/tmp/python/html/emerge.html
... analysis I ✅ total runtime of analysis: 00:00:00 + 786 ms
現在只需將上述file://
路徑複製到任何現代 Web 瀏覽器,然後以互動方式公開 emerge 程式碼庫
s
選擇並反白或取消選擇特定節點r
重置目前活動的節點選擇f
淡出所有未選定的節點,以更加突出顯示當前選定的節點現在讓我們讓這變得更有趣...
如果您想在其他專案上使用emerge,您可以從emerge/configs
目錄中簡單地複製或自訂現有設定範本之一。
為了快速運行,調整export
中的source_directory
directory
應該就夠了。
---
project_name : c-example-project
loglevel : info
analyses :
- analysis_name : check_c_files
source_directory : /Users/user1/emerge/project/source/github/linux-5.8.5/crypto
only_permit_languages :
- c
only_permit_file_extensions :
- .c
- .h
ignore_dependencies_containing :
- string.h
ignore_dependencies_matching :
- ^test_(.*).h$
file_scan :
- number_of_methods
- source_lines_of_code
- dependency_graph
- louvain_modularity
- fan_in_out
- tfidf
export :
- directory : /Users/user1/emerge/project/export
- graphml
- json
- tabular_file
- tabular_console_overall
- d3
自訂目前配置(例如config/c-template.yaml
)或建立自己的配置後,只需使用此新配置再次執行 emerge
python emerge.py -c configs/c-template.yaml
掃描後,您的掃描輸出(包括互動式 Web 應用程式)可以在您建立的目錄中找到,並在配置參數export
-> directory
中設置,如上面的日誌所示。
包含檔案和實體掃描的完整 YAML 設定具有以下格式:
---
project_name : java_project_example
loglevel : info
analyses :
- analysis_name : check_java_files_and_classes
source_directory : /Users/user1/emerge/project/source
only_permit_languages :
- java
only_permit_file_extensions :
- .java
ignore_dependencies_containing :
- java.util
file_scan :
- number_of_methods
- source_lines_of_code
- dependency_graph
- fan_in_out
- louvain_modularity
- tfidf
entity_scan :
- dependency_graph
- source_lines_of_code
- number_of_methods
- fan_in_out
- louvain_modularity
- tfidf
export :
- directory : /Users/user1/emerge/project/export
- graphml
- json
- tabular_file
- tabular_console_overall
- d3
有時,排除平台常用的依賴項或對理解專案沒有太大貢獻的依賴項是有意義的。例如,對於Android 專案來說,以下ignore_dependencies_containing
部分是一個很好的起點:
ignore_dependencies_containing :
- android
- java
- javax
或者對於iOS 項目,以下ignore_entities_containing
部分通常是有意義的,例如不考慮圖形輸出的 SwiftUI 預覽:
ignore_entities_containing :
- _Previews
yaml配置基本上定義在以下幾個層面:
鑰匙 | 值/描述 |
---|---|
project_name | 所有分析、掃描和匯出的項目名稱 |
loglevel | 設定日誌等級: error (無提示,僅錯誤), info (包括error )為您提供有關控制流的基本日誌, debug (包括info )將產生大量偵錯日誌 |
analyses | 一系列可以單獨配置的分析,因此一個項目可以包含一對多分析。 |
鑰匙 | 值/描述 |
---|---|
analysis_name | 具體分析名稱 |
source_directory | 遞歸檔案掃描應開始的來源目錄 |
git_directory | git repo 目錄(如果應包含 git 指標) |
git_commit_limit | 應該挖掘上次提交的多少提交?預設值: 150 |
git_exclude_merge_commits | 是否應該從挖掘所有指標中排除合併提交?預設值: true |
ignore_files_containing | 從掃描中排除包含給定子字串的檔案名 |
ignore_directories_containing | 從掃描中排除包含給定子字串的目錄名稱 |
only_permit_languages | 可能的值包括:java、kotlin、objc、swift、ruby、groovy、javascript、c - 明確阻止您在此處設定的語言之外的任何其他語言掃描 |
only_permit_file_extensions | 明確允許您在此處設定的以下檔案副檔名,例如.java |
only_permit_files_matching_absolute_path | 文件掃描只允許使用以下絕對文件路徑列表,例如[/Users/user1/source/file1.java] 。文件應遵循source_directory |
ignore_dependencies_containing | 忽略此子字串清單中包含的每個依賴項,例如java.util |
ignore_dependencies_matching | 忽略與此子字串清單中的任何正規表示式相符的每個依賴項,例如^java.util. |
ignore_entities_containing | 忽略此子字串清單中包含的每個實體,例如NotRelevantClass |
ignore_entities_matching | 忽略與此子字串清單中的任何正規表示式相符的每個實體,例如^Test |
import_aliases | 定義導入別名列表,即替換完整依賴路徑中的子字串,例如"@foo": src/foo 將用src/foo 替換任何@foo 別名 |
override_resolve_dependencies | 如果語言解析器支持,則強制解析此清單中的每個依賴項 |
override_do_not_resolve_dependencies | 如果語言解析器支持,則強制不解析此列表中的每個依賴項(即視為全域依賴項) |
file_scan | 執行檔案掃描,包含應應用於每個來源檔案的指標 |
entity_scan | 執行實體掃描,包含應應用於每個實體(例如每個類別)的指標 |
export | 包含應建立為輸出的任何導出格式 |
appconfig | 包含任何可配置的應用程式配置參數 |
鑰匙 | 值/描述 |
---|---|
dependency_graph | 基於來源檔案建立依賴圖結構,附加指標將會加入圖節點 |
source_lines_of_code | 將原始碼行指標應用於每個文件,建立總體指標 |
number_of_methods | 將多種方法指標應用於每個文件,建立總體指標 |
fan_in_out | 將扇入/扇出圖形指標應用於每個文件,建立總體指標 |
louvain_modularity | 將 louvain 模組化度量應用於每個文件,創建一個整體度量 |
tfidf | 對每個文件應用 tfidf 指標並提取相關語義關鍵字 |
ws_complexity | 對每個文件套用空白複雜度指標 |
git_metrics | 包含一些基於 git 的指標並嘗試將它們應用到每個文件 |
鑰匙 | 值/描述 |
---|---|
dependency_graph | 基於從文件中提取的實體創建依賴關係圖結構,附加指標將添加到圖節點 |
inheritance_graph | 基於從文件中提取的實體創建繼承圖結構,附加指標將添加到圖節點 |
complete_graph | 基於從文件中提取的實體創建完整的圖結構(依賴/繼承圖的聯合),附加指標將添加到圖節點 |
source_lines_of_code | 將原始碼行指標應用於每個實體,建立總體指標 |
number_of_methods | 將多種方法指標應用於每個實體,建立總體指標 |
fan_in_out | 將扇入/扇出圖形指標應用於每個實體,建立總體指標 |
louvain_modularity | 將 louvain 模組化度量應用於每個實體,創建一個整體度量 |
tfidf | 將 tfidf 指標應用於每個實體並提取相關的語義關鍵字 |
鑰匙 | 值/描述 |
---|---|
directory | 所有指定導出格式的輸出目錄 |
graphml | 建立一個 graphML 文件,其中包含映射到圖節點的圖結構和度量結果 |
tabular_file | 建立一個表格格式的文字文件,其中包含每個指標和統計結果 |
tabular_console | 將表格格式的輸出列印到控制台,其中包含每個指標和統計結果 |
tabular_console_overall | 將表格格式的輸出列印到控制台,其中僅包含總體指標和統計結果 |
json | 建立一個包含每個指標和統計結果的 JSON 文件 |
d3 | 在子資料夾force-graph-html 中建立一個Bootstrap/D3 Web應用程序,以進行進一步的視覺化和互動式/探索性分析 |
鑰匙 | 值/描述 |
---|---|
radius_fan_out | 扇出指標的節點半徑倍增因子,預設值: 0.1 |
radius_fan_in | 扇入指標的節點半徑倍增因子,預設: 0.1 |
radius_louvain | louvain 度量的節點半徑倍增因子,預設值: 0.02 |
radius_sloc | sloc 度量的節點半徑倍增因子,預設值: 0.005 |
radius_number_of_methods | 方法數量度量的節點半徑乘法因子,預設值: 0.05 |
heatmap_sloc_active | sloc 指標是否應該包含在熱圖得分計算中?預設值: true |
heatmap_fan_out_active | 扇出指標是否應該包含在熱圖得分計算中?預設值: true |
heatmap_sloc_weight | 熱圖分數計算中 sloc 指標的權重因子,預設值: 1.5 |
heatmap_fan_out_weight | 熱圖得分計算中扇出指標的權重因子,預設值: 1.7 |
heatmap_score_base | 熱圖顏色映射的最小分數閾值,預設: 10 |
heatmap_score_limit | 熱圖顏色映射的最大分數閾值,預設: 300 |
Emerge 支援以下每種語言的檔案副檔名和掃描類型,而file_scan
只是計算指標並將圖形結構中的節點對應到掃描的文件, entity_scan
嘗試從檔案中提取更細粒度的實體,例如類別或結構。
檔案副檔名 | 語言解析器 | 文件 | 實體 |
---|---|---|---|
.java | 爪哇 | ✅ | ✅ |
.swift | 迅速 | ✅ | ✅ |
.c / .h / .hpp | C | ✅ | |
.cpp / .h / .hpp | C++ | ✅ | |
.groovy | 格羅維 | ✅ | ✅ |
.js / .jsx | JavaScript | ✅ | |
.ts / .tsx | 打字稿 | ✅ | |
.k | 科特林 | ✅ | ✅ |
.m / .h | Objective-C | ✅ | |
.rb | 紅寶石 | ✅ | |
.py | Python | ✅ | |
.go | 去 | ✅ |
對此類圖表的解釋通常非常主觀且依賴項目。以下範例應有助於透過指示器和提示識別某些模式。
揭示模組化的魔力在於將社群偵測演算法(例如 Louvain 優化)應用於力導向圖,以便距離和顏色都會影響結果。以下範例包含模組化程式碼庫的多個指標。
在左側的第一個範例中,您可以發現多個相干的彩色簇,它們在一定距離內顯示出低耦合(= 由力導向圖產生)。
在右側的第二個範例中,使用啟動的叢集外殼呈現相同的圖形。在此範例中,船體顯示出很少的重疊或沒有重疊。這些提示可以作為良好軟體架構的指標,例如在模組化、抽象化和定義良好的介面方面。
「一個大泥球結構隨意,蔓延,草率,膠帶和撈線,意大利麵條代碼叢林」(B. Foote,J. Yoder,1997)。這種圖通常代表不太理想的架構。為了驗證這個義大利麵條式的程式碼叢林,只需對所有叢集啟用外殼渲染即可最終確定:畢竟只有一個大叢集。
有時,如果忽略不相關的依賴關係,可以幫助更好地理解軟體架構的複雜性。
ignore_dependencies_containing
(如果您喜歡正規表示式,則使用ignore_dependencies_matching
)配置性地刪除不相關的依賴項。透過相對活化的扇出指標,人們可以識別出更多的散射、一些遙遠的中心節點和更清晰的集群。所有這些都是潛在的真實(=通常更容易理解)架構的線索。