mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-08-10 08:27:25 +00:00
Fix space with bold markdown
This commit is contained in:
@@ -17,3 +17,7 @@ docker-compose.override.yml
|
||||
.vscode/
|
||||
|
||||
.agent/
|
||||
__pycache__/
|
||||
|
||||
# Check scripts
|
||||
check_project_rules.py
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
```bash
|
||||
周五下午 5:00
|
||||
├── 开发者:代码写完了,本地测试通过,提交!🎉
|
||||
├── 周一早上 9:00
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
```bash
|
||||
新同事入职
|
||||
├── Day 1:领电脑,配环境
|
||||
├── Day 2:继续配环境,遇到问题
|
||||
@@ -43,7 +43,7 @@
|
||||
|
||||
具体内容如下:
|
||||
|
||||
```
|
||||
```bash
|
||||
运维:"我们需要把服务迁移到新服务器"
|
||||
开发:"旧服务器上的配置文档在哪?"
|
||||
运维:"当时是一个已经离职的同事配的……"
|
||||
|
||||
@@ -99,7 +99,7 @@ flowchart TD
|
||||
2. 在容器层中进行修改
|
||||
3. 原始镜像层保持不变
|
||||
|
||||
```
|
||||
```bash
|
||||
读取文件:直接从镜像层读取(共享,高效)
|
||||
修改文件:复制到容器层,然后修改(只有这个容器能看到修改)
|
||||
```
|
||||
|
||||
@@ -55,7 +55,7 @@ flowchart TB
|
||||
|
||||
一个完整的 Docker 镜像名称由 Registry 地址、用户名/组织名、仓库名和标签组成。了解其结构有助于我们更准确地定位镜像。基本格式如下:
|
||||
|
||||
```
|
||||
```bash
|
||||
[registry地址/][用户名/]仓库名[:标签]
|
||||
```
|
||||
|
||||
@@ -190,7 +190,7 @@ $ docker pull localhost:5000/myapp:v1.0
|
||||
|
||||
如图 2-3 所示,镜像从开发环境构建后推送到 Registry,再由生产环境拉取并运行。
|
||||
|
||||
```
|
||||
```bash
|
||||
开发者机器 Registry 生产服务器
|
||||
│ │ │
|
||||
│ docker build │ │
|
||||
|
||||
@@ -26,21 +26,21 @@ $ brew install --cask docker
|
||||
|
||||
如同 macOS 其它软件一样,安装也非常简单,双击下载的 `.dmg` 文件,然后将那只叫 [Moby](https://www.docker.com/blog/call-me-moby-dock/) 的鲸鱼图标拖拽到 `Application` 文件夹即可 (其间需要输入用户密码)。
|
||||
|
||||

|
||||

|
||||
|
||||
### 运行
|
||||
|
||||
从应用中找到 Docker 图标并点击运行。
|
||||
|
||||

|
||||

|
||||
|
||||
运行之后,会在右上角菜单栏看到多了一个鲸鱼图标,这个图标表明了 Docker 的运行状态。
|
||||
|
||||

|
||||

|
||||
|
||||
每次点击鲸鱼图标会弹出操作菜单。
|
||||
|
||||

|
||||

|
||||
|
||||
之后,你可以在终端通过命令检查安装后的 Docker 版本。
|
||||
|
||||
@@ -57,7 +57,7 @@ $ docker run -d -p 80:80 --name webserver nginx
|
||||
|
||||
服务运行后,可以访问 [http://localhost](http://localhost),如果看到了 “Welcome to nginx!”,就说明 Docker Desktop for Mac 安装成功了。
|
||||
|
||||

|
||||

|
||||
|
||||
要停止 Nginx 服务器并删除执行下面的命令:
|
||||
|
||||
|
||||
@@ -28,11 +28,11 @@ $ winget install Docker.DockerDesktop
|
||||
|
||||
在 Windows 搜索栏输入 **Docker** 点击 **Docker Desktop** 开始运行。
|
||||
|
||||

|
||||

|
||||
|
||||
Docker 启动之后会在 Windows 任务栏出现鲸鱼图标。
|
||||
|
||||

|
||||

|
||||
|
||||
等待片刻,当鲸鱼图标静止时,说明 Docker 启动成功,之后你可以打开 PowerShell 使用 Docker。
|
||||
|
||||
|
||||
@@ -91,10 +91,6 @@ Kubernetes 社区已将官方镜像地址从 `k8s.gcr.io` 迁移到 `registry.k8
|
||||
一般情况下有如下对应关系:
|
||||
|
||||
```bash
|
||||
## 旧地址(已迁移)
|
||||
## $ docker pull k8s.gcr.io/xxx
|
||||
|
||||
## 新地址(推荐)
|
||||
$ docker pull registry.k8s.io/xxx
|
||||
```
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ docker pull [选项] [Registry地址/]仓库名[:标签]
|
||||
|
||||
Docker 镜像名称由 Registry 地址、用户名、仓库名和标签组成。其标准格式如下:
|
||||
|
||||
```
|
||||
```bash
|
||||
docker.io / library / ubuntu : 24.04
|
||||
────┬──── ───┬─── ──┬─── ──┬──
|
||||
│ │ │ │
|
||||
|
||||
@@ -58,7 +58,7 @@ Docker 镜像的大小可能与我们通常理解的文件大小有所不同,
|
||||
|
||||
由于镜像是分层存储,不同镜像可能共享相同的层:
|
||||
|
||||
```
|
||||
```bash
|
||||
ubuntu:24.04 nginx:latest redis:latest
|
||||
│ │ │
|
||||
└───────┬───────┘ │
|
||||
|
||||
@@ -20,7 +20,7 @@ $ docker run --name webserver -d -p 80:80 nginx
|
||||
|
||||
直接用浏览器访问的话,我们会看到默认的 Nginx 欢迎页面。
|
||||
|
||||

|
||||

|
||||
|
||||
现在,假设我们非常不喜欢这个欢迎页面,我们希望改成欢迎 Docker 的文字,我们可以使用 `docker exec` 命令进入容器,修改其内容。
|
||||
|
||||
@@ -37,7 +37,7 @@ exit
|
||||
|
||||
现在我们再刷新浏览器的话,会发现内容被改变了。
|
||||
|
||||

|
||||

|
||||
|
||||
我们修改了容器的文件,也就是改动了容器的存储层。我们可以通过 `docker diff` 命令看到具体的改动。
|
||||
|
||||
|
||||
@@ -47,7 +47,7 @@ RUN echo "hello" > world.txt # 文件在根目录!
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```dockerfile
|
||||
RUN cd /app
|
||||
↓
|
||||
启动容器 → cd /app(仅内存变化)→ 提交镜像层 → 容器销毁
|
||||
|
||||
@@ -26,7 +26,7 @@ HEALTHCHECK NONE
|
||||
**引入 HEALTHCHECK 后**:
|
||||
Docker 定期执行指定的检查命令,根据返回值判断容器是否 “健康”。
|
||||
|
||||
```
|
||||
```bash
|
||||
容器状态转换:
|
||||
Starting ──成功──> Healthy ──失败N次──> Unhealthy
|
||||
▲ │
|
||||
|
||||
@@ -64,7 +64,7 @@ FROM my-node-base
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
基础镜像构建:
|
||||
Dockerfile (含 ONBUILD) ──build──> 基础镜像 (记录了 ONBUILD 触发器)
|
||||
(指令未执行)
|
||||
@@ -147,7 +147,7 @@ ONBUILD COPY dist/ /usr/share/nginx/html/
|
||||
|
||||
建议在镜像标签中添加 `-onbuild` 后缀,明确告知使用者该镜像包含触发器。
|
||||
|
||||
```
|
||||
```bash
|
||||
node:20-onbuild
|
||||
python:3.12-onbuild
|
||||
```
|
||||
|
||||
@@ -60,7 +60,7 @@ COPY src/ /app/src/
|
||||
|
||||
> ⚠️ **注意**:复制目录时,复制的是目录的 **内容**,不包含目录本身。
|
||||
|
||||
```
|
||||
```bash
|
||||
构建上下文: 镜像内:
|
||||
src/ /app/src/
|
||||
├── index.js → ├── index.js
|
||||
|
||||
@@ -68,7 +68,7 @@ ADD ubuntu-noble-core-cloudimg-amd64-root.tar.gz /
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
ADD app.tar.gz /app/
|
||||
│
|
||||
├─ 识别 .tar.gz 格式
|
||||
|
||||
@@ -109,7 +109,7 @@ $ docker run -it ubuntu # 进入 bash
|
||||
$ docker run ubuntu cat /etc/os-release # 覆盖为 cat 命令
|
||||
```
|
||||
|
||||
```
|
||||
```bash
|
||||
Dockerfile: docker run 命令:
|
||||
CMD ["/bin/bash"] + cat /etc/os-release
|
||||
│ │
|
||||
@@ -138,7 +138,7 @@ CMD service nginx start
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
1. CMD service nginx start
|
||||
↓ 被转换为
|
||||
2. CMD ["sh", "-c", "service nginx start"]
|
||||
|
||||
@@ -141,7 +141,7 @@ HTTP/1.1 200 OK
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
ENTRYPOINT ["curl", "-s", "http://myip.ipip.net"]
|
||||
│
|
||||
docker run myip -i
|
||||
@@ -199,7 +199,7 @@ exec "$@"
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
docker run redis docker run redis bash
|
||||
│ │
|
||||
▼ ▼
|
||||
|
||||
@@ -26,7 +26,7 @@ ARG <参数名>[=<默认值>]
|
||||
| **适用场景** | 构建参数 (版本号等)| 应用配置 |
|
||||
| **可见性** | `docker history` 可见 | `docker inspect` 可见 |
|
||||
|
||||
```
|
||||
```dockerfile
|
||||
构建时 运行时
|
||||
├─ ARG VERSION=1.0 │ (ARG 已消失)
|
||||
├─ ENV APP_ENV=prod │ APP_ENV=prod(仍存在)
|
||||
|
||||
@@ -58,6 +58,7 @@ $ docker run --dns-search=example.com myapp
|
||||
```
|
||||
|
||||
#### 3. --hostname (-h)
|
||||
|
||||
设置容器的主机名。
|
||||
|
||||
```bash
|
||||
|
||||
@@ -324,7 +324,3 @@ services:
|
||||
* `--no-up` 不自动启动服务。
|
||||
|
||||
* `--quiet` 静默模式。
|
||||
|
||||
### 参考资料
|
||||
|
||||
* [官方文档](https://docs.docker.com/compose/reference/overview/)
|
||||
|
||||
@@ -564,8 +564,3 @@ MONGO_VERSION=3.6
|
||||
```
|
||||
|
||||
执行 `docker compose up` 则会启动一个 `mongo:3.6` 镜像的容器。
|
||||
|
||||
### 参考资料
|
||||
|
||||
* [官方文档](https://docs.docker.com/compose/compose-file/)
|
||||
* [awesome-compose](https://github.com/docker/awesome-compose)
|
||||
|
||||
@@ -209,7 +209,7 @@ $ docker compose run --rm web django-admin startproject mysite .
|
||||
|
||||
生成的目录结构:
|
||||
|
||||
```
|
||||
```bash
|
||||
django-docker/
|
||||
├── compose.yaml
|
||||
├── Dockerfile
|
||||
@@ -266,7 +266,7 @@ $ docker compose up
|
||||
2. 启动 db 服务,等待健康检查通过
|
||||
3. 启动 web 服务
|
||||
|
||||
```
|
||||
```bash
|
||||
db-1 | PostgreSQL init process complete; ready for start up.
|
||||
db-1 | LOG: database system is ready to accept connections
|
||||
web-1 | Watching for file changes with StatReloader
|
||||
|
||||
@@ -202,7 +202,7 @@ $ docker compose up
|
||||
|
||||
输出示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
db-1 | PostgreSQL init process complete; ready for start up.
|
||||
db-1 | LOG: database system is ready to accept connections
|
||||
web-1 | => Booting Puma
|
||||
|
||||
@@ -8,7 +8,7 @@ WordPress 是全球最流行的内容管理系统 (CMS)。使用 Docker Compose
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
wordpress/
|
||||
├── compose.yaml
|
||||
├── .env # 环境变量(敏感信息)
|
||||
|
||||
@@ -399,6 +399,7 @@ $ cosign verify --key cosign.pub $IMAGE
|
||||
```
|
||||
|
||||
### 3. SLSA (Supply-chain Levels for Software Artifacts)
|
||||
|
||||
遵循 SLSA 框架,确保构建过程的完整性,例如使用 GitHub Actions 等受控环境进行构建,而非在开发者本地机器上构建发布。
|
||||
|
||||
---
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
`etcdctl` 支持如下的命令,大体上分为数据库操作和非数据库操作两类,后面将分别进行解释。
|
||||
|
||||
```
|
||||
```bash
|
||||
NAME:
|
||||
etcdctl - A simple command line client for etcd3.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[Kubernetes Dashboard](https://github.com/kubernetes/dashboard) 是基于网页的 Kubernetes 用户界面。
|
||||
|
||||

|
||||

|
||||
|
||||
### 部署
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
在 Docker Desktop 设置页面,点击 `Kubernetes`,选择 `Enable Kubernetes`,稍等片刻,看到左下方 `Kubernetes` 变为 `running`,Kubernetes 启动成功。
|
||||
|
||||

|
||||

|
||||
|
||||
> 注意:Kubernetes 的镜像存储在 `registry.k8s.io`,如果国内网络无法直接访问,可以在 Docker Desktop 配置中的 `Docker Engine` 处配置镜像加速器,或者利用国内云服务商的镜像仓库手动拉取镜像并 retag。
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ sudo k3s kubectl get nodes
|
||||
```
|
||||
|
||||
输出类似:
|
||||
```
|
||||
```bash
|
||||
NAME STATUS ROLES AGE VERSION
|
||||
k3s-master Ready control-plane,master 1m v1.35.1+k3s1
|
||||
```
|
||||
|
||||
@@ -22,7 +22,7 @@ $ sudo yum install containerd.io
|
||||
|
||||
新建 `/etc/systemd/system/cri-containerd.service` 文件
|
||||
|
||||
```
|
||||
```bash
|
||||
[Unit]
|
||||
Description=containerd container runtime for kubernetes
|
||||
Documentation=https://containerd.io
|
||||
|
||||
@@ -27,11 +27,11 @@ graph LR
|
||||
|
||||
Docker 的内部架构如同洋葱一样分层,每一层专注解决特定问题:
|
||||
|
||||
#### 1。Docker CLI (客户端)
|
||||
#### 1. Docker CLI (客户端)
|
||||
|
||||
用户与 Docker 交互的主要方式。它将用户命令 (如 `docker run`) 转换为 API 请求发送给 dockerd。
|
||||
|
||||
#### 2。Dockerd (守护进程)
|
||||
#### 2. Dockerd (守护进程)
|
||||
|
||||
Docker 的大脑。
|
||||
|
||||
@@ -39,7 +39,7 @@ Docker 的大脑。
|
||||
- 管理 Docker 对象 (镜像、容器、网络、卷)
|
||||
- 编排下层组件完成工作
|
||||
|
||||
#### 3。Containerd (高级运行时)
|
||||
#### 3. Containerd (高级运行时)
|
||||
|
||||
行业标准的容器运行时 (CNCF 毕业项目)。
|
||||
|
||||
@@ -48,7 +48,7 @@ Docker 的大脑。
|
||||
- **不包含** 复杂的与容器无关的功能 (如构建、API)
|
||||
- Kubernetes 也可以直接使用 containerd (跳过 Docker)
|
||||
|
||||
#### 4。Runc (低级运行时)
|
||||
#### 4. Runc (低级运行时)
|
||||
|
||||
用于创建和运行容器的 CLI 工具。
|
||||
|
||||
@@ -99,9 +99,12 @@ flowchart TD
|
||||
Shim -.-> |8. Monitor IO/Exit| Container
|
||||
```
|
||||
|
||||
1. **CLI** 发送请求给 **Dockerd**2。**Dockerd** 解析请求,调用 **Containerd**3。**Containerd** 准备镜像,转换为 OCI Bundle
|
||||
1. **CLI** 发送请求给 **Dockerd**
|
||||
2. **Dockerd** 解析请求,调用 **Containerd**
|
||||
3. **Containerd** 准备镜像,转换为 OCI Bundle
|
||||
4. **Containerd** 创建 **Shim** 进程
|
||||
5. **Shim** 调用 **Runc**6。**Runc** 与系统内核交互,创建 Namespaces 和 Cgroups
|
||||
5. **Shim** 调用 **Runc**
|
||||
6. **Runc** 与系统内核交互,创建 Namespaces 和 Cgroups
|
||||
7. **Runc** 启动 nginx 进程后退出
|
||||
8. **Shim** 接管容器 IO 和生命周期监控
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ MNT Namespace 负责文件系统挂载点的隔离,确保容器看到独立的
|
||||
|
||||
如下代码块所示,展示了相关示例:
|
||||
|
||||
```
|
||||
```bash
|
||||
宿主机文件系统: 容器内看到的:
|
||||
/ / ← 容器的根目录
|
||||
├── bin/ ├── bin/
|
||||
|
||||
@@ -88,7 +88,7 @@ $ git push origin master
|
||||
|
||||
打开我们部署好的 `Drone` 网站或者 Drone Cloud,即可看到构建结果。
|
||||
|
||||

|
||||

|
||||
|
||||
当然我们也可以把构建结果上传到 GitHub,Docker Registry,云服务商提供的对象存储,或者生产环境中。
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
登录 GitHub,在 https://github.com/settings/applications/new 新建一个应用。
|
||||
|
||||

|
||||

|
||||
|
||||
接下来查看这个应用的详情,记录 `Client ID` 和 `Client Secret`,之后配置 Drone 会用到。
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
1. 图号格式统一为:`图 <章号>-<序号> <图题>`,例如 `图 10-2 Rails + PostgreSQL 的 Compose 架构`。
|
||||
2. 图号在同一章内按出现顺序连续编号,不重复、不跳号。
|
||||
3. 正文引用图片统一写法:`如图 <章号>-<序号> 所示`,不使用 “下图/上图/示意图如下”。
|
||||
4. 所有图片必须提供有意义的 alt 文本,不使用空 alt (``)。
|
||||
4. 所有图片必须提供有意义的 alt 文本,不使用空 alt (``)。
|
||||
5. 图题单独成行,放在图片下方。
|
||||
|
||||
### 章节风格规范
|
||||
|
||||
@@ -124,7 +124,7 @@ $ docker run --network=my-net --ip=172.25.3.3 -itd --name=my-container busybox
|
||||
|
||||
例如,如下操作将默认存储位置迁移到 /storage/docker。
|
||||
|
||||
```
|
||||
```bash
|
||||
[root@s26 ~]# df -h
|
||||
Filesystem Size Used Avail Use% Mounted on
|
||||
/dev/mapper/VolGroup-lv_root 50G 5.3G 42G 12% /
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
[](https://github.com/yeasy/docker_practice) [](https://github.com/yeasy/docker_practice/releases) [](https://docs.docker.com/engine/release-notes/) [][1]
|
||||
[](https://github.com/yeasy/docker_practice) [](https://github.com/yeasy/docker_practice/releases) [](https://docs.docker.com/engine/release-notes/) [][1]
|
||||
|
||||
**v1.5.5**
|
||||
**v1.5.6**
|
||||
|
||||
[Docker](https://www.docker.com) 是个划时代的开源项目,它彻底释放了计算虚拟化的威力,极大提高了应用的维护效率,降低了云计算应用开发的成本!使用 Docker,可以让应用的部署、测试和分发都变得前所未有的高效和轻松!
|
||||
|
||||
@@ -78,7 +78,7 @@ npx honkit serve
|
||||
|
||||
下图直观地展示了本节内容:
|
||||
|
||||
[][1]
|
||||
[][1]
|
||||
|
||||
《[Docker 技术入门与实战][1]》已更新到第 4 版,讲解最新容器技术栈知识,欢迎大家阅读并反馈建议。
|
||||
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
import os
|
||||
import re
|
||||
import argparse
|
||||
|
||||
def check_file(filepath, verbose=False):
|
||||
violations = []
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
lines = content.split('\n')
|
||||
|
||||
filename = os.path.basename(filepath)
|
||||
is_readme = filename.lower() == 'readme.md'
|
||||
is_summary = filename.lower() == 'summary.md'
|
||||
is_section = re.match(r'^\d+\.\d+_.*\.md$', filename)
|
||||
|
||||
# 1.1 Bold Text: No spaces inside the bold markers
|
||||
for i, line in enumerate(lines):
|
||||
if '** ' in line or ' **' in line:
|
||||
# We must be careful: '** ' might be a bold start with space inside, but it could also be regular text.
|
||||
# Let's use a simpler, line-bound regex line by line
|
||||
if re.search(r'\*\*\s+[^*]+\*\*|\*\*[^*]+\s+\*\*', line):
|
||||
violations.append(f"1.1 Bold Text: Space inside bold markers at line {i+1}")
|
||||
|
||||
# 1.4 Trailing Newline
|
||||
if not content.endswith('\n') or content.endswith('\n\n'):
|
||||
if content: # ignore empty files
|
||||
violations.append("1.4 Trailing Newline: File must end with exactly one newline character")
|
||||
|
||||
headers = []
|
||||
for i, line in enumerate(lines):
|
||||
m = re.match(r'^(#{1,6})\s+(.*)', line)
|
||||
if m:
|
||||
level = len(m.group(1))
|
||||
text = m.group(2)
|
||||
headers.append({'line': i, 'level': level, 'text': text})
|
||||
|
||||
# 1.2 Header Spacing
|
||||
if i + 1 < len(lines):
|
||||
next_line = lines[i+1].strip()
|
||||
if next_line != '':
|
||||
violations.append(f"1.2 Header Spacing: Header at line {i+1} not followed by a blank line")
|
||||
if i + 2 < len(lines):
|
||||
if lines[i+1].strip() == '' and lines[i+2].strip() == '':
|
||||
violations.append(f"1.2 Header Spacing: Header at line {i+1} followed by multiple blank lines")
|
||||
|
||||
# 1.3 Header Hierarchy
|
||||
for j in range(len(headers) - 1):
|
||||
curr_level = headers[j]['level']
|
||||
next_level = headers[j+1]['level']
|
||||
if next_level > curr_level + 1:
|
||||
violations.append(f"1.3 Header Hierarchy: Skipped header level from H{curr_level} to H{next_level} at line {headers[j+1]['line']+1}")
|
||||
|
||||
# 2.2 File Header Levels
|
||||
if headers:
|
||||
first_header_level = headers[0]['level']
|
||||
if is_readme and first_header_level != 1:
|
||||
violations.append("2.2 File Header Levels: README.md first header must be level 1")
|
||||
if is_summary and first_header_level != 2:
|
||||
violations.append("2.2 File Header Levels: SUMMARY.md first header must be level 2")
|
||||
if is_section and first_header_level != 2:
|
||||
violations.append("2.2 File Header Levels: Section file first header must be level 2")
|
||||
|
||||
# 2.2 No English Parentheses in Headers unless very common terminologies
|
||||
for h in headers:
|
||||
text = h['text']
|
||||
i = h['line']
|
||||
if re.search(r'([A-Za-z\s]+)', text):
|
||||
violations.append(f"2.2 No English Parentheses: Header at line {i+1} contains English in parentheses: {text}")
|
||||
|
||||
# 2.3 Single Child Headers
|
||||
for j in range(len(headers)):
|
||||
level = headers[j]['level']
|
||||
children = 0
|
||||
for k in range(j+1, len(headers)):
|
||||
if headers[k]['level'] <= level:
|
||||
break
|
||||
if headers[k]['level'] == level + 1:
|
||||
children += 1
|
||||
if children == 1:
|
||||
violations.append(f"2.3 Single Child Headers: Header at line {headers[j]['line']+1} has exactly 1 child")
|
||||
|
||||
# 2.5 Bridge Text
|
||||
for j in range(len(headers)):
|
||||
level = headers[j]['level']
|
||||
child_line = -1
|
||||
for k in range(j+1, len(headers)):
|
||||
if headers[k]['level'] <= level:
|
||||
break
|
||||
if headers[k]['level'] == level + 1:
|
||||
child_line = headers[k]['line']
|
||||
break
|
||||
if child_line != -1:
|
||||
text_between = '\n'.join([l.strip() for l in lines[headers[j]['line']+1:child_line] if l.strip()])
|
||||
if not text_between:
|
||||
violations.append(f"2.5 Bridge Text: Header at line {headers[j]['line']+1} is followed by a sub-header without introductory text")
|
||||
|
||||
# 3.2 Content Introduction
|
||||
in_code_block = False
|
||||
for j, line in enumerate(lines):
|
||||
if line.startswith('```'):
|
||||
if not in_code_block:
|
||||
for k in range(j-1, -1, -1):
|
||||
if lines[k].strip():
|
||||
if lines[k].startswith('#'):
|
||||
violations.append(f"3.2 Content Introduction: Code block at line {j+1} immediately follows a header")
|
||||
break
|
||||
in_code_block = not in_code_block
|
||||
elif ":
|
||||
if lines[k].strip():
|
||||
if lines[k].startswith('#'):
|
||||
violations.append(f"3.2 Content Introduction: Image at line {j+1} immediately follows a header")
|
||||
break
|
||||
|
||||
return violations
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('-v', '--verbose', action='store_true')
|
||||
args = parser.parse_args()
|
||||
|
||||
md_files = []
|
||||
for root, dirs, files in os.walk('.'):
|
||||
for f in files:
|
||||
if f.endswith('.md') and '.git' not in root and 'node_modules' not in root and '.vuepress' not in root and 'book_rule.md' not in f and 'rules_result.txt' not in f:
|
||||
md_files.append(os.path.join(root, f))
|
||||
|
||||
total_violations = 0
|
||||
for f in md_files:
|
||||
try:
|
||||
violations = check_file(f, args.verbose)
|
||||
if args.verbose:
|
||||
print(f"Scanned {f}")
|
||||
if violations:
|
||||
print(f"\\nViolations in {f}:")
|
||||
for v in violations:
|
||||
print(f" - {v}")
|
||||
total_violations += len(violations)
|
||||
except Exception as e:
|
||||
print(f"Error reading {f}: {e}")
|
||||
|
||||
if total_violations == 0:
|
||||
print("No violations found!")
|
||||
else:
|
||||
print(f"\\nTotal violations: {total_violations}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1 +0,0 @@
|
||||
Total issues found: 0
|
||||
Reference in New Issue
Block a user