View Issue Details

IDProjectCategoryView StatusLast Update
0000476fileGeneralpublic2024-02-04 19:30
Reporterabathur Assigned Tochristos  
PrioritynormalSeverityminorReproducibilityalways
Status feedbackResolutionopen 
Product Version5.45 
Summary0000476: identifying templated shebangs?
DescriptionI noticed the identifications like below for a few templates in ruby's bundler project:

bundler/lib/bundler/templates/Executable: a <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> script, ASCII text executable


I'm not sure if a fix will be in scope since this feels like a pathological edge case. I'm also not sure what the best outcome would be if you feel like it is. I can imagine a few:

1. If it isn't a valid shebang, perhaps it can be excluded from the category of executables? I tried a naive test of this--mark it executable and try to run it. On Linux (NixOS) this just hangs (in strace it looks like it's looping before it ever gets passed to env). In macOS some or all of the shebang makes it through to env:

$ bundler/lib/bundler/templates/Executable.standalone
env: Bundler.settings[:shebang]: No such file or directory

I'm not sure if it's the system or env ignoring `<%=` here.

2. Identify them as templates

3. Identify them as Ruby scripts (though I only really suggest this since it's already identifying the Executable.bundler script that way)
Steps To Reproduce$ file bundler/lib/bundler/templates/Executable*
bundler/lib/bundler/templates/Executable: a <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> script, ASCII text executable
bundler/lib/bundler/templates/Executable.bundler: Ruby script, ASCII text
bundler/lib/bundler/templates/Executable.standalone: a <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %> script, ASCII text executable
Additional Information$ file --version
file-5.45
magic file from /nix/store/nil8ddwh0gg3rx7gr7bs6xi0lnnvsi71-file-5.45/share/misc/magic

TagsNo tags attached.

Activities

abathur

2023-09-02 16:58

reporter  

Executable (868 bytes)   
#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %>
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application '<%= executable %>' is installed as part of a gem, and
# this file is here to facilitate running it.
#

ENV["BUNDLE_GEMFILE"] ||= File.expand_path("<%= relative_gemfile_path %>", __dir__)

bundle_binstub = File.expand_path("bundle", __dir__)

if File.file?(bundle_binstub)
  if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
    load(bundle_binstub)
  else
    abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
  end
end

require "rubygems"
require "bundler/setup"

load Gem.bin_path("<%= spec.name %>", "<%= executable %>")
Executable (868 bytes)   
Executable.bundler (2,915 bytes)   
#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %>
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application '<%= executable %>' is installed as part of a gem, and
# this file is here to facilitate running it.
#

require "rubygems"

m = Module.new do
  module_function

  def invoked_as_script?
    File.expand_path($0) == File.expand_path(__FILE__)
  end

  def env_var_version
    ENV["BUNDLER_VERSION"]
  end

  def cli_arg_version
    return unless invoked_as_script? # don't want to hijack other binstubs
    return unless "update".start_with?(ARGV.first || " ") # must be running `bundle update`
    bundler_version = nil
    update_index = nil
    ARGV.each_with_index do |a, i|
      if update_index && update_index.succ == i && a =~ Gem::Version::ANCHORED_VERSION_PATTERN
        bundler_version = a
      end
      next unless a =~ /\A--bundler(?:[= ](#{Gem::Version::VERSION_PATTERN}))?\z/
      bundler_version = $1
      update_index = i
    end
    bundler_version
  end

  def gemfile
    gemfile = ENV["BUNDLE_GEMFILE"]
    return gemfile if gemfile && !gemfile.empty?

    File.expand_path("<%= relative_gemfile_path %>", __dir__)
  end

  def lockfile
    lockfile =
      case File.basename(gemfile)
      when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
      else "#{gemfile}.lock"
      end
    File.expand_path(lockfile)
  end

  def lockfile_version
    return unless File.file?(lockfile)
    lockfile_contents = File.read(lockfile)
    return unless lockfile_contents =~ /\n\nBUNDLED WITH\n\s{2,}(#{Gem::Version::VERSION_PATTERN})\n/
    Regexp.last_match(1)
  end

  def bundler_requirement
    @bundler_requirement ||=
      env_var_version ||
      cli_arg_version ||
      bundler_requirement_for(lockfile_version)
  end

  def bundler_requirement_for(version)
    return "#{Gem::Requirement.default}.a" unless version

    bundler_gem_version = Gem::Version.new(version)

    bundler_gem_version.approximate_recommendation
  end

  def load_bundler!
    ENV["BUNDLE_GEMFILE"] ||= gemfile

    activate_bundler
  end

  def activate_bundler
    gem_error = activation_error_handling do
      gem "bundler", bundler_requirement
    end
    return if gem_error.nil?
    require_error = activation_error_handling do
      require "bundler/version"
    end
    return if require_error.nil? && Gem::Requirement.new(bundler_requirement).satisfied_by?(Gem::Version.new(Bundler::VERSION))
    warn "Activating bundler (#{bundler_requirement}) failed:\n#{gem_error.message}\n\nTo install the version of bundler this project requires, run `gem install bundler -v '#{bundler_requirement}'`"
    exit 42
  end

  def activation_error_handling
    yield
    nil
  rescue StandardError, LoadError => e
    e
  end
end

m.load_bundler!

if m.invoked_as_script?
  load Gem.bin_path("<%= spec.name %>", "<%= executable %>")
end
Executable.bundler (2,915 bytes)   
Executable.standalone (428 bytes)   
#!/usr/bin/env <%= Bundler.settings[:shebang] || RbConfig::CONFIG["ruby_install_name"] %>
# frozen_string_literal: true

#
# This file was generated by Bundler.
#
# The application '<%= executable %>' is installed as part of a gem, and
# this file is here to facilitate running it.
#

$:.unshift File.expand_path "<%= standalone_path %>", __dir__

require "bundler/setup"
load File.expand_path "<%= executable_path %>", __dir__
Executable.standalone (428 bytes)   

christos

2024-02-04 19:30

manager   ~0004000

If you want so try to supply some magic for it, I will probably add it... Yes, it is quite complicated...

Issue History

Date Modified Username Field Change
2023-09-02 16:58 abathur New Issue
2023-09-02 16:58 abathur File Added: Executable
2023-09-02 16:58 abathur File Added: Executable.bundler
2023-09-02 16:58 abathur File Added: Executable.standalone
2024-02-04 19:29 christos Assigned To => christos
2024-02-04 19:29 christos Status new => assigned
2024-02-04 19:30 christos Status assigned => feedback
2024-02-04 19:30 christos Note Added: 0004000