gist-logs: truncate log files to be gist-friendly (#279)
Truncates each log file to about 1 MB. This avoids upload and download errors with the gists, and respects GitHub's suggested size limits.
This commit is contained in:
		
							parent
							
								
									1b1bf56733
								
							
						
					
					
						commit
						f518f57bd8
					
				@ -91,6 +91,9 @@ module Homebrew
 | 
			
		||||
    logs = {}
 | 
			
		||||
    dir.children.sort.each do |file|
 | 
			
		||||
      contents = file.size? ? file.read : "empty log"
 | 
			
		||||
      # small enough to avoid GitHub "unicorn" page-load-timeout errors
 | 
			
		||||
      max_file_size = 1_000_000
 | 
			
		||||
      contents = truncate_text_to_approximate_size(contents, max_file_size, :front_weight => 0.2)
 | 
			
		||||
      logs[file.basename.to_s] = { :content => contents }
 | 
			
		||||
    end if dir.exist?
 | 
			
		||||
    raise "No logs." if logs.empty?
 | 
			
		||||
 | 
			
		||||
@ -45,10 +45,6 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
  HOMEBREW_TAP_REGEX = %r{^([\w-]+)/homebrew-([\w-]+)$}
 | 
			
		||||
 | 
			
		||||
  def ruby_has_encoding?
 | 
			
		||||
    String.method_defined?(:force_encoding)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  if ruby_has_encoding?
 | 
			
		||||
    def fix_encoding!(str)
 | 
			
		||||
      # Assume we are starting from a "mostly" UTF-8 string
 | 
			
		||||
@ -1032,13 +1028,7 @@ module Homebrew
 | 
			
		||||
 | 
			
		||||
      # Truncate to 1MB to avoid hitting CI limits
 | 
			
		||||
      if output.bytesize > MAX_STEP_OUTPUT_SIZE
 | 
			
		||||
        if ruby_has_encoding?
 | 
			
		||||
          binary_output = output.force_encoding("BINARY")
 | 
			
		||||
          output = binary_output.slice(-MAX_STEP_OUTPUT_SIZE, MAX_STEP_OUTPUT_SIZE)
 | 
			
		||||
          fix_encoding!(output)
 | 
			
		||||
        else
 | 
			
		||||
          output = output.slice(-MAX_STEP_OUTPUT_SIZE, MAX_STEP_OUTPUT_SIZE)
 | 
			
		||||
        end
 | 
			
		||||
        output = truncate_text_to_approximate_size(output, MAX_STEP_OUTPUT_SIZE, :front_weight => 0.0)
 | 
			
		||||
        output = "truncated output to 1MB:\n" + output
 | 
			
		||||
      end
 | 
			
		||||
    end
 | 
			
		||||
 | 
			
		||||
@ -210,4 +210,17 @@ class UtilTests < Homebrew::TestCase
 | 
			
		||||
    assert_equal "1,000", number_readable(1_000)
 | 
			
		||||
    assert_equal "1,000,000", number_readable(1_000_000)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
  def test_truncate_text_to_approximate_size
 | 
			
		||||
    glue = "\n[...snip...]\n" # hard-coded copy from truncate_text_to_approximate_size
 | 
			
		||||
    n = 20
 | 
			
		||||
    long_s = "x" * 40
 | 
			
		||||
    s = truncate_text_to_approximate_size(long_s, n)
 | 
			
		||||
    assert_equal n, s.length
 | 
			
		||||
    assert_match(/^x+#{Regexp.escape(glue)}x+$/, s)
 | 
			
		||||
    s = truncate_text_to_approximate_size(long_s, n, :front_weight => 0.0)
 | 
			
		||||
    assert_equal glue + ("x" * (n - glue.length)), s
 | 
			
		||||
    s = truncate_text_to_approximate_size(long_s, n, :front_weight => 1.0)
 | 
			
		||||
    assert_equal(("x" * (n - glue.length)) + glue, s)
 | 
			
		||||
  end
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
@ -534,3 +534,49 @@ def number_readable(number)
 | 
			
		||||
  (numstr.size - 3).step(1, -3) { |i| numstr.insert(i, ",") }
 | 
			
		||||
  numstr
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# True if this version of Ruby supports text encodings in its strings
 | 
			
		||||
def ruby_has_encoding?
 | 
			
		||||
  String.method_defined?(:force_encoding)
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
# Truncates a text string to fit within a byte size constraint,
 | 
			
		||||
# preserving character encoding validity. The returned string will
 | 
			
		||||
# be not much longer than the specified max_bytes, though the exact
 | 
			
		||||
# shortfall or overrun may vary.
 | 
			
		||||
def truncate_text_to_approximate_size(s, max_bytes, options = {})
 | 
			
		||||
  front_weight = options.fetch(:front_weight, 0.5)
 | 
			
		||||
  if front_weight < 0.0 || front_weight > 1.0
 | 
			
		||||
    raise "opts[:front_weight] must be between 0.0 and 1.0"
 | 
			
		||||
  end
 | 
			
		||||
  return s if s.bytesize <= max_bytes
 | 
			
		||||
 | 
			
		||||
  glue = "\n[...snip...]\n"
 | 
			
		||||
  max_bytes_in = [max_bytes - glue.bytesize, 1].max
 | 
			
		||||
  if ruby_has_encoding?
 | 
			
		||||
    bytes = s.dup.force_encoding("BINARY")
 | 
			
		||||
    glue_bytes = glue.encode("BINARY")
 | 
			
		||||
  else
 | 
			
		||||
    bytes = s
 | 
			
		||||
    glue_bytes = glue
 | 
			
		||||
  end
 | 
			
		||||
  n_front_bytes = (max_bytes_in * front_weight).floor
 | 
			
		||||
  n_back_bytes = max_bytes_in - n_front_bytes
 | 
			
		||||
  if n_front_bytes == 0
 | 
			
		||||
    front = bytes[1..0]
 | 
			
		||||
    back = bytes[-max_bytes_in..-1]
 | 
			
		||||
  elsif n_back_bytes == 0
 | 
			
		||||
    front = bytes[0..(max_bytes_in - 1)]
 | 
			
		||||
    back = bytes[1..0]
 | 
			
		||||
  else
 | 
			
		||||
    front = bytes[0..(n_front_bytes - 1)]
 | 
			
		||||
    back = bytes[-n_back_bytes..-1]
 | 
			
		||||
  end
 | 
			
		||||
  out = front + glue_bytes + back
 | 
			
		||||
  if ruby_has_encoding?
 | 
			
		||||
    out.force_encoding("UTF-8")
 | 
			
		||||
    out.encode!("UTF-16", :invalid => :replace)
 | 
			
		||||
    out.encode!("UTF-8")
 | 
			
		||||
  end
 | 
			
		||||
  out
 | 
			
		||||
end
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user