Skip to content

Commit 1898203

Browse files
committed
Merge branch 'feature/tools' of https://github.com/yalechen-cyw/CodeAnalysis into feature/tools
2 parents 860b0bb + ded73d1 commit 1898203

740 files changed

Lines changed: 13657 additions & 28556 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
File renamed without changes.

README.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@
1010

1111
English | [简体中文](README_ZH.md)
1212

13+
## TCA Official Website
14+
15+
[https://cloud.tencent.com/product/tcap](https://cloud.tencent.com/product/tcap)
16+
1317
## TCA Github Pages
1418

1519
[https://tencent.github.io/CodeAnalysis/](https://tencent.github.io/CodeAnalysis/)
@@ -45,12 +49,9 @@ Using TCA can help team find normative, structural, security vulnerabilities and
4549

4650
## Getting Started
4751

48-
- [How to get start](https://tencent.github.io/CodeAnalysis/)
52+
- [How to deploy](https://tencent.github.io/CodeAnalysis/en/quickStarted/)
4953
- [How to use TCA Action](https://github.com/TCATools/TCA-action/blob/main/README.md)
50-
- [How to deploy server and web](https://tencent.github.io/CodeAnalysis/zh/quickStarted/deploySever.html#通过源代码)
51-
- [How to deploy server and web with docker-compose](https://tencent.github.io/CodeAnalysis/zh/quickStarted/deploySever.html#通过docker-compose)
52-
- [How to use client](https://tencent.github.io/CodeAnalysis/zh/quickStarted/deployClient.html)
53-
- [Deploy Q&A](https://tencent.github.io/CodeAnalysis/zh/quickStarted/FAQ.html)
54+
- [How to use client](https://tencent.github.io/CodeAnalysis/en/guide/客户端/本地分析.html)
5455

5556
## Community
5657

README_ZH.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,17 @@
88

99
[![license](https://img.shields.io/badge/License-MIT-brightgreen.svg?style=flat)](LICENSE) [![docs](https://img.shields.io/badge/docs-read-brightgreen.svg?style=flat)](https://tencent.github.io/CodeAnalysis/)
1010

11-
## TCA Github Pages
11+
## TCA-官方网址
12+
13+
[https://cloud.tencent.com/product/tcap](https://cloud.tencent.com/product/tcap)
14+
15+
## TCA-Github代码库
1216

1317
[https://tencent.github.io/CodeAnalysis/](https://tencent.github.io/CodeAnalysis/)
1418

1519
[https://github.com/TCATools](https://github.com/TCATools)
1620

17-
## 工蜂代码库镜像
21+
## TCA-国内镜像工蜂代码库
1822

1923
[https://git.code.tencent.com/Tencent_Open_Source/CodeAnalysis.git](https://git.code.tencent.com/Tencent_Open_Source/CodeAnalysis.git)
2024

@@ -43,12 +47,9 @@
4347

4448
## 快速入门
4549

46-
- [快速入门](https://tencent.github.io/CodeAnalysis/)
50+
- [快速部署](https://tencent.github.io/CodeAnalysis/zh/quickStarted/)
4751
- [如何使用TCA Action快速体验](https://github.com/TCATools/TCA-action/blob/main/README.md)
48-
- [如何在本地部署Server与Web](https://tencent.github.io/CodeAnalysis/zh/quickStarted/deploySever.html#通过源代码)
49-
- [如何通过Docker-Compose部署Server与Web](https://tencent.github.io/CodeAnalysis/zh/quickStarted/deploySever.html#通过docker-compose)
50-
- [如何使用客户端](https://tencent.github.io/CodeAnalysis/zh/quickStarted/deployClient.html)
51-
- [部署常见问题与解决方式](https://tencent.github.io/CodeAnalysis/zh/quickStarted/FAQ.html)
52+
- [如何使用客户端](https://tencent.github.io/CodeAnalysis/zh/guide/客户端/本地分析.html)
5253

5354
## 社区
5455

client/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM python:3.7.12-slim
22

3-
ARG EXTRA_TOOLS="curl wget python3-dev git git-lfs vim-tiny gcc locales subversion telnet procps"
3+
ARG EXTRA_TOOLS="curl wget python3-dev git git-lfs vim-tiny gcc locales subversion telnet procps openssh-client"
44

55
RUN apt-get update \
66
&& apt-get install -y --no-install-recommends $EXTRA_TOOLS \

client/node/common/taskdirmgr.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def acquire_task_dir(self, task_id=None, dirname_prefix="task_"):
4040
suffix_no += 1
4141
task_dir = os.path.join(self._task_dirs_root, f"{dirname_prefix}{task_id}_{suffix_no}")
4242
else: # 没有传task_id,根据本地task dir名称排序,创建一个新的
43-
task_id = 0
43+
task_id = 1
4444
while True:
4545
if not os.path.exists(os.path.join(self._task_dirs_root, f"{dirname_prefix}{task_id}")):
4646
break

client/node/localtask/runlocaltask.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ def scan_project(self, execute_request_list, proj_conf):
7575
if execute_request_list and not self._remote_task_names:
7676
if self._source_dir:
7777
task_request = copy.deepcopy(execute_request_list[0]) # 深度copy,以免影响原字典数据
78+
task_request["task_name"] = "linecount"
7879
RequestModify.modify_local_task_request(task_request, self._task_name_id_maps, self._job_id,
7980
self._scm_auth_info.ssh_file,
8081
self._token, self._server_url, self._source_dir, self._scm_info,

client/node/servertask/looprunner.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,6 +193,8 @@ def run(self):
193193
kill_task_id = task_params['task_id']
194194
# kill task时进程如果已不存在,会报异常: ProcessLookupError: [Errno 3] No such process
195195
self._terminate_task(kill_task_id)
196+
# 等待一段时间后再接下一个任务
197+
time.sleep(self._get_task_interval)
196198
continue
197199

198200
# 获取到分析任务,向server发送确认信息(kill_task不需要确认)
@@ -229,6 +231,8 @@ def run(self):
229231
task = Task(task_id, task_name, request_file, response_file, task_log, env=self._origin_os_env)
230232
task.start()
231233
self._running_task.append(task)
234+
# 等待一段时间后再接下一个任务
235+
time.sleep(self._get_task_interval)
232236
except:
233237
# 遇到异常,输出异常信息
234238
LogPrinter.exception("task loop encounter error.")
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# -*- encoding: utf-8 -*-
2+
# Copyright (c) 2022 THL A29 Limited
3+
#
4+
# This source code file is made available under MIT License
5+
# See LICENSE for details
6+
# ==============================================================================
7+
8+
"""
9+
通过http方式拉取工具
10+
"""
11+
12+
import os
13+
14+
from util.logutil import LogPrinter
15+
from util.api.fileserver import RetryFileServer
16+
from util.exceptions import FileServerError
17+
from util.pathlib import PathMgr
18+
from util.zipmgr import Zip
19+
20+
21+
class HttpToolLoader(object):
22+
"""通过http方式拉取工具,如果目录已存在,不拉取"""
23+
@staticmethod
24+
def download_tool(tool_url, dest_dir):
25+
if os.path.exists(dest_dir):
26+
# 工具目录存在时,直接复用,不重新拉取(如需更新,先删除工具目录)
27+
LogPrinter.debug(f"tool dir({os.path.basename(dest_dir)}) from zip can be reused.")
28+
return
29+
30+
tool_root_dir = os.path.dirname(dest_dir)
31+
if not os.path.exists(tool_root_dir): # 如果上层目录不存在,先创建
32+
os.makedirs(tool_root_dir)
33+
zip_file_name = tool_url.split('/')[-1]
34+
dest_zip_file_path = os.path.join(tool_root_dir, zip_file_name)
35+
36+
file_server = RetryFileServer(retry_times=2).get_server(server_url=tool_url)
37+
file_server.download_big_file("", dest_zip_file_path)
38+
39+
if os.path.exists(dest_zip_file_path):
40+
LogPrinter.debug(f"download {tool_url} to {dest_zip_file_path}")
41+
# 使用7z解压
42+
Zip().decompress_by_7z(dest_zip_file_path, tool_root_dir)
43+
LogPrinter.debug(f"unzip {dest_zip_file_path} to {dest_dir}")
44+
PathMgr().safe_rmpath(dest_zip_file_path)
45+
else:
46+
raise FileServerError(f"download {tool_url} failed!")
47+
48+
49+
if __name__ == '__main__':
50+
pass

client/node/toolloader/loadconfig.py

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,8 @@ def __update_tool_names(self, tool_names, task_list):
161161
tool_names.remove(c_name)
162162
return tool_names
163163

164-
def read_tool_config_from_ini_file(self, tool_names=None, custom_tools=None, task_list=None, config_all_tools=False, include_common=True):
164+
def read_tool_config_from_ini_file(self, tool_names=None, custom_tools=None, task_list=None, config_all_tools=False,
165+
include_common=True):
165166
"""
166167
从ini文件中读取工具配置
167168
"""
@@ -194,6 +195,7 @@ def read_tool_config_from_ini_file(self, tool_names=None, custom_tools=None, tas
194195
"env_path": env_path_section, # env_path_section中现在已经没有key为"PATH"的元素,可以作为编译工具的env_path
195196
"env_value": env_value_section
196197
}
198+
self.__format_to_fullpath(compile_config)
197199
config_dict["compile_config"] = compile_config
198200
return config_dict
199201
else:
@@ -236,6 +238,25 @@ def __format_config(self, tool_cfg, env_path_section, env_value_section):
236238
tool_cfg["env_value"] = self.__str_to_dict(tool_cfg["env_value"], env_value_section)
237239
tool_cfg["tool_url"] = self.__str_to_list(tool_cfg["tool_url"])
238240
tool_cfg["path"] = self.__str_to_list(tool_cfg["path"], uniq=False)
241+
self.__format_to_fullpath(tool_cfg)
242+
243+
def __format_to_fullpath(self, tool_cfg):
244+
# 将路径类型的环境变量(env_path)中的相对路径转换成绝对路径
245+
for env_name, rel_path in tool_cfg["env_path"].items():
246+
if "PATH" == env_name: # PATH应该单独放在path字段中,如果放在env_path中,忽略,避免影响和覆盖原有PATH变量
247+
continue
248+
full_path = os.path.join(settings.TOOL_BASE_DIR, rel_path)
249+
tool_cfg["env_path"][env_name] = full_path
250+
251+
# 将PATH环境变量的相对路径转换成绝对路径
252+
path_env = []
253+
for rel_path in tool_cfg["path"]:
254+
if "$" in rel_path or "%" in rel_path: # 带变量的环境变量,已经是全路径
255+
full_path = rel_path
256+
else:
257+
full_path = os.path.join(settings.TOOL_BASE_DIR, rel_path)
258+
path_env.append(full_path)
259+
tool_cfg["path"] = path_env
239260

240261
def read_config_from_tool_schemes(self, tool_names=None, task_list=None):
241262
"""
@@ -266,7 +287,7 @@ def read_config_from_tool_schemes(self, tool_names=None, task_list=None):
266287
config_dict = {}
267288
already_config_tools = [] # 记录已经读取到配置的工具
268289
for task_config in task_list:
269-
task_name = task_config["task_name"]
290+
task_name = task_config.get("task_name")
270291
if tool_names and task_name not in tool_names:
271292
continue
272293
task_params = task_config.get("task_params", {})
@@ -282,29 +303,41 @@ def read_config_from_tool_schemes(self, tool_names=None, task_list=None):
282303
for tool_lib in tool_libs:
283304
lib_support_os = tool_lib.get("os", [])
284305
if self._os_type in lib_support_os:
306+
# 使用新的结构存储环境变量,避免修改原有的任务参数
307+
new_lib_envs = {}
285308
lib_envs = tool_lib.get("envs", {})
286309
if not lib_envs: # 可能会传空list,这里判空,避免后面格式出错
287-
lib_envs = {}
310+
new_lib_envs = {}
311+
288312
scm_url = tool_lib.get("scm_url")
289-
lib_dir_name = scm_url.split('/')[-1].strip().replace(".git", "")
290-
# 环境变量中的$ROOT_DIR替换为目录名,后续加载环境变量时会拼接为全路径
313+
# 支持git仓库地址和zip包地址两种格式
314+
lib_dir_name = BaseScmUrlMgr.get_last_dir_name_from_url(scm_url)
315+
lib_dir_path = os.path.join(settings.TOOL_BASE_DIR, lib_dir_name)
316+
317+
# 将环境变量中的$ROOT_DIR替换为实际路径,重新保存到new_lib_envs
291318
for key, value in lib_envs.items():
292319
if "$ROOT_DIR" in value:
293-
lib_envs[key] = value.replace("$ROOT_DIR", lib_dir_name)
320+
new_lib_envs[key] = value.replace("$ROOT_DIR", lib_dir_path)
321+
else:
322+
new_lib_envs[key] = value
323+
294324
# PATH和其他环境变量分开处理
295325
path_envs = []
296326
other_envs = {}
297-
for env_name, env_value in lib_envs.items():
327+
for env_name, env_value in new_lib_envs.items():
298328
if env_name == "PATH":
299329
path_envs = self.__str_to_list(env_value)
300330
else:
301-
other_envs[env_name] = env_value
331+
# 根据英文分号拆分后,再环境变量分隔符拼接到一起
332+
value_list = self.__str_to_list(env_value)
333+
value_format = os.pathsep.join(value_list)
334+
other_envs[env_name] = value_format
302335
lib_config = {
303336
"tool_url": scm_url,
304337
"scm_type": tool_lib.get("scm_type"),
305338
"auth_info": tool_lib.get("auth_info"),
306339
"path": path_envs,
307-
"env_path": lib_envs,
340+
"env_path": other_envs,
308341
"env_value": {}
309342
}
310343
lib_name = tool_lib.get("name")

client/node/toolloader/loadtool.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,25 @@
1818
from node.app import settings
1919
from node.toolloader.gitload import GitLoader
2020
from node.toolloader.loadconfig import ConfigLoader, ToolConfig, LoadToolTypes
21+
from node.toolloader.httploadtool import HttpToolLoader
2122
from util.envset import EnvSet
2223
from util.scanlang.callback_queue import CallbackQueue
2324
from util.pathlib import PathMgr
2425
from util.logutil import LogPrinter
2526
from util.scmurlmgr import BaseScmUrlMgr
2627
from util.subprocc import SubProcController
28+
from util.textutil import ZIP_EXT
2729

2830

2931
class ToolCommonLoader(object):
3032
@staticmethod
33+
def is_zip_url(tool_url):
34+
"""判断是否是压缩包地址"""
35+
if tool_url.lower().endswith(ZIP_EXT):
36+
return True
37+
else:
38+
return False
39+
@staticmethod
3140
def load_tool_type(tool_dirpath, tool_dirname, tool_url=None):
3241
"""
3342
判断使用哪种方式加载工具
@@ -38,8 +47,10 @@ def load_tool_type(tool_dirpath, tool_dirname, tool_url=None):
3847
"""
3948
if settings.USE_LOCAL_TOOL == "True":
4049
if os.path.exists(tool_dirpath):
41-
# LogPrinter.info(f"USE_LOCAL_TOOL=True, use local tool dir: {tool_dirpath}")
50+
LogPrinter.info(f"USE_LOCAL_TOOL=True, use local tool dir: {tool_dirpath}")
4251
return "Local", None
52+
elif tool_url and ToolCommonLoader.is_zip_url(tool_url):
53+
return "HTTP", None
4354
else:
4455
return "Git", None
4556
else:
@@ -54,6 +65,8 @@ def load_tool_type(tool_dirpath, tool_dirname, tool_url=None):
5465
return "Copy", tool_dirpath_copy_from
5566
else: # 拷贝源目录不存在,从git拉取
5667
return "Git", None
68+
elif tool_url and ToolCommonLoader.is_zip_url(tool_url):
69+
return "HTTP", None
5770
else:
5871
return "Git", None
5972

@@ -69,6 +82,8 @@ def load_tool(load_type, tool_dirpath, tool_dirpath_copy_from, git_url, scm_auth
6982
:param print_enable:
7083
:return:
7184
"""
85+
if settings.DEBUG:
86+
print_enable = True
7287
if load_type == "Local":
7388
if print_enable:
7489
LogPrinter.info(f"Use local tool dir: {tool_dirpath}")
@@ -78,6 +93,11 @@ def load_tool(load_type, tool_dirpath, tool_dirpath_copy_from, git_url, scm_auth
7893
LogPrinter.info(f"Copy from {tool_dirpath_copy_from} to {tool_dirpath}")
7994
PathMgr().retry_copy(tool_dirpath_copy_from, tool_dirpath)
8095
return tool_dirpath
96+
elif load_type == "HTTP":
97+
if print_enable:
98+
LogPrinter.info(f"Load from {git_url} to {tool_dirpath}")
99+
HttpToolLoader.download_tool(git_url, tool_dirpath)
100+
return tool_dirpath
81101
else:
82102
if print_enable:
83103
LogPrinter.info(f"Load from git to {tool_dirpath} ...")

0 commit comments

Comments
 (0)