当前位置: 首页 > news >正文

p4 大小写检查

P4 服务器存储文件的路径不一致

背景:p4服务器没有开启文件大小写 + Windows 磁盘上不路径大小写

使用p4 where 本地磁盘目录, 获取Depot中的目录, workspace中的目录,本地磁盘中存储的目录

得到Depot中的目录

//depot/Game/Content/Textures/.png
//depot/Game/Content/textures/T.png

而在P4V中或者控制台中使用p4 dirs 即p4 dirs //depot/Game/Content/* 看到的是:

//depot/Game/Content/Textures

因此,这里遍历本地磁盘中文件,查找本地文件在P4中的Depot中的位置,用P4 dirs 获取Depot中最开始存储的文件夹, 这样就能比较出哪些文件被记录在Depot中文件路径是错误的。

以下是python代码

ChatGPT给的方案

from P4 import P4, P4Exception
import osdef get_actual_case_on_disk(path):"""Given a path, returns the actual case of each part as found on disk.On Windows, this is necessary to detect case mismatches.Returns None if the path does not exist."""if not os.path.exists(path):return Nonedrive, rest = os.path.splitdrive(os.path.abspath(path))parts = rest.strip(os.sep).split(os.sep)actual_parts = []current = drive + os.sep if drive else os.sepfor part in parts:try:entries = os.listdir(current)except PermissionError:return Nonefor entry in entries:if entry.lower() == part.lower():actual_parts.append(entry)current = os.path.join(current, entry)breakelse:return Nonereturn actual_partsdef main():p4 = P4()try:p4.connect()depot_root = '//depot'# Recursively get all directoriesall_dirs = []stack = [depot_root]while stack:curr = stack.pop()try:subdirs = p4.run('dirs', f'{curr}/*')for d in subdirs:all_dirs.append(d)stack.append(d)except P4Exception:pass  # no subdirsprint("Checking case consistency between depot and local filesystem:")for depot_dir in all_dirs:# Map depot dir to local pathtry:where = p4.run('where', depot_dir)if where and 'path' in where[0]:local_path = where[0]['path']else:print(f"Cannot map depot dir: {depot_dir}")continueexcept P4Exception:print(f"Error mapping: {depot_dir}")continueactual_parts = get_actual_case_on_disk(local_path)if actual_parts is None:print(f"Local path missing: {local_path} (for depot {depot_dir})")continueexpected_parts = os.path.normpath(local_path).split(os.sep)depot_parts = depot_dir.lstrip('/').split('/')[1:]  # remove leading //depot# Compare only last N parts (to match depot dir depth)n = len(depot_parts)compare_expected = expected_parts[-n:]compare_actual = actual_parts[-n:]for exp, act, dep in zip(compare_expected, compare_actual, depot_parts):if exp != act:print(f"Case mismatch: depot '{dep}' vs local '{act}' in {local_path}")except P4Exception as e:print("Perforce error:", e)finally:p4.disconnect()if __name__ == "__main__":main()

Deep Seek给的代码

from P4 import P4, P4Exception
import osdef list_dirs_recursive(p4, depot_path, all_dirs):try:subdirs = p4.run('dirs', f'{depot_path}/*')for d in subdirs:all_dirs.append(d)list_dirs_recursive(p4, d, all_dirs)except P4Exception:passdef main():p4 = P4()output_file = "p4_depot_structure.txt"  # 输出文件名try:p4.connect()root = '//depot'all_dirs = []list_dirs_recursive(p4, root, all_dirs)# 确保输出目录存在os.makedirs(os.path.dirname(output_file), exist_ok=True)with open(output_file, 'w', encoding='utf-8') as f:# 写入目录结构f.write("Folders on depot:\n")for d in all_dirs:f.write(f"{d}\n")# 写入文件列表f.write("\nFiles under each folder:\n")for depot_dir in all_dirs:try:# 获取本地映射路径where_result = p4.run('where', depot_dir)if not where_result:continuelocal_path = where_result[0].get('path', '')if not local_path or not os.path.exists(local_path):continue# 获取工作区根路径以正确转换路径client_root = p4.fetch_client()['Root'].replace('\\', '/')if not client_root.endswith('/'):client_root += '/'# 遍历本地文件系统for root_dir, _, files in os.walk(local_path):for file in files:full_path = os.path.join(root_dir, file)# 将本地路径转换为depot路径# 方法:移除工作区根路径,添加depot根路径rel_path = os.path.relpath(full_path, p4.fetch_client()['Root'])depot_path = f"//{p4.client}/{rel_path.replace(os.sep, '/')}"f.write(f"{depot_path}\n")except (P4Exception, OSError) as e:f.write(f"\n[Error] Skipping {depot_dir}: {str(e)}\n")continueprint(f"成功生成仓库结构报告: {os.path.abspath(output_file)}")except P4Exception as e:print("Perforce error:", e)finally:p4.disconnect()if __name__ == "__main__":main()
http://www.lryc.cn/news/586833.html

相关文章:

  • Rust赋能文心大模型4.5智能开发
  • QCustomPlot绘图保存成PDF文件
  • 软考中级学习系列-- 阶码与尾数
  • 香港服务器Python自动化巡检脚本开发与邮件告警集成
  • 详解Linux下多进程与多线程通信(一)
  • Leetcode 3615. Longest Palindromic Path in Graph
  • OpenLoong技术观察 | 卓益得十年磨一剑:“行者”系列人形机器人技术演进观察
  • 构造函数延伸应用
  • DH(Denavit–Hartenberg)矩阵
  • redis汇总笔记
  • JAVA生成PDF(itextpdf)
  • 译码器设计
  • 论意识与人工智能:跨越鸿沟的艰难求索
  • gitlab批量删除远程分支(推荐方案二)
  • Java 大视界 -- Java 大数据在智能安防视频监控系统中的视频摘要快速生成与检索优化(345)
  • 【读书笔记】《C++ Software Design》第十章与第十一章 The Singleton Pattern The Last Guideline
  • vue3 ref vs reactive值的修改
  • 【Python练习】042. 编写一个函数,实现二叉树的前序、中序、后序遍历
  • k8s:0/1 nodes are available: pod has unbound immediate PersistentVolumeClaims.
  • 线性代数学习笔记
  • 【unitrix】 5.1 第二套类型级二进制数基本结构体(types2.rs)
  • k8s存储入门
  • archive/tar: unknown file mode ?rwxr-xr-x
  • JSON/AJAX/XHR/FetchAPI知识点学习整理
  • 06.计算两个日期之间的差值
  • IT岗位任职资格体系及发展通道-产品经理岗位任职标准参考
  • 基于Flink的实时开发平台-Dinky
  • composer如何安装以及举例在PHP项目中使用Composer安装TCPDF库-优雅草卓伊凡
  • Spring Boot中的路径变量
  • INA226 数据手册解读