Add Utils::Cp for interacting with cp command
This module determines the `cp` command to use based on availability of the `coreutils` formula and optimizes the command invocation to prefer a lightweight copy-on-write clone, which is significantly faster than a full file copy and helps to reduce the risk of exhausting the storage during the operation.
This commit is contained in:
parent
9fdb0d5399
commit
b905959a99
96
Library/Homebrew/utils/cp.rb
Normal file
96
Library/Homebrew/utils/cp.rb
Normal file
@ -0,0 +1,96 @@
|
||||
# typed: true
|
||||
# frozen_string_literal: true
|
||||
|
||||
require "system_command"
|
||||
|
||||
module Utils
|
||||
# Helper functions for interacting with the `cp` command.
|
||||
module Cp
|
||||
class << self
|
||||
sig {
|
||||
params(
|
||||
source: T.any(String, Pathname, T::Array[T.any(String, Pathname)]),
|
||||
target: T.any(String, Pathname),
|
||||
sudo: T::Boolean,
|
||||
verbose: T::Boolean,
|
||||
command: T.class_of(SystemCommand),
|
||||
).returns(SystemCommand::Result)
|
||||
}
|
||||
def copy(source, target, sudo: false, verbose: false, command: SystemCommand)
|
||||
command.run! executable, args: ["-p", *extra_flags, *source, target], sudo:, verbose:
|
||||
end
|
||||
|
||||
sig {
|
||||
params(
|
||||
source: T.any(String, Pathname, T::Array[T.any(String, Pathname)]),
|
||||
target: T.any(String, Pathname),
|
||||
sudo: T::Boolean,
|
||||
verbose: T::Boolean,
|
||||
command: T.class_of(SystemCommand),
|
||||
).returns(SystemCommand::Result)
|
||||
}
|
||||
def copy_recursive(source, target, sudo: false, verbose: false, command: SystemCommand)
|
||||
command.run! executable, args: ["-pR", *extra_flags, *source, target], sudo:, verbose:
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
GCP = (HOMEBREW_PREFIX/"opt/coreutils/libexec/gnubin/cp").freeze
|
||||
UCP = (HOMEBREW_PREFIX/"opt/uutils-coreutils/libexec/uubin/cp").freeze
|
||||
|
||||
sig { returns(T.any(String, Pathname)) }
|
||||
def executable
|
||||
case type
|
||||
when :coreutils
|
||||
GCP
|
||||
when :uutils
|
||||
UCP
|
||||
else
|
||||
"cp"
|
||||
end
|
||||
end
|
||||
|
||||
GNU_FLAGS = [
|
||||
# Unlike BSD cp, `gcp -p` doesn't guarantee to preserve extended attributes, including
|
||||
# quarantine information on macOS.
|
||||
"--preserve=all",
|
||||
"--no-preserve=links",
|
||||
# Perform a lightweight copy-on-write clone if applicable.
|
||||
"--reflink=auto",
|
||||
].freeze
|
||||
# On macOS, the `cp` utility has the `-c` option, which is equivalent to
|
||||
# `gcp --reflink=always`, but we are not using that because it would fail if the `clonefile`
|
||||
# syscall isn't applicable (the underlying filesystem doesn't support the feature or the
|
||||
# source and the target are on different filesystems).
|
||||
GENERIC_FLAGS = [].freeze
|
||||
|
||||
sig { returns(T::Array[String]) }
|
||||
def extra_flags
|
||||
if type
|
||||
GNU_FLAGS
|
||||
else
|
||||
GENERIC_FLAGS
|
||||
end
|
||||
end
|
||||
|
||||
sig { returns(T.nilable(Symbol)) }
|
||||
def type
|
||||
return @type if defined?(@type)
|
||||
|
||||
{
|
||||
coreutils: "coreutils",
|
||||
uutils: "uutils-coreutils",
|
||||
}.each do |type, formula|
|
||||
begin
|
||||
formula = Formula[formula]
|
||||
rescue FormulaUnavailableError
|
||||
next
|
||||
end
|
||||
return @type = type if formula.optlinked?
|
||||
end
|
||||
|
||||
@type = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
x
Reference in New Issue
Block a user