ETPackageVersionModule.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. #if ODIN_INSPECTOR
  2. using System;
  3. using System.Collections.Generic;
  4. using System.IO;
  5. using System.Text.RegularExpressions;
  6. using System.Threading.Tasks;
  7. using Newtonsoft.Json.Linq;
  8. using Sirenix.OdinInspector;
  9. using SerializationUtility = Sirenix.Serialization.SerializationUtility;
  10. using UnityEditor;
  11. using UnityEngine;
  12. namespace ET.PackageManager.Editor
  13. {
  14. [Flags]
  15. public enum EPackagesFilterType
  16. {
  17. [LabelText("全部")]
  18. All = 1 << 30,
  19. [LabelText("无")]
  20. None = 1,
  21. [LabelText("ET包")]
  22. ET = 1 << 1,
  23. [LabelText("更新")]
  24. Update = 1 << 2,
  25. [LabelText("请求")]
  26. Req = 1 << 3,
  27. [LabelText("禁用")]
  28. Ban = 1 << 4,
  29. [LabelText("解禁")]
  30. ReBan = 1 << 5,
  31. }
  32. public enum EPackagesFilterOperationType
  33. {
  34. [LabelText("唯一")]
  35. Only = 0,
  36. [LabelText("或")]
  37. Or = 1,
  38. [LabelText("与")]
  39. And = 2,
  40. }
  41. /// <summary>
  42. /// 版本管理
  43. /// </summary>
  44. [ETPackageMenu("版本管理", 1000)]
  45. public partial class ETPackageVersionModule : BasePackageToolModule
  46. {
  47. public static ETPackageVersionModule Inst;
  48. [HideLabel]
  49. [HideIf("CheckUpdateAllEnd")]
  50. [ShowInInspector]
  51. [DisplayAsString(false, 100, TextAlignment.Center, true)]
  52. private const string m_CheckUpdateAllReqing = "请求所有包最新版本中...";
  53. [BoxGroup("信息", centerLabel: true)]
  54. [EnumToggleButtons]
  55. [HideLabel]
  56. [OnValueChanged("OnFilterOperationTypeChanged")]
  57. [ShowIf("CheckUpdateAllEnd")]
  58. [PropertyOrder(-666)]
  59. public EPackagesFilterOperationType FilterOperationType;
  60. private void OnFilterOperationTypeChanged()
  61. {
  62. if (FilterOperationType == EPackagesFilterOperationType.Only)
  63. {
  64. LastFilterType = EPackagesFilterType.None;
  65. FilterType = EPackagesFilterType.None;
  66. }
  67. LoadFilterPackageInfoData();
  68. }
  69. [BoxGroup("信息", centerLabel: true)]
  70. [EnumToggleButtons]
  71. [HideLabel]
  72. [OnValueChanged("OnFilterTypeChanged")]
  73. [ShowIf("CheckUpdateAllEnd")]
  74. [PropertyOrder(-666)]
  75. public EPackagesFilterType FilterType;
  76. private EPackagesFilterType LastFilterType;
  77. private void OnFilterTypeChanged()
  78. {
  79. if (FilterOperationType == EPackagesFilterOperationType.Only)
  80. {
  81. if (FilterType != LastFilterType)
  82. {
  83. var current = (int)FilterType;
  84. var last = (int)LastFilterType;
  85. FilterType = (EPackagesFilterType)(current > last ? current - last : last - current);
  86. }
  87. }
  88. LastFilterType = FilterType;
  89. LoadFilterPackageInfoData();
  90. }
  91. [BoxGroup("信息", centerLabel: true)]
  92. [LabelText("搜索 (支持正则)")]
  93. [ShowIf("CheckUpdateAllEnd")]
  94. [OnValueChanged("OnSearchChanged")]
  95. [Delayed]
  96. [ShowInInspector]
  97. [PropertyOrder(-444)]
  98. private string Search = "";
  99. private void OnSearchChanged()
  100. {
  101. Search = Search.ToLower();
  102. LoadFilterPackageInfoData();
  103. }
  104. private EnumPrefs<EPackagesFilterType> FilterTypePrefs = new("ETPackageVersionModule_FilterType", null, EPackagesFilterType.ET);
  105. private EnumPrefs<EPackagesFilterOperationType> FilterOperationTypePrefs = new("ETPackageVersionModule_FilterOperationType");
  106. private BoolPrefs SyncDependencyPrefs = new("ETPackageVersionModule_SyncDependency", null, true);
  107. private StringPrefs SearchPrefs = new("ETPackageVersionModule_Search", null, "");
  108. public bool CheckUpdateAllEnd { get; private set; }
  109. public bool RequestAllResult { get; private set; }
  110. public override void Initialize()
  111. {
  112. CheckUpdateAllEnd = false;
  113. RequestAllResult = false;
  114. PackageHelper.CheckUpdateAll((result) =>
  115. {
  116. CheckUpdateAllEnd = true;
  117. RequestAllResult = result;
  118. if (!result) return;
  119. Search = SearchPrefs.Value;
  120. FilterType = FilterTypePrefs.Value;
  121. LastFilterType = FilterType;
  122. FilterOperationType = FilterOperationTypePrefs.Value;
  123. LoadAllPackageInfoData();
  124. LoadFilterPackageInfoData();
  125. Inst = this;
  126. });
  127. }
  128. public override void OnDestroy()
  129. {
  130. Inst = null;
  131. SearchPrefs.Value = Search;
  132. FilterTypePrefs.Value = FilterType;
  133. FilterOperationTypePrefs.Value = FilterOperationType;
  134. }
  135. [Button("同步生成", 50)]
  136. [GUIColor(1, 1, 0)]
  137. [PropertyOrder(-888)]
  138. [ShowIf("CheckUpdateAllEnd")]
  139. public void SyncPackages()
  140. {
  141. UnityTipsHelper.CallBack($"确定同步生成当前所有改动版本?", () =>
  142. {
  143. #pragma warning disable CS4014 // 由于此调用不会等待,因此在调用完成前将继续执行当前方法
  144. UpdatePackagesInfo();
  145. #pragma warning restore CS4014 // 由于此调用不会等待,因此在调用完成前将继续执行当前方法
  146. });
  147. }
  148. [Button("文档", 30, Icon = SdfIconType.Link45deg, IconAlignment = IconAlignment.LeftOfText)]
  149. [PropertyOrder(-999)]
  150. [ShowIf("CheckUpdateAllEnd")]
  151. public void OpenDocument()
  152. {
  153. ETPackageDocumentModule.ETPackageVersion();
  154. }
  155. private async Task UpdatePackagesInfo(bool close = true)
  156. {
  157. var count = m_AllPackageInfoDataDic.Count;
  158. var index = 0;
  159. foreach (var data in m_AllPackageInfoDataDic)
  160. {
  161. index++;
  162. var packageInfo = data.Value;
  163. if (!CheckPackageChange(packageInfo)) continue;
  164. EditorUtility.DisplayProgressBar("同步信息", $"更新{packageInfo.Name}", index * 1f / count);
  165. await ChangePackageInfo(packageInfo);
  166. }
  167. ETPackageAutoTool.UnloadAllAssets();
  168. if (close)
  169. {
  170. PackageExecuteMenuItemHelper.ET_Init_RepairDependencies();
  171. EditorUtility.ClearProgressBar();
  172. ETPackageAutoTool.CloseWindowRefresh();
  173. }
  174. }
  175. private bool CheckPackageChange(PackageVersionData packageInfoData)
  176. {
  177. if (!packageInfoData.IsETPackage)
  178. {
  179. return false;
  180. }
  181. var oldAllPackage = PackageVersionHelper.PackageVersionAsset.AllPackageVersionData;
  182. if (!oldAllPackage.ContainsKey(packageInfoData.Name))
  183. {
  184. return false;
  185. }
  186. var oldPackageInfo = oldAllPackage[packageInfoData.Name];
  187. //对比版本
  188. if (packageInfoData.Version != oldPackageInfo.Version)
  189. {
  190. return true;
  191. }
  192. //对比依赖
  193. if (packageInfoData.Dependencies.Count != oldPackageInfo.Dependencies.Count)
  194. {
  195. return true;
  196. }
  197. for (int i = 0; i < packageInfoData.Dependencies.Count; i++)
  198. {
  199. var dependency = packageInfoData.Dependencies[i];
  200. var oldDependency = oldPackageInfo.Dependencies[i];
  201. if (dependency.Name != oldDependency.Name || dependency.Version != oldDependency.Version)
  202. {
  203. return true;
  204. }
  205. }
  206. //对比依赖我
  207. if (packageInfoData.DependenciesSelf.Count != oldPackageInfo.DependenciesSelf.Count)
  208. {
  209. return true;
  210. }
  211. for (int i = 0; i < packageInfoData.DependenciesSelf.Count; i++)
  212. {
  213. var dependency = packageInfoData.DependenciesSelf[i];
  214. var oldDependency = oldPackageInfo.DependenciesSelf[i];
  215. if (dependency.Name != oldDependency.Name || dependency.Version != oldDependency.Version)
  216. {
  217. return true;
  218. }
  219. }
  220. return false;
  221. }
  222. private async Task ChangePackageInfo(PackageVersionData packageInfoData)
  223. {
  224. var assetPath = $"Packages/{packageInfoData.Name}/package.json";
  225. var packagePath = $"{Application.dataPath}/../{assetPath}";
  226. if (!File.Exists(packagePath))
  227. {
  228. //Debug.LogError($"包 {packageInfoData.Name} 路径 {packagePath} 不存在");
  229. return;
  230. }
  231. var changeVersion = Regex.Replace(packageInfoData.Version, Pattern, "");
  232. try
  233. {
  234. string fileContent = await File.ReadAllTextAsync(packagePath);
  235. JObject json = JObject.Parse(fileContent);
  236. json["version"] = changeVersion;
  237. json["dependencies"] = NewDependencies(packageInfoData);
  238. await File.WriteAllTextAsync(packagePath, json.ToString(), System.Text.Encoding.UTF8);
  239. Debug.Log($"修改成功 {packageInfoData.Name}");
  240. }
  241. catch (Exception e)
  242. {
  243. Debug.LogError($"错误 修改包 {packageInfoData.Name} 失败 {e.Message}");
  244. return;
  245. }
  246. }
  247. private JObject NewDependencies(PackageVersionData packageInfoData)
  248. {
  249. JObject newDependencies = new JObject();
  250. foreach (var dependency in packageInfoData.Dependencies)
  251. {
  252. newDependencies[dependency.Name] = Regex.Replace(dependency.Version, Pattern, "");
  253. }
  254. return newDependencies;
  255. }
  256. [TableList(DrawScrollView = true, AlwaysExpanded = true, IsReadOnly = true)]
  257. [NonSerialized]
  258. [BoxGroup("筛选包数据", centerLabel: true)]
  259. [HideLabel]
  260. [ShowInInspector]
  261. [ShowIf("CheckUpdateAllEnd")]
  262. [PropertyOrder(999)]
  263. private List<PackageVersionData> m_FilterPackageInfoDataList = new();
  264. private readonly Dictionary<string, PackageVersionData> m_FilterPackageInfoDataDic = new();
  265. private Dictionary<string, PackageVersionData> m_AllPackageInfoDataDic;
  266. public PackageVersionData GetPackageInfoData(string packageName)
  267. {
  268. m_AllPackageInfoDataDic.TryGetValue(packageName, out PackageVersionData packageInfoData);
  269. return packageInfoData;
  270. }
  271. private void LoadFilterPackageInfoData()
  272. {
  273. m_FilterPackageInfoDataList.Clear();
  274. m_FilterPackageInfoDataDic.Clear();
  275. var packagesFilterTypeValues = Enum.GetValues(typeof(EPackagesFilterType));
  276. foreach (var data in m_AllPackageInfoDataDic)
  277. {
  278. var name = data.Key;
  279. if (!string.IsNullOrEmpty(Search) && !Regex.IsMatch(name, Search))
  280. {
  281. continue;
  282. }
  283. var infoData = data.Value;
  284. var add = false;
  285. switch (FilterOperationType)
  286. {
  287. case EPackagesFilterOperationType.Only:
  288. add = GetResult(FilterType);
  289. break;
  290. case EPackagesFilterOperationType.Or:
  291. add = false;
  292. foreach (var value in packagesFilterTypeValues)
  293. {
  294. var filterTypeValue = (EPackagesFilterType)value;
  295. var hasReslut = FilterType.HasFlag(filterTypeValue);
  296. if (hasReslut)
  297. {
  298. add = GetResult(filterTypeValue);
  299. if (add)
  300. {
  301. break;
  302. }
  303. }
  304. }
  305. break;
  306. case EPackagesFilterOperationType.And:
  307. add = true;
  308. foreach (var value in packagesFilterTypeValues)
  309. {
  310. var filterTypeValue = (EPackagesFilterType)value;
  311. var hasReslut = FilterType.HasFlag(filterTypeValue);
  312. if (hasReslut)
  313. {
  314. add = GetResult(filterTypeValue);
  315. if (!add)
  316. {
  317. break;
  318. }
  319. }
  320. }
  321. break;
  322. default:
  323. //Debug.LogError($"未实现的操作类型 {FilterOperationType}");
  324. break;
  325. }
  326. if (!add) continue;
  327. m_FilterPackageInfoDataList.Add(infoData);
  328. m_FilterPackageInfoDataDic.Add(name, infoData);
  329. continue;
  330. bool GetResult(EPackagesFilterType filterValue)
  331. {
  332. var result = false;
  333. switch (filterValue)
  334. {
  335. case EPackagesFilterType.All:
  336. result = true;
  337. break;
  338. case EPackagesFilterType.None:
  339. result = false;
  340. break;
  341. case EPackagesFilterType.ET:
  342. result = infoData.IsETPackage;
  343. break;
  344. case EPackagesFilterType.Update:
  345. result = infoData.CanUpdateVersion;
  346. break;
  347. case EPackagesFilterType.Req:
  348. result = infoData.ShowIfReqVersion();
  349. break;
  350. case EPackagesFilterType.Ban:
  351. result = infoData.ShowIfBanReqVersion();
  352. break;
  353. case EPackagesFilterType.ReBan:
  354. result = infoData.ShowIfReBanReqVersion();
  355. break;
  356. default:
  357. //Debug.LogError($"新增了筛选条件 请扩展 {filterValue}");
  358. break;
  359. }
  360. return result;
  361. }
  362. }
  363. }
  364. private void LoadAllPackageInfoData()
  365. {
  366. m_AllPackageInfoDataDic = (Dictionary<string, PackageVersionData>)SerializationUtility.CreateCopy(PackageVersionHelper.PackageVersionAsset.AllPackageVersionData);
  367. //处理依赖检查
  368. foreach (var data in m_AllPackageInfoDataDic.Values)
  369. {
  370. var name = data.Name;
  371. var dependencies = data.Dependencies;
  372. foreach (var dependency in dependencies)
  373. {
  374. if (!m_AllPackageInfoDataDic.ContainsKey(dependency.Name))
  375. {
  376. if (dependency.Name.Contains("cn.etetet."))
  377. {
  378. Debug.LogError($"{name}依赖包{dependency.Name}不存在");
  379. }
  380. continue;
  381. }
  382. var target = m_AllPackageInfoDataDic[dependency.Name];
  383. if (target.IsETPackage && !CheckVersion(dependency, target))
  384. {
  385. Debug.LogError($"[{name}]依赖包[{dependency.Name}] 版本不匹配,依赖版本[{dependency.Version}],当前版本[{target.Version}]");
  386. }
  387. }
  388. }
  389. }
  390. private readonly Dictionary<string, int[]> m_VersionValueDict = new();
  391. public const string Pattern = "[^0-9.]";
  392. private int[] GetVersionValue(string version)
  393. {
  394. if (m_VersionValueDict.TryGetValue(version, out int[] value))
  395. {
  396. return value;
  397. }
  398. var versionSplit = Regex.Replace(version, Pattern, "").Split('.');
  399. m_VersionValueDict[version] = new int[versionSplit.Length];
  400. for (int i = 0; i < versionSplit.Length; i++)
  401. {
  402. if (!int.TryParse(versionSplit[i], out m_VersionValueDict[version][i]))
  403. {
  404. Debug.LogError($"{version} {i} {versionSplit[i]} 不是数字");
  405. }
  406. }
  407. return m_VersionValueDict[version];
  408. }
  409. private bool CheckVersion(DependencyInfo dependencyInfo, PackageVersionData targetData)
  410. {
  411. var dependencyVersion = dependencyInfo.Version;
  412. var versionValue = GetVersionValue(dependencyVersion);
  413. var targetVersionValue = targetData?.VersionValue;
  414. if (targetVersionValue == null)
  415. {
  416. Debug.Log($"{targetData.Name} Version == null");
  417. return false;
  418. }
  419. //长度判断
  420. if (targetVersionValue.Length != versionValue.Length)
  421. {
  422. Debug.Log($"{targetData.Name} Version长度不一致,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
  423. return false;
  424. }
  425. //大版本号判断
  426. if (targetVersionValue.Length >= 1 && targetVersionValue[0] != versionValue[0])
  427. {
  428. Debug.Log($"{targetData.Name} 大版本号不匹配,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
  429. return false;
  430. }
  431. //中版本号判断
  432. if (targetVersionValue.Length >= 2 && targetVersionValue[1] != versionValue[1])
  433. {
  434. Debug.Log($"{targetData.Name} 中版本号不匹配,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
  435. return false;
  436. }
  437. //小版本号判断
  438. if (targetVersionValue.Length >= 3 && targetVersionValue[2] < versionValue[2])
  439. {
  440. Debug.Log($"{targetData.Name} 小版本号不匹配,实际:{targetData.Version} 与 依赖:{dependencyVersion}不匹配");
  441. return false;
  442. }
  443. return true;
  444. }
  445. }
  446. }
  447. #endif