Module: CBin::Helpers::WorktreeIdentity

Defined in:
lib/cocoapods-meitu-bin/helpers/worktree_identity.rb

Constant Summary collapse

RULE_VERSION =

规则版本会进入调试日志,便于在不同实现版本间快速对齐排障。

'v1_git_tree_diff_untracked_sha1'.freeze

Class Method Summary collapse

Class Method Details

.compute(module_dir) ⇒ Object



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/cocoapods-meitu-bin/helpers/worktree_identity.rb', line 25

def compute(module_dir)
  module_dir = Pathname.new(module_dir).expand_path
  git_root = git_output(module_dir.to_s, %w[rev-parse --show-toplevel])
  return fallback_directory_digest(module_dir) if git_root.nil? || git_root.empty?

  git_root_path = Pathname.new(git_root)
  relative_path = module_dir.relative_path_from(git_root_path).to_s
  # 四段输入覆盖 HEAD/index/worktree/untracked:
  # 1) base_tree: HEAD 下模块快照
  # 2) staged_diff: 已暂存改动
  # 3) unstaged_diff: 未暂存改动
  # 4) untracked_digest: 未跟踪文件列表 + 内容
  base_tree = git_output(git_root, ['rev-parse', "HEAD:#{relative_path}"], allow_failure: true).to_s
  staged_diff = git_output(git_root, ['diff', '--cached', '--binary', '--no-ext-diff', '--', relative_path], allow_failure: true).to_s
  unstaged_diff = git_output(git_root, ['diff', '--binary', '--no-ext-diff', '--', relative_path], allow_failure: true).to_s
  untracked_lines = git_output(git_root, ['ls-files', '--others', '--exclude-standard', '--', relative_path], allow_failure: true).to_s

  untracked_digest = Digest::SHA1.new
  untracked_lines.lines.map(&:chomp).reject(&:empty?).sort.each do |entry|
    abs_path = git_root_path.join(entry)
    untracked_digest.update(entry)
    untracked_digest.update("\0")
    untracked_digest.file(abs_path.to_s) if abs_path.file?
    untracked_digest.update("\0")
  end

  payload = [
    base_tree,
    Digest::SHA1.hexdigest(staged_diff),
    Digest::SHA1.hexdigest(unstaged_diff),
    untracked_digest.hexdigest,
  ].join('|')

  Digest::SHA1.hexdigest(payload)
rescue ArgumentError, Errno::ENOENT
  # Git 查询异常时回退到全目录摘要,确保仍有稳定 identity 可用于版本计算。
  fallback_directory_digest(module_dir)
end

.fallback_directory_digest(module_dir) ⇒ Object



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/cocoapods-meitu-bin/helpers/worktree_identity.rb', line 75

def fallback_directory_digest(module_dir)
  digest = Digest::SHA1.new

  # 非 git 场景:按相对路径 + 文件内容做摘要,保证目录态变化可感知。
  Find.find(module_dir.to_s) do |path|
    next if File.directory?(path)

    rel_path = Pathname.new(path).relative_path_from(module_dir).to_s
    digest.update(rel_path)
    digest.update("\0")
    digest.file(path)
    digest.update("\0")
  end

  digest.hexdigest
end

.for_sandbox_pod(sandbox, pod_name) ⇒ Object



17
18
19
20
21
22
23
# File 'lib/cocoapods-meitu-bin/helpers/worktree_identity.rb', line 17

def for_sandbox_pod(sandbox, pod_name)
  podspec_path = sandbox.local_podspec(pod_name)
  return nil unless podspec_path

  # local podspec 所在目录即该组件在 monorepo 中的实际模块目录。
  compute(Pathname.new(podspec_path).dirname)
end

.git_output(chdir, args, allow_failure: false) ⇒ Object



64
65
66
67
68
69
70
71
72
73
# File 'lib/cocoapods-meitu-bin/helpers/worktree_identity.rb', line 64

def git_output(chdir, args, allow_failure: false)
  stdout, status = Open3.capture2('git', *args, chdir: chdir)
  return stdout.strip if status.success?
  # allow_failure 为 true 的场景用于容忍“模块首次接入/路径不存在于 HEAD”等可预期情况。
  return nil if allow_failure

  nil
rescue Errno::ENOENT
  nil
end

.rule_versionObject



13
14
15
# File 'lib/cocoapods-meitu-bin/helpers/worktree_identity.rb', line 13

def rule_version
  RULE_VERSION
end