已合并
基于 devcontainer 的 MindStudio 统一开发环境方案 #429
基于 devcontainer 的 MindStudio 统一开发环境方案 #429
已合并
Zhang-Yu001创建于 8月3日
9 个文件变更+391-5
A.clangd+2-0
@@ -0,0 +1,2 @@
1+CompileFlags:
2+ CompilationDatabase: build/
@@ -0,0 +1,56 @@
1+{
2+ "name": "msserviceprofiler-devcontainer",
3+ "image": "swr.cn-north-4.myhuaweicloud.com/mindstudio-image/mindstudio-build:26.1.0-0701",
4+ "workspaceFolder": "/workspace",
5+ "workspaceMount": "source=${localWorkspaceFolder},target=/workspace,type=bind",
6+ "remoteUser": "mindstudio",
7+ "updateRemoteUserUID": true,
8+ "runArgs": [
9+ "--network=host",
10+ "--privileged",
11+ "--ipc=host",
12+ "--ulimit=nproc=65535:65535",
13+ "--security-opt=seccomp=unconfined"
14+ ],
15+ "mounts": [
16+ "source=/usr/local/sbin,target=/usr/local/sbin,type=bind,ro"
17+ ],
18+ "containerEnv": {
19+ "GCC11_NO_RPATH": "1",
20+ "NPM_CONFIG_PREFIX": "/home/mindstudio/.local"
21+ },
22+ "remoteEnv": {
23+ "PATH": "/home/mindstudio/.local/bin:${containerEnv:PATH}"
24+ },
25+ "postCreateCommand": "bash /workspace/.devcontainer/post-create.sh",
26+ "customizations": {
27+ "vscode": {
28+ "extensions": [
29+ "ms-vscode.cpptools",
30+ "ms-vscode.cmake-tools",
31+ "ms-python.python",
32+ "ms-python.vscode-pylance",
33+ "charliermarsh.ruff",
34+ "llvm-vs-code-extensions.vscode-clangd",
35+ "llvm-vs-code-extensions.vscode-clang-format",
36+ "bierner.markdown-preview-github-styles"
37+ ],
38+ "settings": {
39+ "terminal.integrated.profiles.linux": {
40+ "bash": {
41+ "path": "bash",
42+ "args": ["-l"]
43+ }
44+ },
45+ "terminal.integrated.defaultProfile.linux": "bash",
46+ "C_Cpp.intelliSenseEngine": "disabled",
47+ "clangd.serverArgs": [
48+ "--query-driver=*",
49+ "--header-insertion=iwyu",
50+ "--completion-style=detailed"
51+ ],
52+ "clangd.pathToCompdb": "build"
53+ }
54+ }
55+ }
56+}
@@ -0,0 +1,221 @@
1+#!/bin/bash
L
Lleo9203208月4日

【review】增加下版权信息,参照其他shell脚本下的内容

