diff --git a/.github/workflows/bsp_buildings.yml b/.github/workflows/bsp_buildings.yml index aef4f9c9e5..f4c7fdf76b 100644 --- a/.github/workflows/bsp_buildings.yml +++ b/.github/workflows/bsp_buildings.yml @@ -41,66 +41,29 @@ permissions: jobs: generate-matrix: runs-on: ubuntu-22.04 + name: 🔍 Summary of Git Diff Changes outputs: filtered_matrix: ${{ steps.filter.outputs.filtered_matrix }} steps: - name: Checkout repo uses: actions/checkout@main with: - sparse-checkout: .github/ALL_BSP_COMPILE.json persist-credentials: false - - name: Read matrix config - id: read-config - run: | - #读取ALL_BSP_COMPILE.json文件 - raw_matrix_base64=$(cat .github/ALL_BSP_COMPILE.json |egrep -v '^//'|base64 -w 0) - echo "raw_matrix=$raw_matrix_base64" >> $GITHUB_OUTPUT - - name: Get changed files - id: changed_files - if: github.event_name == 'pull_request' - run: | - changed_files=$(curl -s \ - "https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files" | \ - jq -r '.[].filename') - prefix=$(echo "$changed_files" | cut -d'/' -f1 | sort -u ) - has_bsp=true - for r in "$prefix"; do - if [[ ! "$r" == "bsp" ]]; then - has_bsp=false - break - fi - done - if [[ $has_bsp == true ]]; then - changed_files=$(echo "${changed_files}"| cut -d'/' -f2 | sort -u| tr '\n' ',' | sed 's/,$//') - echo "CHANGED_FILES=[${changed_files}]" >> $GITHUB_OUTPUT - fi - #获取修改文件的路径,如果有bsp以外的文件夹则编译全部bsp,否则获取对应文件夹名 - - echo "${changed_files}" + fetch-depth: 0 - name: Filter matrix id: filter run: | - raw_matrix=$(echo "${{ steps.read-config.outputs.raw_matrix }}" | base64 --decode) - - CHANGED_FILES=${{ steps.changed_files.outputs.CHANGED_FILES }} - CHANGED_FILES=$(echo "$CHANGED_FILES" | sed 's/\[\|\]//g') - # 将修改的文件路径与ALL_BSP_COMPILE.json文件的SUB_RTT_BSP进行判断,判断是否包含 - filtered_matrix=[] - echo "${CHANGED_FILES}" - if [[ -z "$CHANGED_FILES" ]]; then - FILTER_CONDITION='.legs[]' - filtered_matrix=$(jq -c "{legs: [$FILTER_CONDITION]}" <<< "$raw_matrix") - else - CONDITIONS=$(echo "$CHANGED_FILES" | awk 'BEGIN { RS="," } { printf "contains(\"%s\") or ", $1 }') - CONDITIONS=${CONDITIONS% or } - - FILTER_CONDITION=".legs[] | select(any(.SUB_RTT_BSP[]; $CONDITIONS))" - - filtered_matrix=$(jq -c "{legs: [$FILTER_CONDITION]}" <<< "$raw_matrix") - fi + git config --global http.postBuffer 524288000 + git remote -v + git fetch origin + git branch + git branch -a + python tools/ci/git_diff_show.py origin/master + raw_matrix=$(cat .github/ALL_BSP_COMPILE_TEMP.json) + FILTER_CONDITION='.legs[]' + filtered_matrix=$(jq -c "{legs: [$FILTER_CONDITION]}" <<< "$raw_matrix") echo "filtered_matrix=${filtered_matrix}" >> $GITHUB_OUTPUT - echo ${filtered_matrix} build: runs-on: ubuntu-22.04 diff --git a/.github/workflows/git_diff_status_show.yml b/.github/workflows/git_diff_status_show.yml deleted file mode 100644 index f63cafed26..0000000000 --- a/.github/workflows/git_diff_status_show.yml +++ /dev/null @@ -1,50 +0,0 @@ -# -# Copyright (c) 2006-2023, RT-Thread Development Team -# -# SPDX-License-Identifier: Apache-2.0 -# -# Change Logs: -# Date Author Notes -# 2025-05-15 Supper Thomas show the PR size -# - -name: PR status - -# 这个ci主要用来显示当前的PR对于master节点上的增加的code size有多大 -on: - pull_request: - branches: - - master - -permissions: - contents: read # to fetch code (actions/checkout) - -jobs: - build: - runs-on: ubuntu-24.04 - name: PR status show - - steps: - - uses: actions/checkout@main - with: - fetch-depth: 0 - - name: Set up Python - uses: actions/setup-python@main - with: - python-version: 3.8 - - - name: fetch origin - shell: bash - run: | - git config --global http.postBuffer 524288000 - git remote -v - git fetch origin - git branch - git branch -a - - - name: PR status show - if: ${{ success() }} - shell: bash - run: | - python tools/ci/git_diff_status_show.py origin/master - diff --git a/tools/ci/git_diff_show.py b/tools/ci/git_diff_show.py new file mode 100644 index 0000000000..435823c702 --- /dev/null +++ b/tools/ci/git_diff_show.py @@ -0,0 +1,372 @@ +# +# Copyright (c) 2025, RT-Thread Development Team +# +# SPDX-License-Identifier: Apache-2.0 +# +# Change Logs: +# Date Author Notes +# 2025-05-15 supperthomas add PR status show +# 2025-05-22 hydevcode 替换bsp_building.yml的判断文件修改机制,并将PR status show合并进bsp_building.yml +import subprocess +import sys +import os +import re +import argparse +import locale +from typing import List, Dict + +import json +from typing import List +class FileDiff: + def __init__(self, path: str, status: str, size_change: int = 0, old_size: int = 0, new_size: int = 0): + self.path = path + self.status = status # A (added), M (modified), D (deleted), R (renamed) + self.size_change = size_change + self.old_size = old_size + self.new_size = new_size + + def __str__(self): + if self.status == 'A': + return f"Added {self.path}: {self.size_change} bytes" + elif self.status == 'D': + return f"Deleted {self.path}: was {self.old_size} bytes" + elif self.status == 'M' or self.status == 'R': + return f"Modified {self.path}: {self.size_change} bytes change" + else: + return f"{self.status} {self.path}" + +class GitDiffAnalyzer: + def __init__(self, target_branch: str): + self.target_branch = target_branch + self.encoding = locale.getpreferredencoding() + + def get_diff_files(self) -> List[FileDiff]: + """获取当前分支与目标分支之间的差异文件""" + # 找到当前分支和目标分支的最近共同祖先 + merge_base = self.get_merge_base() + if not merge_base: + print("No common ancestor found between current branch and target branch") + sys.exit(1) + + # 获取差异文件列表 + diff_cmd = f"git diff --name-status {merge_base} HEAD" + print(diff_cmd) + try: + output = subprocess.check_output(diff_cmd.split(), stderr=subprocess.STDOUT) + output = output.decode(self.encoding).strip() + print(output) + except subprocess.CalledProcessError as e: + print(f"Error executing git diff: {e.output.decode(self.encoding)}") + sys.exit(1) + + if not output: + print("No differences between current branch and target branch") + sys.exit(0) + + # 处理可能的换行符问题 + output = output.replace('\r\n', '\n') + lines = output.split('\n') + + file_diffs = [] + for line in lines: + line = line.strip() + if not line: + continue + + parts = line.split('\t') + if len(parts) < 2: + # 可能是重命名文件,格式为 "RXXX\told_path\tnew_path" + match = re.match(r'R(\d+)\t(.+)\t(.+)', line) + if match: + status = 'R' + old_path = match.group(2) + new_path = match.group(3) + # 计算重命名文件的修改大小 + old_size = self.get_file_size(old_path, self.target_branch) + new_size = self.get_file_size(new_path, 'HEAD') + size_change = new_size - old_size if old_size > 0 else new_size + file_diffs.append(FileDiff(new_path, status, size_change, old_size, new_size)) + else: + status = parts[0][0] # 取状态码的第一个字符 + path = parts[1] + + if status == 'A': + # 新增文件,计算大小 + size = self.get_file_size(path, 'HEAD') + file_diffs.append(FileDiff(path, status, size, 0, size)) + elif status == 'D': + # 删除文件,计算原大小 + size = self.get_file_size(path, self.target_branch) + file_diffs.append(FileDiff(path, status, 0, size, 0)) + elif status == 'M': + # 修改文件,计算大小变化 + old_size = self.get_file_size(path, self.target_branch) + new_size = self.get_file_size(path, 'HEAD') + size_change = new_size - old_size + file_diffs.append(FileDiff(path, status, size_change, old_size, new_size)) + + return file_diffs + + def get_merge_base(self) -> str: + """获取当前分支和目标分支的最近共同祖先""" + try: + cmd = f"git merge-base {self.target_branch} HEAD" + print(cmd) + output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) + return output.decode(self.encoding).strip() + except subprocess.CalledProcessError as e: + print(f"Error executing git merge-base: {e.output.decode(self.encoding)}") + return None + + def get_file_size(self, path: str, ref: str) -> int: + """获取指定分支上文件的大小""" + try: + # 使用 git cat-file 来获取文件内容,然后计算其大小 + cmd = f"git cat-file blob {ref}:{path}" + output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) + return len(output) + except subprocess.CalledProcessError: + # 如果文件不存在或无法获取,返回0 + return 0 + +def format_size(size: int) -> str: + """将字节大小转换为人类可读的格式""" + if size >= 0: + if size < 1024: + return f"{size} bytes" + elif size < 1024 * 1024: + return f"{size / 1024:.1f} KB" + elif size < 1024 * 1024 * 1024: + return f"{size / (1024 * 1024):.1f} MB" + else: + return f"{size / (1024 * 1024 * 1024):.1f} GB" + else: + temp_size=abs(size) + if temp_size < 1024: + return f"-{temp_size} bytes" + elif temp_size < 1024 * 1024: + return f"-{temp_size / 1024:.1f} KB" + elif temp_size < 1024 * 1024 * 1024: + return f"-{temp_size / (1024 * 1024):.1f} MB" + else: + return f"-{temp_size / (1024 * 1024 * 1024):.1f} GB" + +def is_bsp(path): + return os.path.isfile(os.path.join(path, "rtconfig.h")) + +def filter_bsp_config(file_diffs: List[FileDiff], config_path: str): + # 读取原始JSON配置 + with open(config_path, 'r', encoding='utf-8') as f: + config = json.load(f) + + # 获取所有修改的文件路径(统一使用Linux风格路径) + modified_paths = [diff.path.replace('\\', '/') for diff in file_diffs] + print(modified_paths) + if not modified_paths: + print("master分支运行") + return + + bsp_paths = set() + bsp_in_but_not_bsp_paths = set() + all_print_paths = set() + for modified_path in modified_paths: + parts = modified_path.strip(os.sep).split('/') + if not parts: + continue + first_level = parts[0] + first_level_path = os.path.join(os.getcwd(), first_level) + + #处理bsp路径的逻辑 + if first_level == "bsp": + temp_path=os.path.join(os.getcwd(), modified_path) + # 判断是否是文件 + if not os.path.isdir(modified_path): + temp_path = os.path.dirname(temp_path) + + #循环搜索每一级是否有rtconfig.h + while temp_path !=first_level_path: + if is_bsp(temp_path): + bsp_paths.add(temp_path) + + break + temp_path=os.path.dirname(temp_path) + + if temp_path ==first_level_path: + bsp_in_but_not_bsp_paths.add(parts[1]) + + else: + #非bsp路径逻辑 + all_print_paths.add(first_level_path) + + # 变成相对路径 + bsp_list = set() + for path in sorted(bsp_paths): + current_working_dir = os.path.join(os.getcwd(), "bsp/") + if path.startswith(current_working_dir): + bsp_list.add(path[len(current_working_dir):].lstrip(os.sep)) + else: + bsp_list.add(path) # 如果 first_level_path 不以 current_working_dir 开头,则保持不变 + + # 处理修改了bsp外的文件的情况 + filtered_bsp = [ + path for path in bsp_list + if path.split('/')[0] not in bsp_in_but_not_bsp_paths + ] + + merged_result = filtered_bsp + list(bsp_in_but_not_bsp_paths) + + filtered_legs = [] + for leg in config["legs"]: + matched_paths = [ + path for path in leg.get("SUB_RTT_BSP", []) + if any(keyword in path for keyword in merged_result) + ] + if matched_paths: + filtered_legs.append({**leg, "SUB_RTT_BSP": matched_paths}) + + # 生成新的配置 + new_config = {"legs": filtered_legs} + + # 判断有没有修改到bsp外的文件,有的话则编译全部 + if not all_print_paths: + print(new_config) + file_name = ".github/ALL_BSP_COMPILE_TEMP.json" + + # 将 new_config 写入文件 + with open(file_name, "w", encoding="utf-8") as file: + json.dump(new_config, file, ensure_ascii=False, indent=4) + + +def main(): + # 源文件路径 + source_file = ".github/ALL_BSP_COMPILE.json" # 替换为你的文件路径 + + # 目标文件路径 + target_file = ".github/ALL_BSP_COMPILE_TEMP.json" # 替换为你的目标文件路径 + + # 读取源文件并过滤掉带有 // 的行 + with open(source_file, "r", encoding="utf-8") as infile, open(target_file, "w", encoding="utf-8") as outfile: + for line in infile: + if not line.lstrip().startswith("//"): + outfile.write(line) + + parser = argparse.ArgumentParser(description='Compare current branch with target branch and show file differences.') + parser.add_argument('target_branch', help='Target branch to compare against (e.g., master)') + args = parser.parse_args() + + analyzer = GitDiffAnalyzer(args.target_branch) + file_diffs = analyzer.get_diff_files() + + # 生成报告 + generate_report(file_diffs, args.target_branch) + + filter_bsp_config(file_diffs,".github/ALL_BSP_COMPILE_TEMP.json") + + +def add_summary(text): + """ + add summary to github action. + """ + if "GITHUB_STEP_SUMMARY" in os.environ: + summary_path = os.environ["GITHUB_STEP_SUMMARY"] # 获取摘要文件路径 + + # 将 text 写入摘要文件(追加模式) + with open(summary_path, "a") as f: # "a" 表示追加模式 + f.write(text + "\n") # 写入文本并换行 + else: + print("Environment variable $GITHUB_STEP_SUMMARY is not set.") + +def summarize_diff(label, count, size=None): + """格式化输出变更摘要""" + line = f" {label:<12} {count:>3} files" + if size is not None: + line += f" ({format_size(size)})" + add_summary(line) + +def generate_report(file_diffs: List[FileDiff], target_branch: str): + """生成差异报告""" + + add_summary(f"# 📊 **Comparison between {target_branch} and Current Branch**\n") + + # 分类统计 + added_files = [f for f in file_diffs if f.status.startswith('A')] + removed_files = [f for f in file_diffs if f.status.startswith('D')] + modified_files = [f for f in file_diffs if f.status.startswith('M')] + renamed_files = [f for f in file_diffs if f.status.startswith('R')] + copied_files = [f for f in file_diffs if f.status.startswith('C')] + unmerged_files = [f for f in file_diffs if f.status.startswith('U')] + type_changed_files = [f for f in file_diffs if f.status.startswith('T')] + + # 计算总变化量 + total_added = sum(f.size_change for f in added_files) + total_removed = sum(f.old_size for f in removed_files) + total_modified = sum(f.size_change for f in modified_files) + total_copied = sum(f.size_change for f in copied_files) + total_renamed = sum(f.old_size for f in renamed_files) + total_type_changed = sum(f.size_change for f in type_changed_files) + + total_size_change = sum(f.size_change for f in file_diffs) + # === 汇总输出 === + summarize_diff("Total:", len(file_diffs)) + summarize_diff("Added:", len(added_files), total_added) + summarize_diff("Removed:", len(removed_files), total_removed) + summarize_diff("Modified:", len(modified_files), total_modified) + summarize_diff("Renamed:", len(renamed_files), total_renamed) + summarize_diff("Copied:", len(copied_files), total_copied) + summarize_diff("Type Changed:", len(type_changed_files), total_type_changed) + summarize_diff("Unmerged:", len(unmerged_files)) + + + if total_size_change > 0: + change_desc = f"📈 **Increase of {format_size(total_size_change)}**" + elif total_size_change < 0: + change_desc = f"📉 **Reduction of {format_size(abs(total_size_change))}**" + else: + change_desc = "➖ **No net size change**" + + add_summary(f"\n### 📦 **Total Size Change:** {change_desc} (Excluding removed files)") + + + # 显示详细差异文件内容 + add_summary("\n## 📂 **Detailed File Changes**\n") + + for diff in file_diffs: + add_summary(f"📄 {diff.path} — **[{diff.status}]**") + + # 文件状态处理 + if diff.status.startswith('A'): + add_summary(f"📦 Size: {format_size(diff.new_size)}") + + elif diff.status.startswith(('M', 'R')): # 修改或重命名 + add_summary(f"📏 Original size: {format_size(diff.old_size)}") + add_summary(f"📐 New size: {format_size(diff.new_size)}") + + delta = diff.size_change + if delta > 0: + change_str = f"📈 Increased by {format_size(delta)}" + elif delta < 0: + change_str = f"📉 Reduced by {format_size(abs(delta))}" + else: + change_str = "➖ No size change" + + add_summary(f"📊 Size change: {change_str}") + + elif diff.status.startswith('D'): + add_summary(f"🗑️ Original size: {format_size(diff.old_size)}") + + elif diff.status.startswith('C'): + add_summary(f"📎 Copied from size: {format_size(diff.old_size)} → {format_size(diff.new_size)}") + + elif diff.status.startswith('T'): + add_summary("⚙️ File type changed") + + elif diff.status.startswith('U'): + add_summary("⚠️ Unmerged conflict detected") + + else: + add_summary("❓ Unknown change type") + + add_summary("\n\n") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/tools/ci/git_diff_status_show.py b/tools/ci/git_diff_status_show.py deleted file mode 100644 index 128964ff24..0000000000 --- a/tools/ci/git_diff_status_show.py +++ /dev/null @@ -1,201 +0,0 @@ -# -# Copyright (c) 2025, RT-Thread Development Team -# -# SPDX-License-Identifier: Apache-2.0 -# -# Change Logs: -# Date Author Notes -# 2025-05-15 supperthomas add PR status show -# -#!/usr/bin/env python3 -import subprocess -import sys -import os -import re -import argparse -import locale -from typing import List, Dict - -class FileDiff: - def __init__(self, path: str, status: str, size_change: int = 0, old_size: int = 0, new_size: int = 0): - self.path = path - self.status = status # A (added), M (modified), D (deleted), R (renamed) - self.size_change = size_change - self.old_size = old_size - self.new_size = new_size - - def __str__(self): - if self.status == 'A': - return f"Added {self.path}: {self.size_change} bytes" - elif self.status == 'D': - return f"Deleted {self.path}: was {self.old_size} bytes" - elif self.status == 'M' or self.status == 'R': - return f"Modified {self.path}: {self.size_change} bytes change" - else: - return f"{self.status} {self.path}" - -class GitDiffAnalyzer: - def __init__(self, target_branch: str): - self.target_branch = target_branch - self.encoding = locale.getpreferredencoding() - - def get_diff_files(self) -> List[FileDiff]: - """获取当前分支与目标分支之间的差异文件""" - # 找到当前分支和目标分支的最近共同祖先 - merge_base = self.get_merge_base() - if not merge_base: - print("No common ancestor found between current branch and target branch") - sys.exit(1) - - # 获取差异文件列表 - diff_cmd = f"git diff --name-status {merge_base} " - print(diff_cmd) - try: - output = subprocess.check_output(diff_cmd.split(), stderr=subprocess.STDOUT) - output = output.decode(self.encoding).strip() - print(output) - except subprocess.CalledProcessError as e: - print(f"Error executing git diff: {e.output.decode(self.encoding)}") - sys.exit(1) - - if not output: - print("No differences between current branch and target branch") - sys.exit(0) - - # 处理可能的换行符问题 - output = output.replace('\r\n', '\n') - lines = output.split('\n') - - file_diffs = [] - for line in lines: - line = line.strip() - if not line: - continue - - parts = line.split('\t') - if len(parts) < 2: - # 可能是重命名文件,格式为 "RXXX\told_path\tnew_path" - match = re.match(r'R(\d+)\t(.+)\t(.+)', line) - if match: - status = 'R' - old_path = match.group(2) - new_path = match.group(3) - # 计算重命名文件的修改大小 - old_size = self.get_file_size(old_path, self.target_branch) - new_size = self.get_file_size(new_path, 'HEAD') - size_change = new_size - old_size if old_size > 0 else new_size - file_diffs.append(FileDiff(new_path, status, size_change, old_size, new_size)) - else: - status = parts[0][0] # 取状态码的第一个字符 - path = parts[1] - - if status == 'A': - # 新增文件,计算大小 - size = self.get_file_size(path, 'HEAD') - file_diffs.append(FileDiff(path, status, size, 0, size)) - elif status == 'D': - # 删除文件,计算原大小 - size = self.get_file_size(path, self.target_branch) - file_diffs.append(FileDiff(path, status, 0, size, 0)) - elif status == 'M': - # 修改文件,计算大小变化 - old_size = self.get_file_size(path, self.target_branch) - new_size = self.get_file_size(path, 'HEAD') - size_change = new_size - old_size - file_diffs.append(FileDiff(path, status, size_change, old_size, new_size)) - - return file_diffs - - def get_merge_base(self) -> str: - """获取当前分支和目标分支的最近共同祖先""" - try: - cmd = f"git merge-base {self.target_branch} HEAD" - print(cmd) - output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) - return output.decode(self.encoding).strip() - except subprocess.CalledProcessError as e: - print(f"Error executing git merge-base: {e.output.decode(self.encoding)}") - return None - - def get_file_size(self, path: str, ref: str) -> int: - """获取指定分支上文件的大小""" - try: - # 使用 git cat-file 来获取文件内容,然后计算其大小 - cmd = f"git cat-file blob {ref}:{path}" - output = subprocess.check_output(cmd.split(), stderr=subprocess.STDOUT) - return len(output) - except subprocess.CalledProcessError: - # 如果文件不存在或无法获取,返回0 - return 0 - -def format_size(size: int) -> str: - """将字节大小转换为人类可读的格式""" - if size < 1024: - return f"{size} bytes" - elif size < 1024 * 1024: - return f"{size / 1024:.1f} KB" - elif size < 1024 * 1024 * 1024: - return f"{size / (1024 * 1024):.1f} MB" - else: - return f"{size / (1024 * 1024 * 1024):.1f} GB" - -def main(): - parser = argparse.ArgumentParser(description='Compare current branch with target branch and show file differences.') - parser.add_argument('target_branch', help='Target branch to compare against (e.g., master)') - args = parser.parse_args() - - analyzer = GitDiffAnalyzer(args.target_branch) - file_diffs = analyzer.get_diff_files() - - # 生成报告 - generate_report(file_diffs, args.target_branch) - - - -def generate_report(file_diffs: List[FileDiff], target_branch: str): - """生成差异报告""" - print(f"\n=== Comparison between {target_branch} and current branch ===\n") - - # 分类统计 - added_files = [f for f in file_diffs if f.status == 'A'] - removed_files = [f for f in file_diffs if f.status == 'D'] - modified_files = [f for f in file_diffs if f.status == 'M'] - renamed_files = [f for f in file_diffs if f.status == 'R'] - - # 计算总变化量 - total_added = sum(f.size_change for f in added_files) - total_removed = sum(f.old_size for f in removed_files) - total_modified = sum(abs(f.size_change) for f in modified_files) - # 计算总的大小变化 - total_size_change = sum(f.size_change for f in file_diffs) - - print(f"Total changes: {len(file_diffs)} files") - print(f"Added: {len(added_files)} files ({format_size(total_added)})") - print(f"Removed: {len(removed_files)} files ({format_size(total_removed)})") - print(f"Modified: {len(modified_files)} files ({format_size(total_modified)})") - print(f"Renamed: {len(renamed_files)} files") - print(f"\nTotal size change: {format_size(total_size_change)}") - print("\n" + "="*60 + "\n") - - # 显示详细差异 - for diff in file_diffs: - print(diff) - - # 详细展示修改和新增的文件大小 - if diff.status == 'A': - print(f" Size: {format_size(diff.new_size)}") - elif diff.status == 'M': - print(f" Original size: {format_size(diff.old_size)}") - print(f" New size: {format_size(diff.new_size)}") - print(f" Size change: {format_size(abs(diff.size_change))}") - elif diff.status == 'R': - print(f" Original size: {format_size(diff.old_size)}") - print(f" New size: {format_size(diff.new_size)}") - print(f" Size change: {format_size(abs(diff.size_change))}") - elif diff.status == 'D': - print(f" Original size: {format_size(diff.old_size)}") - - print("-" * 50) - -if __name__ == "__main__": - main() \ No newline at end of file