Last active
May 23, 2026 14:38
-
-
Save bensheldon/f475a2669d72256545df5e2fcd1a4dae to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # frozen_string_literal: true | |
| require "fileutils" | |
| # Helper for Git worktree-aware behavior | |
| class GitWorktree | |
| PROJECT_ROOT = File.expand_path("..", __dir__) | |
| def self.instance = new | |
| def self.name = instance.name | |
| def self.worktree? = instance.worktree? | |
| def self.db_suffix = instance.db_suffix | |
| def self.copy_from_main_worktree(...) = instance.copy_from_main_worktree(...) | |
| def self.copy_to_main_worktree(...) = instance.copy_to_main_worktree(...) | |
| def self.integer(...) = instance.integer(...) | |
| def name | |
| return @_name if defined?(@_name) | |
| git_dir = `git rev-parse --git-dir 2>/dev/null`.strip | |
| return @_name = nil if git_dir.empty? || !git_dir.include?("/.git/worktrees/") # rubocop:disable Rails/NegateInclude | |
| # Conductor renames the branch after setup runs, so use the worktree directory | |
| # name (set at worktree creation) for a stable identifier during setup. | |
| @_name = normalize(File.basename(git_dir)) | |
| end | |
| def worktree? = !name.nil? | |
| def db_suffix | |
| value = name | |
| return "" if value.nil? | |
| "_#{value[0, 30]}" | |
| end | |
| # When in a worktree, copies each +relative_path+ from the main repo into this | |
| # worktree. Safe to call without Rails loaded. | |
| # +on_duplicate+ controls behavior when the destination already exists: | |
| # :ignore - skip the file | |
| # :overwrite - replace the destination | |
| # :increment - keep both if different, writing to +base-1.ext+, +base-2.ext+, etc. | |
| def copy_from_main_worktree(*relative_paths, on_duplicate:) | |
| return unless (root = main_root) | |
| relative_paths.each do |relative_path| | |
| copy_file(File.join(root, relative_path), File.join(PROJECT_ROOT, relative_path), on_duplicate: on_duplicate) | |
| end | |
| end | |
| # When in a worktree, copies each +relative_path+ from this worktree into the | |
| # main repo. Safe to call without Rails loaded. | |
| # +on_duplicate+ controls behavior when the destination already exists: | |
| # :ignore - skip the file | |
| # :overwrite - replace the destination | |
| # :increment - keep both if different, writing to +base-1.ext+, +base-2.ext+, etc. | |
| def copy_to_main_worktree(*relative_paths, on_duplicate:) | |
| return unless (root = main_root) | |
| relative_paths.each do |relative_path| | |
| copy_file(File.join(PROJECT_ROOT, relative_path), File.join(root, relative_path), on_duplicate: on_duplicate) | |
| end | |
| end | |
| # Returns a deterministic integer from +range+ based on the current worktree branch name. | |
| # Returns +range.first+ when not in a worktree (e.g. main branch). | |
| # | |
| # +stride+ reserves a block of consecutive integers per worktree so callers can add an | |
| # offset without colliding with adjacent worktrees. For example, Capybara system tests | |
| # use stride equal to PARALLEL_TEST_GROUPS and add TEST_ENV_NUMBER on top: | |
| # | |
| # GitWorktree.integer(4000..4990, stride: ENV.fetch("PARALLEL_TEST_GROUPS", 1).to_i) + ENV.fetch("TEST_ENV_NUMBER", 0).to_i | |
| # # worktree A (PARALLEL_TEST_GROUPS=4) => 4000, 4001, 4002, 4003 | |
| # # worktree B (PARALLEL_TEST_GROUPS=4) => 4020, 4021, 4022, 4023 (never overlaps A) | |
| def integer(range, stride: 1) | |
| value = name | |
| return range.first if value.nil? | |
| require "zlib" | |
| slots = range.size / stride | |
| range.first + ((Zlib.crc32(value) % slots) * stride) | |
| end | |
| private | |
| def main_root | |
| git_dir = `git rev-parse --git-dir 2>/dev/null`.strip | |
| git_common_dir = `git rev-parse --git-common-dir 2>/dev/null`.strip | |
| return if git_dir.empty? || git_dir == git_common_dir | |
| File.expand_path("..", git_common_dir) | |
| end | |
| def normalize(text) | |
| text.gsub(/[^a-zA-Z0-9_]/, "_").squeeze("_").downcase | |
| end | |
| def copy_file(source, dest, on_duplicate:) | |
| return unless File.exist?(source) | |
| if File.exist?(dest) | |
| case on_duplicate | |
| when :ignore | |
| return | |
| when :overwrite | |
| # fall through | |
| when :increment | |
| return if File.binread(source) == File.binread(dest) | |
| ext = File.extname(dest) | |
| base = dest.delete_suffix(ext) | |
| i = 1 | |
| loop do | |
| candidate = "#{base}-#{i}#{ext}" | |
| if File.exist?(candidate) | |
| return if File.binread(source) == File.binread(candidate) | |
| else | |
| dest = candidate | |
| break | |
| end | |
| i += 1 | |
| end | |
| end | |
| end | |
| FileUtils.mkdir_p(File.dirname(dest)) | |
| FileUtils.cp(source, dest) | |
| end | |
| end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment