summaryrefslogtreecommitdiff
path: root/lib/gitlab/ci/trace_reader.rb
blob: 1d7ddeb3e0f02277e6ef9c2ffa20e0373e4c42dd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
module Gitlab
  module Ci
    # This was inspired from: http://stackoverflow.com/a/10219411/1520132
    class TraceReader
      BUFFER_SIZE = 4096

      attr_accessor :path, :buffer_size

      def initialize(new_path, buffer_size: BUFFER_SIZE)
        self.path = new_path
        self.buffer_size = Integer(buffer_size)
      end

      def read(last_lines: nil)
        if last_lines
          read_last_lines(last_lines)
        else
          File.read(path)
        end
      end

      def read_last_lines(max_lines)
        File.open(path) do |file|
          chunks = []
          pos = lines = 0
          max = file.size

          # We want an extra line to make sure fist line has full contents
          while lines <= max_lines && pos < max
            pos += buffer_size

            buf = if pos <= max
                    file.seek(-pos, IO::SEEK_END)
                    file.read(buffer_size)
                  else # Reached the head, read only left
                    file.seek(0)
                    file.read(buffer_size - (pos - max))
                  end

            lines += buf.count("\n")
            chunks.unshift(buf)
          end

          chunks.join.lines.last(max_lines).join
            .force_encoding(Encoding.default_external)
        end
      end
    end
  end
end