module Git::Repository::ObjectOperations::Private
Private helpers
@api private
Public Instance Methods
Source
# File lib/git/repository/object_operations.rb, line 1280 def apply_gzip(file) gz_tmp = Tempfile.create('archive_gz', File.dirname(file)).tap(&:close).path Zlib::GzipWriter.open(gz_tmp) { |gz| File.open(file, 'rb') { |f| IO.copy_stream(f, gz) } } FileUtils.rm_f(file) File.rename(gz_tmp, file) rescue StandardError FileUtils.rm_f(gz_tmp) if gz_tmp raise end
Apply gzip compression to the given file in place
Streams from the source file through a {Zlib::GzipWriter} into a sibling temporary file, then replaces the original. Peak memory is proportional to the stream buffer rather than the full archive size.
@param file [String] path to the file to compress in place
@return [void]
@api private
Source
# File lib/git/repository/object_operations.rb, line 1231 def atomic_replace(src, dest) mode = File.exist?(dest) ? (File.stat(dest).mode & 0o777) : (0o666 & ~File.umask) File.chmod(mode, src) File.rename(src, dest) rescue StandardError FileUtils.rm_f(src) raise end
Atomically rename the staging file ‘src` to `dest`, replacing any existing file at `dest`. Both paths must be on the same filesystem (guaranteed when `src` is created by {#staging_dir_for}).
Before the rename, the staging file’s permissions are set to the existing file’s numeric mode (if ‘dest` already existed) or to `0666 & ~umask` (standard creation mode) for new files. The chmod is applied to `src` before the rename so that, if chmod fails, `src` is still present and can be cleaned up by the rescue. Only the numeric permission bits are carried over; ownership, ACLs, and extended attributes from an existing `dest` are not preserved.
If ‘dest` is a symlink, the symlink itself is replaced by the renamed staging file rather than writing through the link to its target.
@param src [String] staging file path to rename; removed on success
@param dest [String] destination file path
@return [void]
@api private
Source
# File lib/git/repository/object_operations.rb, line 1167 def create_archive_tempfile(execution_context, treeish, opts, format, dest_dir) tmp_file = Tempfile.create('archive', dest_dir).tap(&:binmode) run_archive_command(execution_context, treeish, opts, format, tmp_file) tmp_file.close tmp_file rescue StandardError tmp_file&.close FileUtils.rm_f(tmp_file.path) if tmp_file raise end
Create a staging file, write the archive into it, close it, and return it
Uses ‘Tempfile.create` (not `Tempfile.new`) so that no GC finalizer is registered on the returned object — the file path remains valid after this method returns and after the caller stores only the path string.
@param execution_context [Git::ExecutionContext] for the git command
@param treeish [String] tree-ish passed to ‘git archive`
@param format [String] archive format string (e.g. ‘’zip’‘ or `’tar’‘)
@param dest_dir [String] directory in which to create the temp file
@param opts [Hash] caller-supplied options (read-only; used for :prefix,
:remote, and :path)
@option opts [String] :prefix (nil) prefix for entries in the archive
@option opts [String] :path (nil) path within ‘treeish` to archive
@option opts [String] :remote (nil) remote repository from which to
retrieve the archive
@return [File] the closed file containing the archive
@api private
Source
# File lib/git/repository/object_operations.rb, line 1262 def parse_archive_format_options(opts) format = opts[:format] || 'zip' gzip = opts[:add_gzip] == true || format == 'tgz' [format == 'tgz' ? 'tar' : format, gzip] end
Determine the archive format and whether to apply gzip post-processing
The ‘tgz` pseudo-format is not understood by `git archive` directly; it is converted to `tar` and the gzip flag is set so that {#archive} applies gzip compression after the archive is written.
@param opts [Hash] caller-supplied options hash (read-only)
@option opts [String] :format (‘zip’) archive format (‘’tar’‘, `’zip’‘,
or `'tgz'`)
@option opts [Boolean, nil] :add_gzip (nil) apply gzip post-processing
after archive generation
@return [Array(String, Boolean)] a two-element array ‘[format, gzip]`
`format` is the string to pass to `git archive --format`; `gzip` is `true` when the caller should apply gzip post-processing after writing the archive.
@api private
Source
# File lib/git/repository/object_operations.rb, line 1068 def parse_grep_result(result) exitstatus = result.status.exitstatus return {} if exitstatus == 1 && result.stderr.empty? raise Git::FailedError, result if exitstatus == 1 Git::Parsers::Grep.parse(result.stdout) end
Parses the result of a git grep command
@param result [Git::CommandLine::Result] the result of a git grep command
@return [Hash<String, Array<Array(Integer, String)>>] hash mapping “treeish:filename”
keys to arrays of [line_number, text] pairs
Source
# File lib/git/repository/object_operations.rb, line 1202 def run_archive_command(execution_context, treeish, opts, format, tmp_file) command_opts = opts.slice(:prefix, :remote).merge(format: format) path_args = opts[:path] ? [opts[:path]] : [] Git::Commands::Archive.new(execution_context).call(treeish, *path_args, **command_opts, out: tmp_file) end
Invoke ‘git archive` and stream output into `tmp_file`
@param execution_context [Git::ExecutionContext] for the git command
@param treeish [String] tree-ish passed to ‘git archive`
@param format [String] archive format to pass to ‘git archive –format`
@param tmp_file [File] open, binary-mode IO to write archive data to
@param opts [Hash] caller-supplied options (read-only; used for :prefix,
:remote, and :path)
@option opts [String] :prefix (nil) prefix for entries in the archive
@option opts [String] :path (nil) path within ‘treeish` to archive
@option opts [String] :remote (nil) remote repository from which to
retrieve the archive
@return [Git::CommandLine::Result] the result of the git command
@api private
Source
# File lib/git/repository/object_operations.rb, line 1052 def show_ref_tag_sha(execution_context, tag_name) ref = "refs/tags/#{tag_name}" result = Git::Commands::ShowRef::List.new(execution_context).call(ref) return '' if result.status.exitstatus == 1 line = result.stdout.lines.find { |l| l.split[1] == ref } line ? line.split[0] : '' end
Returns the direct SHA for a tag reference
Returns the hash from ‘refs/tags/<name>` only. Returns an empty string when the ref does not exist.
@param execution_context [Git::ExecutionContext] for running
`git show-ref`
@param tag_name [String] tag name without the ‘refs/tags/` prefix
@return [String] direct ref SHA or an empty string when missing
@api private
Source
# File lib/git/repository/object_operations.rb, line 1090 def staging_dir_for(file) return Dir.tmpdir unless file File.dirname(File.expand_path(file)) end
Resolve the staging directory for a git archive temp file
Always returns ‘Dir.tmpdir` when `file` is nil, or the parent directory of `file` otherwise. Staging the temp file in the same directory as the destination keeps both paths on the same filesystem so that {#atomic_replace} can use an atomic rename that requires no extra disk space.
@param file [String, nil] the explicit destination path, or nil
@return [String] directory path to pass to ‘Tempfile.create`
@api private
Source
# File lib/git/repository/object_operations.rb, line 1025 def tag_add_delete_deprecated(facade, name, target, opts) Git::Deprecation.warn( 'Passing :d or :delete to tag_add is deprecated and will be removed in v6.0.0. ' \ 'Use tag_delete instead.' ) raise ArgumentError, 'Cannot pass a target when using the :d/:delete option.' if target extra = opts.keys - %i[d delete] raise ArgumentError, "Cannot combine :d/:delete with other options: #{extra.join(', ')}" unless extra.empty? facade.tag_delete(name) end
Handle the deprecated :d/:delete option on tag_add
Issues a deprecation warning and delegates to tag_delete. Raises ArgumentError if a target or incompatible options are also supplied.
@param facade [ObjectOperations] the calling facade instance
@param name [String] tag name
@param target [String, nil] target argument (must be nil)
@param opts [Hash] options hash (must contain only :d/:delete)
@option opts [Boolean] :d (true) request deletion in the deprecated
`tag_add` form
@option opts [Boolean] :delete (true) alias for ‘:d`
@return [String] stdout from tag_delete
@api private
Source
# File lib/git/repository/object_operations.rb, line 994 def validate_tag_options!(opts) needs_message = %i[a annotate s sign u local_user].any? { |k| opts[k] } has_message = opts[:m] || opts[:message] || opts[:F] || opts[:file] return unless needs_message && !has_message raise ArgumentError, 'Cannot create an annotated or signed tag without a message.' end
Validate that a message is present when an annotated or signed tag is requested
@param opts [Hash] the tag-creation options
@option opts [Boolean, nil] :annotate request an annotated tag
@option opts [Boolean, nil] :a alias for ‘:annotate`
@option opts [Boolean, nil] :sign request a signed tag
@option opts [Boolean, nil] :s alias for ‘:sign`
@option opts [String] :local_user key id used when signing
@option opts [String] :u alias for ‘:local_user`
@option opts [String] :message tag message text
@option opts [String] :m alias for ‘:message`
@option opts [String] :file path to a tag message file
@option opts [String] :F alias for ‘:file`
@return [void]
@raise [ArgumentError] when an annotated or signed tag is requested
without a `:message`/`:m`/`:file`/`:F` value
Source
# File lib/git/repository/object_operations.rb, line 1128 def write_archive_tmp(execution_context, treeish, opts, dest_dir: Dir.tmpdir) format, gzip = parse_archive_format_options(opts) tmp_file = create_archive_tempfile(execution_context, treeish, opts, format, dest_dir) apply_gzip(tmp_file.path) if gzip tmp_file.path rescue StandardError tmp_file.close unless tmp_file.nil? || tmp_file.closed? FileUtils.rm_f(tmp_file.path) if tmp_file raise end
Write a git archive to a fresh temporary file and return its path
Always writes to a new temporary file so that on error the caller’s destination file is never truncated. Format and gzip post-processing are determined from ‘opts` via {#parse_archive_format_options}.
@param execution_context [Git::ExecutionContext] for the git command
@param treeish [String] tree-ish passed to ‘git archive`
@param dest_dir [String] directory for the staging temp file; use
{#staging_dir_for} to select the optimal directory for the destination
@param opts [Hash] caller-supplied options (read-only)
@option opts [String] :format (‘zip’) archive format (‘’tar’‘, `’zip’‘,
or `'tgz'`)
@option opts [Boolean, nil] :add_gzip (nil) apply gzip post-processing
to the generated archive
@option opts [String] :prefix (nil) prefix for entries in the archive
@option opts [String] :path (nil) path within ‘treeish` to archive
@option opts [String] :remote (nil) remote repository from which to
retrieve the archive
@return [String] path to the populated temporary file
@api private