likedislike
2+# -*- coding: utf-8 -*-
3+# -------------------------------------------------------------------------
4+# This file is part of the MindStudio project.
5+# Copyright (c) 2026 Huawei Technologies Co.,Ltd.
6+#
7+# MindStudio is licensed under Mulan PSL v2.
8+# You can use this software according to the terms and conditions of the Mulan PSL v2.
9+# You may obtain a copy of Mulan PSL v2 at:
10+#
11+# http://license.coscl.org.cn/MulanPSL2
12+#
13+# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
14+# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
15+# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
16+# See the Mulan PSL v2 for more details.
17+# -------------------------------------------------------------------------
18+ 
19+log() { echo "[post-create] $*"; }
20+warn() { echo "[post-create] WARN: $*"; }
21+ 
22+configure_user_bin() {
23+ log "Configuring user bin directory..."
24+ mkdir -p "$HOME/.local/bin"
25+ npm config set prefix "$HOME/.local" 2>/dev/null || warn "npm config set prefix failed"
26+ local marker="# msserviceprofiler-devcontainer-user-bin"
27+ for rcfile in "$HOME/.bashrc" "$HOME/.bash_profile"; do
28+ if [ -f "$rcfile" ] && ! grep -qF "$marker" "$rcfile"; then
29+ cat >> "$rcfile" <<EOF
30+$marker
31+export PATH="\$HOME/.local/bin:\$PATH"
32+EOF
33+ log "Appended PATH to $rcfile"
34+ fi
35+ done
36+}
37+ 
38+configure_python3() {
39+ log "Configuring Python 3..."
40+ if [ -f "/etc/profile.d/pyenv.sh" ]; then
41+ source /etc/profile.d/pyenv.sh 2>/dev/null || warn "Failed to source pyenv.sh"
42+ log "Loaded pyenv profile"
43+ fi
44+ for candidate in /opt/python/cp*-cp*; do
45+ if [ -d "$candidate/bin" ] && [ -x "$candidate/bin/python3" ]; then
46+ local marker="# msserviceprofiler-pyenv-python"
47+ for rcfile in "$HOME/.bashrc" "$HOME/.bash_profile"; do
48+ if [ -f "$rcfile" ] && ! grep -qF "$marker" "$rcfile"; then
49+ cat >> "$rcfile" <<EOF
50+$marker
51+export PATH="$candidate/bin:\$PATH"
52+EOF
53+ log "Prepended pyenv Python to PATH in $rcfile"
54+ fi
55+ done
56+ export PATH="$candidate/bin:$PATH"
57+ break
58+ fi
59+ done
60+ if command -v python3 &>/dev/null; then
61+ log "Python 3 found: $(python3 --version 2>&1)"
62+ else
63+ warn "python3 not found in PATH"
64+ fi
65+}
66+ 
67+install_build_deps() {
68+ log "Installing build dependencies..."
69+ if command -v dnf &>/dev/null; then
70+ for pkg in python3-devel; do
71+ if ! rpm -q "$pkg" &>/dev/null; then
72+ log " Installing: $pkg"
73+ sudo dnf install -y "$pkg" 2>/dev/null || warn "dnf install failed: $pkg"
74+ else
75+ log " System pkg OK: $pkg"
76+ fi
77+ done
78+ elif command -v apt-get &>/dev/null; then
79+ for pkg in python3-dev; do
80+ if ! dpkg -s "$pkg" &>/dev/null; then
81+ log " Installing: $pkg"
82+ sudo apt-get update -qq && sudo apt-get install -y "$pkg" 2>/dev/null || warn "apt-get install failed: $pkg"
83+ else
84+ log " System pkg OK: $pkg"
85+ fi
86+ done
87+ fi
88+ 
89+ if ! command -v gitleaks &>/dev/null; then
90+ log " Installing gitleaks..."
91+ GITLEAKS_VER="8.18.4"
92+ case "$(uname -m)" in
93+ x86_64) GITLEAKS_ARCH="amd64";;
94+ aarch64) GITLEAKS_ARCH="arm64";;
95+ *) warn "Unsupported architecture, skipping gitleaks";;
96+ esac
97+ if [ -n "$GITLEAKS_ARCH" ]; then
98+ GITLEAKS_INSTALLED=false
99+ for MIRROR in \
100+ "https://ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VER}/gitleaks_${GITLEAKS_VER}_linux_${GITLEAKS_ARCH}.tar.gz" \
101+ "https://mirror.ghproxy.com/https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VER}/gitleaks_${GITLEAKS_VER}_linux_${GITLEAKS_ARCH}.tar.gz" \
102+ "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VER}/gitleaks_${GITLEAKS_VER}_linux_${GITLEAKS_ARCH}.tar.gz"; do
103+ log " Trying: ${MIRROR}"
104+ curl -fsSL "${MIRROR}" -o /tmp/gitleaks.tar.gz --connect-timeout 10 2>/dev/null && \
105+ sudo tar -xzf /tmp/gitleaks.tar.gz -C /usr/local/bin gitleaks 2>/dev/null && \
106+ GITLEAKS_INSTALLED=true && break
107+ rm -f /tmp/gitleaks.tar.gz
108+ done
109+ if ${GITLEAKS_INSTALLED}; then
110+ sudo chmod +x /usr/local/bin/gitleaks
111+ log " gitleaks ${GITLEAKS_VER} (${GITLEAKS_ARCH}) installed"
112+ else
113+ log " Download mirrors unreachable, trying pip install gitleaks..."
114+ python3 -m pip install gitleaks 2>/dev/null && log " gitleaks installed via pip" || \
115+ warn "gitleaks install failed (pre-commit gitleaks will be skipped)"
116+ fi
117+ fi
118+ else
119+ log " System pkg OK: gitleaks"
120+ fi
121+ 
122+ local pip_pkgs=(wheel pre-commit "bandit[toml]")
123+ for PY in $(command -v python3 2>/dev/null) $(command -v python 2>/dev/null); do
124+ log "Installing pip packages for: $($PY --version 2>&1)"
125+ "$PY" -m pip install --quiet --upgrade pip setuptools >/dev/null 2>&1 || warn "pip/setuptools upgrade failed for $PY"
126+ for pkg in "${pip_pkgs[@]}"; do
127+ local pkg_name="${pkg%%[*}"
128+ if ! "$PY" -m pip show "$pkg_name" &>/dev/null; then
129+ log " Installing for $PY: $pkg"
130+ "$PY" -m pip install "$pkg" || warn "pip install failed for $PY: $pkg"
131+ else
132+ log " Pip pkg OK ($PY): $pkg"
133+ fi
134+ done
135+ done
136+ log "Build dependencies check complete"
137+}
138+ 
139+sync_git_identity() {
140+ log "Syncing Git identity..."
141+ local gitconfig="$HOME/.devcontainer-host-gitconfig"
142+ if [ -f "$gitconfig" ] && [ -s "$gitconfig" ]; then
143+ local name email
144+ name=$(git config --file "$gitconfig" --get user.name 2>/dev/null) || true
145+ email=$(git config --file "$gitconfig" --get user.email 2>/dev/null) || true
146+ [ -n "$name" ] && git config --global user.name "$name"
147+ [ -n "$email" ] && git config --global user.email "$email"
148+ log "Git identity synced from host"
149+ else
150+ warn "No host Git config found, skipping identity sync"
151+ fi
152+}
153+ 
154+append_dev_hint_once() {
155+ local marker="# msserviceprofiler-dev-hint"
156+ local rcfile="$HOME/.bashrc"
157+ if grep -qF "$marker" "$rcfile" 2>/dev/null; then return; fi
158+ cat >> "$rcfile" <<EOF
159+$marker
160+# msserviceprofiler development commands:
161+# python3 build.py Build Release (full)
162+# python3 build.py local Build Release (skip deps)
163+# python3 build.py test Build and run unit tests
164+EOF
165+ log "Appended dev hints to $rcfile"
166+}
167+ 
168+install_pre_commit_hook() {
169+ log "Installing pre-commit hook..."
170+ export PATH="$HOME/.local/bin:$PATH"
171+ local pre_commit_cmd=""
172+ if command -v pre-commit &>/dev/null; then
173+ pre_commit_cmd="pre-commit"
174+ elif python3 -m pre_commit --version &>/dev/null 2>&1; then
175+ pre_commit_cmd="python3 -m pre_commit"
176+ elif python -m pre_commit --version &>/dev/null 2>&1; then
177+ pre_commit_cmd="python -m pre_commit"
178+ else
179+ warn "pre-commit not found, skipping hook installation"
180+ return
181+ fi
182+ if ! git rev-parse --git-dir &>/dev/null; then
183+ warn "Not a Git repository, skipping pre-commit hook"
184+ return
185+ fi
186+ $pre_commit_cmd install || warn "pre-commit install failed"
187+ log "pre-commit hook installed via: $pre_commit_cmd"
188+}
189+ 
190+setup_clangd() {
191+ log "Setting up clangd..."
192+ if command -v clangd &>/dev/null; then
193+ log "clangd found: $(clangd --version 2>&1 | head -1)"
194+ return
195+ fi
196+ warn "clangd not found, attempting to install..."
197+ if command -v dnf &>/dev/null; then
198+ sudo dnf install -y clangd 2>/dev/null || sudo dnf install -y clang-tools-extra 2>/dev/null || warn "Failed to install clangd via dnf"
199+ elif command -v apt-get &>/dev/null; then
200+ sudo apt-get update -qq && sudo apt-get install -y clangd 2>/dev/null || warn "Failed to install clangd via apt-get"
201+ fi
202+}
203+ 
204+ignore_local_changes() {
205+ log "Setting up skip-worktree for local-modifiable files..."
206+ if [ -f ".vscode/settings.json" ]; then
207+ git update-index --skip-worktree .vscode/settings.json 2>/dev/null || true
208+ log " skip-worktree: .vscode/settings.json"
209+ fi
210+}
211+ 
212+log "Starting container initialization (msserviceprofiler)..."
213+configure_user_bin
214+configure_python3
215+install_build_deps
216+sync_git_identity
217+append_dev_hint_once
218+install_pre_commit_hook
219+setup_clangd
220+ignore_local_changes
221+log "Container initialization complete!"
@@ -1,6 +1,6 @@
1**/__pycache__1**/__pycache__
2*.pyc2*.pyc
3-.vscode3+.vscode/settings.json
4.idea4.idea
5build5build
6test/.coverage6test/.coverage
@@ -15,3 +15,12 @@ cmake-build-debug
153rdparty/opentelemetry/include/opentelemetry/153rdparty/opentelemetry/include/opentelemetry/
163rdparty/protobuf/163rdparty/protobuf/
17 17 
18+# Build artifacts
19+/artifacts/
20+/output/
21+ 
22+# Cache
23+.ruff_cache/
24+ 
25+# Devcontainer
26+.devcontainer/.host-gitconfig
@@ -62,6 +62,7 @@ repos:
62 - id: bandit62 - id: bandit
63 name: bandit (Python 安全漏洞检查)63 name: bandit (Python 安全漏洞检查)
64 types: [python]64 types: [python]
65+ additional_dependencies: ["bandit[toml]"]
65 args: [66 args: [
66 "--config=pre-commit/pyproject.toml",67 "--config=pre-commit/pyproject.toml",
67 "--quiet",68 "--quiet",
@@ -91,7 +92,7 @@ repos:
91 hooks:92 hooks:
92 - id: gitleaks-offline-scan93 - id: gitleaks-offline-scan
93 name: Gitleaks Secret Scan(Local Binary)94 name: Gitleaks Secret Scan(Local Binary)
94- entry: ./gitleaks95+ entry: gitleaks
95 language: system96 language: system
96 pass_filenames: true97 pass_filenames: true
97 exclude: ^\.pre-commit-config\.yaml$98 exclude: ^\.pre-commit-config\.yaml$
@@ -0,0 +1,30 @@
1+{
2+ "version": "0.2.0",
3+ "configurations": [
4+ {
5+ "name": "Python: Debug Active File",
6+ "type": "debugpy",
7+ "request": "launch",
8+ "program": "${file}",
9+ "console": "integratedTerminal",
10+ "justMyCode": false,
11+ "env": {
12+ "PYTHONPATH": "${workspaceFolder}:${env:PYTHONPATH}",
13+ "LD_LIBRARY_PATH": "${workspaceFolder}/build/cpp:${env:LD_LIBRARY_PATH}"
14+ }
15+ },
16+ {
17+ "name": "Python: Pytest Case Debugging",
18+ "type": "debugpy",
19+ "request": "launch",
20+ "module": "pytest",
21+ "args": ["${file}", "-v"],
22+ "console": "integratedTerminal",
23+ "justMyCode": false,
24+ "env": {
25+ "PYTHONPATH": "${workspaceFolder}:${env:PYTHONPATH}",
26+ "LD_LIBRARY_PATH": "${workspaceFolder}/build/cpp:${env:LD_LIBRARY_PATH}"
27+ }
28+ }
29+ ]
30+}
@@ -0,0 +1,59 @@
1+{
2+ "version": "2.0.0",
3+ "tasks": [
4+ {
5+ "label": "Build: Release Mode",
6+ "type": "shell",
7+ "command": "python3 build.py local",
8+ "group": {
9+ "kind": "build",
10+ "isDefault": true
11+ },
12+ "presentation": {
13+ "reveal": "always",
14+ "panel": "dedicated"
15+ },
16+ "problemMatcher": []
17+ },
18+ {
19+ "label": "Build: Debug Mode",
20+ "type": "shell",
21+ "command": "python3 build.py -e only_down_deps=true && cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -Dms_service_profiler_BUILD_TESTS=OFF && make -C build -j$(nproc)",
22+ "group": {
23+ "kind": "build"
24+ },
25+ "presentation": {
26+ "reveal": "always",
27+ "panel": "dedicated"
28+ },
29+ "problemMatcher": []
30+ },
31+ {
32+ "label": "Test: Run Unit Tests",
33+ "type": "shell",
34+ "command": "python3 build.py test local",
35+ "group": {
36+ "kind": "test",
37+ "isDefault": true
38+ },
39+ "presentation": {
40+ "reveal": "always",
41+ "panel": "dedicated"
42+ },
43+ "problemMatcher": []
44+ },
45+ {
46+ "label": "Clean: All Workspace",
47+ "type": "shell",
48+ "command": "find build -depth -type d -name CMakeFiles -exec rm -rf {} + ; find build -depth -type f -name cmake_install.cmake -delete ; rm -rf build output artifacts *.egg-info __pycache__ .pytest_cache .mypy_cache",
49+ "options": {
50+ "cwd": "${workspaceFolder}"
51+ },
52+ "presentation": {
53+ "reveal": "always",
54+ "panel": "dedicated"
55+ },
56+ "problemMatcher": []
57+ }
58+ ]
59+}
@@ -4,6 +4,7 @@ project(ms_service_profiler VERSION 8.5.0 LANGUAGES CXX C)
4 4 
5set(CMAKE_CXX_STANDARD 14)5set(CMAKE_CXX_STANDARD 14)
6set(CMAKE_CXX_STANDARD_REQUIRED True)6set(CMAKE_CXX_STANDARD_REQUIRED True)
7+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
7set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")8set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_GLIBCXX_USE_CXX11_ABI=0")
8 9 
9set(THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty")10set(THIRD_PARTY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty")
@@ -15,7 +16,7 @@ find_package(Python3 COMPONENTS Interpreter REQUIRED)
15message(STATUS "Checking for conflicting package 'msserviceprofiler'...")16message(STATUS "Checking for conflicting package 'msserviceprofiler'...")
16 17 
17execute_process(18execute_process(
18- COMMAND ${Python3_EXECUTABLE} -c "import msserviceprofiler" 19+ COMMAND ${Python3_EXECUTABLE} -c "import msserviceprofiler"
19 RESULT_VARIABLE CHECK_RESULT20 RESULT_VARIABLE CHECK_RESULT
20 OUTPUT_QUIET21 OUTPUT_QUIET
21 ERROR_QUIET22 ERROR_QUIET
@@ -135,11 +135,18 @@ class BuildManager:
135 self._run_tests()135 self._run_tests()
136 else:136 else:
137 # -------------------- 产品构建 --------------------137 # -------------------- 产品构建 --------------------
138- 
139- # 在非 local 场景下按需更新依赖;在 local 场景下仅使用本地已有代码,不更新依赖。
140 if 'local' not in self.args.command:138 if 'local' not in self.args.command:
141 self._execute_command(["bash", "scripts/download_thirdparty.sh"])139 self._execute_command(["bash", "scripts/download_thirdparty.sh"])
142 140 
141+ # only_down_deps 在依赖下载后、构建前检查
142+ extra_options = {}
143+ for opt in self.args.extra:
144+ key, _, val = opt.partition('=')
145+ extra_options[key] = val
146+ if extra_options.get('only_down_deps') == 'true':
147+ logging.info("only_down_deps=true, exiting after dependency download.")
148+ return
149+ 
143 logging.info("--version: %s", self.args.version)150 logging.info("--version: %s", self.args.version)
144 for opt in self.args.extra:151 for opt in self.args.extra:
145 key, _, val = opt.partition('=')152 key, _, val = opt.partition('=')