jit 0.0.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (95) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE.txt +674 -0
  3. data/bin/jit +21 -0
  4. data/lib/color.rb +32 -0
  5. data/lib/command.rb +62 -0
  6. data/lib/command/add.rb +65 -0
  7. data/lib/command/base.rb +92 -0
  8. data/lib/command/branch.rb +199 -0
  9. data/lib/command/checkout.rb +104 -0
  10. data/lib/command/cherry_pick.rb +51 -0
  11. data/lib/command/commit.rb +86 -0
  12. data/lib/command/config.rb +126 -0
  13. data/lib/command/diff.rb +114 -0
  14. data/lib/command/fetch.rb +116 -0
  15. data/lib/command/init.rb +41 -0
  16. data/lib/command/log.rb +188 -0
  17. data/lib/command/merge.rb +148 -0
  18. data/lib/command/push.rb +172 -0
  19. data/lib/command/receive_pack.rb +92 -0
  20. data/lib/command/remote.rb +55 -0
  21. data/lib/command/reset.rb +64 -0
  22. data/lib/command/rev_list.rb +33 -0
  23. data/lib/command/revert.rb +69 -0
  24. data/lib/command/rm.rb +105 -0
  25. data/lib/command/shared/fast_forward.rb +19 -0
  26. data/lib/command/shared/print_diff.rb +116 -0
  27. data/lib/command/shared/receive_objects.rb +37 -0
  28. data/lib/command/shared/remote_agent.rb +44 -0
  29. data/lib/command/shared/remote_client.rb +82 -0
  30. data/lib/command/shared/send_objects.rb +24 -0
  31. data/lib/command/shared/sequencing.rb +146 -0
  32. data/lib/command/shared/write_commit.rb +167 -0
  33. data/lib/command/status.rb +210 -0
  34. data/lib/command/upload_pack.rb +54 -0
  35. data/lib/config.rb +240 -0
  36. data/lib/config/stack.rb +42 -0
  37. data/lib/database.rb +112 -0
  38. data/lib/database/author.rb +27 -0
  39. data/lib/database/backends.rb +57 -0
  40. data/lib/database/blob.rb +24 -0
  41. data/lib/database/commit.rb +70 -0
  42. data/lib/database/entry.rb +7 -0
  43. data/lib/database/loose.rb +70 -0
  44. data/lib/database/packed.rb +75 -0
  45. data/lib/database/tree.rb +77 -0
  46. data/lib/database/tree_diff.rb +88 -0
  47. data/lib/diff.rb +46 -0
  48. data/lib/diff/combined.rb +72 -0
  49. data/lib/diff/hunk.rb +64 -0
  50. data/lib/diff/myers.rb +90 -0
  51. data/lib/editor.rb +59 -0
  52. data/lib/index.rb +212 -0
  53. data/lib/index/checksum.rb +44 -0
  54. data/lib/index/entry.rb +91 -0
  55. data/lib/lockfile.rb +55 -0
  56. data/lib/merge/bases.rb +38 -0
  57. data/lib/merge/common_ancestors.rb +77 -0
  58. data/lib/merge/diff3.rb +156 -0
  59. data/lib/merge/inputs.rb +42 -0
  60. data/lib/merge/resolve.rb +178 -0
  61. data/lib/pack.rb +45 -0
  62. data/lib/pack/compressor.rb +83 -0
  63. data/lib/pack/delta.rb +58 -0
  64. data/lib/pack/entry.rb +54 -0
  65. data/lib/pack/expander.rb +54 -0
  66. data/lib/pack/index.rb +100 -0
  67. data/lib/pack/indexer.rb +200 -0
  68. data/lib/pack/numbers.rb +79 -0
  69. data/lib/pack/reader.rb +98 -0
  70. data/lib/pack/stream.rb +80 -0
  71. data/lib/pack/unpacker.rb +62 -0
  72. data/lib/pack/window.rb +47 -0
  73. data/lib/pack/writer.rb +92 -0
  74. data/lib/pack/xdelta.rb +118 -0
  75. data/lib/pager.rb +24 -0
  76. data/lib/progress.rb +78 -0
  77. data/lib/refs.rb +260 -0
  78. data/lib/remotes.rb +82 -0
  79. data/lib/remotes/protocol.rb +82 -0
  80. data/lib/remotes/refspec.rb +70 -0
  81. data/lib/remotes/remote.rb +57 -0
  82. data/lib/repository.rb +64 -0
  83. data/lib/repository/divergence.rb +21 -0
  84. data/lib/repository/hard_reset.rb +35 -0
  85. data/lib/repository/inspector.rb +49 -0
  86. data/lib/repository/migration.rb +168 -0
  87. data/lib/repository/pending_commit.rb +60 -0
  88. data/lib/repository/sequencer.rb +118 -0
  89. data/lib/repository/status.rb +98 -0
  90. data/lib/rev_list.rb +244 -0
  91. data/lib/revision.rb +155 -0
  92. data/lib/sorted_hash.rb +17 -0
  93. data/lib/temp_file.rb +34 -0
  94. data/lib/workspace.rb +107 -0
  95. metadata +103 -9
@@ -0,0 +1,118 @@
1
+ module Pack
2
+ class XDelta
3
+
4
+ BLOCK_SIZE = 16
5
+
6
+ def self.create_index(source)
7
+ blocks = source.bytesize / BLOCK_SIZE
8
+ index = {}
9
+
10
+ (0 ... blocks).each do |i|
11
+ offset = i * BLOCK_SIZE
12
+ slice = source.byteslice(offset, BLOCK_SIZE)
13
+
14
+ index[slice] ||= []
15
+ index[slice].push(offset)
16
+ end
17
+
18
+ new(source, index)
19
+ end
20
+
21
+ def initialize(source, index)
22
+ @source = source
23
+ @index = index
24
+ end
25
+
26
+ def compress(target)
27
+ @target = target
28
+ @offset = 0
29
+ @insert = []
30
+ @ops = []
31
+
32
+ generate_ops while @offset < @target.bytesize
33
+ flush_insert
34
+
35
+ @ops
36
+ end
37
+
38
+ private
39
+
40
+ def generate_ops
41
+ m_offset, m_size = longest_match
42
+ return push_insert if m_size == 0
43
+
44
+ m_offset, m_size = expand_match(m_offset, m_size)
45
+
46
+ flush_insert
47
+ @ops.push(Delta::Copy.new(m_offset, m_size))
48
+ end
49
+
50
+ def longest_match
51
+ slice = @target.byteslice(@offset, BLOCK_SIZE)
52
+ return [0, 0] unless @index.has_key?(slice)
53
+
54
+ m_offset = m_size = 0
55
+
56
+ @index[slice].each do |pos|
57
+ remaining = remaining_bytes(pos)
58
+ break if remaining <= m_size
59
+
60
+ s = match_from(pos, remaining)
61
+ next if m_size >= s - pos
62
+
63
+ m_offset = pos
64
+ m_size = s - pos
65
+ end
66
+
67
+ [m_offset, m_size]
68
+ end
69
+
70
+ def remaining_bytes(pos)
71
+ source_remaining = @source.bytesize - pos
72
+ target_remaining = @target.bytesize - @offset
73
+
74
+ [source_remaining, target_remaining, MAX_COPY_SIZE].min
75
+ end
76
+
77
+ def match_from(pos, remaining)
78
+ s, t = pos, @offset
79
+
80
+ while remaining > 0 and @source.getbyte(s) == @target.getbyte(t)
81
+ s, t = s + 1, t + 1
82
+ remaining -= 1
83
+ end
84
+
85
+ s
86
+ end
87
+
88
+ def expand_match(m_offset, m_size)
89
+ while m_offset > 0 and @source.getbyte(m_offset - 1) == @insert.last
90
+ break if m_size == MAX_COPY_SIZE
91
+
92
+ @offset -= 1
93
+ m_offset -= 1
94
+ m_size += 1
95
+
96
+ @insert.pop
97
+ end
98
+
99
+ @offset += m_size
100
+ [m_offset, m_size]
101
+ end
102
+
103
+ def push_insert
104
+ @insert.push(@target.getbyte(@offset))
105
+ @offset += 1
106
+ flush_insert(MAX_INSERT_SIZE)
107
+ end
108
+
109
+ def flush_insert(size = nil)
110
+ return if size and @insert.size < size
111
+ return if @insert.empty?
112
+
113
+ @ops.push(Delta::Insert.new(@insert.pack("C*")))
114
+ @insert = []
115
+ end
116
+
117
+ end
118
+ end
@@ -0,0 +1,24 @@
1
+ class Pager
2
+ PAGER_CMD = "less"
3
+ PAGER_ENV = { "LESS" => "FRX", "LV" => "-c" }
4
+
5
+ attr_reader :input
6
+
7
+ def initialize(env = {}, stdout = $stdout, stderr = $stderr)
8
+ env = PAGER_ENV.merge(env)
9
+ cmd = env["GIT_PAGER"] || env["PAGER"] || PAGER_CMD
10
+
11
+ reader, writer = IO.pipe
12
+ options = { :in => reader, :out => stdout, :err => stderr }
13
+
14
+ @pid = Process.spawn(env, cmd, options)
15
+ @input = writer
16
+
17
+ reader.close
18
+ end
19
+
20
+ def wait
21
+ Process.waitpid(@pid) if @pid
22
+ @pid = nil
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ class Progress
2
+ UNITS = ["B", "KiB", "MiB", "GiB"]
3
+ SCALE = 1024.0
4
+
5
+ def initialize(output)
6
+ @output = output
7
+ @message = nil
8
+ end
9
+
10
+ def start(message, total = nil)
11
+ return if ENV["NO_PROGRESS"] or not @output.isatty
12
+
13
+ @message = message
14
+ @total = total
15
+ @count = 0
16
+ @bytes = 0
17
+ @write_at = get_time
18
+ end
19
+
20
+ def tick(bytes = 0)
21
+ return unless @message
22
+
23
+ @count += 1
24
+ @bytes = bytes
25
+
26
+ current_time = get_time
27
+ return if current_time < @write_at + 0.05
28
+ @write_at = current_time
29
+
30
+ clear_line
31
+ @output.write(status_line)
32
+ end
33
+
34
+ def stop
35
+ return unless @message
36
+
37
+ @total = @count
38
+
39
+ clear_line
40
+ @output.puts(status_line)
41
+ @message = nil
42
+ end
43
+
44
+ private
45
+
46
+ def get_time
47
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
48
+ end
49
+
50
+ def clear_line
51
+ @output.write("\e[G\e[K")
52
+ end
53
+
54
+ def status_line
55
+ line = "#{ @message }: #{ format_count }"
56
+
57
+ line.concat(", #{ format_bytes }") if @bytes > 0
58
+ line.concat(", done.") if @count == @total
59
+
60
+ line
61
+ end
62
+
63
+ def format_count
64
+ if @total
65
+ percent = (@total == 0) ? 100 : 100 * @count / @total
66
+ "#{ percent }% (#{ @count }/#{ @total })"
67
+ else
68
+ "(#{ @count })"
69
+ end
70
+ end
71
+
72
+ def format_bytes
73
+ power = Math.log(@bytes, SCALE).floor
74
+ scaled = @bytes / (SCALE ** power)
75
+
76
+ format("%.2f #{ UNITS[power] }", scaled)
77
+ end
78
+ end
@@ -0,0 +1,260 @@
1
+ require "fileutils"
2
+ require "pathname"
3
+
4
+ require_relative "./lockfile"
5
+ require_relative "./revision"
6
+
7
+ class Refs
8
+ InvalidBranch = Class.new(StandardError)
9
+ StaleValue = Class.new(StandardError)
10
+
11
+ SymRef = Struct.new(:refs, :path) do
12
+ def read_oid
13
+ refs.read_ref(path)
14
+ end
15
+
16
+ def head?
17
+ path == HEAD
18
+ end
19
+
20
+ def branch?
21
+ path.start_with?("refs/heads/")
22
+ end
23
+
24
+ def remote?
25
+ path.start_with?("refs/remotes/")
26
+ end
27
+
28
+ def short_name
29
+ refs.short_name(path)
30
+ end
31
+ end
32
+
33
+ Ref = Struct.new(:oid) do
34
+ def read_oid
35
+ oid
36
+ end
37
+ end
38
+
39
+ HEAD = "HEAD"
40
+ ORIG_HEAD = "ORIG_HEAD"
41
+ SYMREF = /^ref: (.+)$/
42
+
43
+ REFS_DIR = Pathname.new("refs")
44
+ HEADS_DIR = REFS_DIR.join("heads")
45
+ REMOTES_DIR = REFS_DIR.join("remotes")
46
+
47
+ def initialize(pathname)
48
+ @pathname = pathname
49
+ @refs_path = @pathname.join(REFS_DIR)
50
+ @heads_path = @pathname.join(HEADS_DIR)
51
+ @remotes_path = @pathname.join(REMOTES_DIR)
52
+ end
53
+
54
+ def read_head
55
+ read_symref(@pathname.join(HEAD))
56
+ end
57
+
58
+ def update_head(oid)
59
+ update_symref(@pathname.join(HEAD), oid)
60
+ end
61
+
62
+ def set_head(revision, oid)
63
+ head = @pathname.join(HEAD)
64
+ path = @heads_path.join(revision)
65
+
66
+ if File.file?(path)
67
+ relative = path.relative_path_from(@pathname)
68
+ update_ref_file(head, "ref: #{ relative }")
69
+ else
70
+ update_ref_file(head, oid)
71
+ end
72
+ end
73
+
74
+ def read_ref(name)
75
+ path = path_for_name(name)
76
+ path ? read_symref(path) : nil
77
+ end
78
+
79
+ def update_ref(name, oid)
80
+ update_ref_file(@pathname.join(name), oid)
81
+ end
82
+
83
+ def compare_and_swap(name, old_oid, new_oid)
84
+ path = @pathname.join(name)
85
+
86
+ update_ref_file(path, new_oid) do
87
+ unless old_oid == read_symref(path)
88
+ raise StaleValue, "value of #{ name } changed since last read"
89
+ end
90
+ end
91
+ end
92
+
93
+ def create_branch(branch_name, start_oid)
94
+ path = @heads_path.join(branch_name)
95
+
96
+ unless Revision.valid_ref?(branch_name)
97
+ raise InvalidBranch, "'#{ branch_name }' is not a valid branch name."
98
+ end
99
+
100
+ if File.file?(path)
101
+ raise InvalidBranch, "A branch named '#{ branch_name }' already exists."
102
+ end
103
+
104
+ FileUtils.mkdir_p(path.dirname)
105
+ update_ref_file(path, start_oid)
106
+ end
107
+
108
+ def delete_branch(branch_name)
109
+ path = @heads_path.join(branch_name)
110
+
111
+ lockfile = Lockfile.new(path)
112
+ lockfile.hold_for_update
113
+
114
+ oid = read_symref(path)
115
+ raise InvalidBranch, "branch '#{ branch_name }' not found." unless oid
116
+
117
+ File.unlink(path)
118
+ oid
119
+ ensure
120
+ lockfile.rollback
121
+ end
122
+
123
+ def current_ref(source = HEAD)
124
+ ref = read_oid_or_symref(@pathname.join(source))
125
+
126
+ case ref
127
+ when SymRef then current_ref(ref.path)
128
+ when Ref, nil then SymRef.new(self, source)
129
+ end
130
+ end
131
+
132
+ def list_all_refs
133
+ [SymRef.new(self, HEAD)] + list_refs(@refs_path)
134
+ end
135
+
136
+ def list_branches
137
+ list_refs(@heads_path)
138
+ end
139
+
140
+ def list_remotes
141
+ list_refs(@remotes_path)
142
+ end
143
+
144
+ def reverse_refs
145
+ table = Hash.new { |hash, key| hash[key] = [] }
146
+
147
+ list_all_refs.each do |ref|
148
+ oid = ref.read_oid
149
+ table[oid].push(ref) if oid
150
+ end
151
+
152
+ table
153
+ end
154
+
155
+ def short_name(path)
156
+ path = @pathname.join(path)
157
+
158
+ prefix = [@remotes_path, @heads_path, @pathname].find do |dir|
159
+ path.dirname.ascend.any? { |parent| parent == dir }
160
+ end
161
+
162
+ path.relative_path_from(prefix).to_s
163
+ end
164
+
165
+ def long_name(ref)
166
+ path = path_for_name(ref)
167
+ return path.relative_path_from(@pathname).to_s if path
168
+
169
+ raise InvalidBranch,
170
+ "the requested upstream branch '#{ ref }' does not exist"
171
+ end
172
+
173
+ private
174
+
175
+ def list_refs(dirname)
176
+ names = Dir.entries(dirname) - [".", ".."]
177
+
178
+ names.map { |name| dirname.join(name) }.flat_map do |path|
179
+ if File.directory?(path)
180
+ list_refs(path)
181
+ else
182
+ path = path.relative_path_from(@pathname)
183
+ SymRef.new(self, path.to_s)
184
+ end
185
+ end
186
+
187
+ rescue Errno::ENOENT
188
+ []
189
+ end
190
+
191
+ def path_for_name(name)
192
+ prefixes = [@pathname, @refs_path, @heads_path, @remotes_path]
193
+ prefix = prefixes.find { |path| File.file? path.join(name) }
194
+
195
+ prefix ? prefix.join(name) : nil
196
+ end
197
+
198
+ def read_oid_or_symref(path)
199
+ data = File.read(path).strip
200
+ match = SYMREF.match(data)
201
+
202
+ match ? SymRef.new(self, match[1]) : Ref.new(data)
203
+ rescue Errno::ENOENT
204
+ nil
205
+ end
206
+
207
+ def read_symref(path)
208
+ ref = read_oid_or_symref(path)
209
+
210
+ case ref
211
+ when SymRef then read_symref(@pathname.join(ref.path))
212
+ when Ref then ref.oid
213
+ end
214
+ end
215
+
216
+ def update_ref_file(path, oid)
217
+ lockfile = Lockfile.new(path)
218
+
219
+ lockfile.hold_for_update
220
+ yield if block_given?
221
+
222
+ if oid
223
+ write_lockfile(lockfile, oid)
224
+ else
225
+ File.unlink(path) rescue Errno::ENOENT
226
+ lockfile.rollback
227
+ end
228
+
229
+ rescue Lockfile::MissingParent
230
+ FileUtils.mkdir_p(path.dirname)
231
+ retry
232
+ rescue => error
233
+ lockfile.rollback
234
+ raise error
235
+ end
236
+
237
+ def update_symref(path, oid)
238
+ lockfile = Lockfile.new(path)
239
+ lockfile.hold_for_update
240
+
241
+ ref = read_oid_or_symref(path)
242
+
243
+ unless ref.is_a?(SymRef)
244
+ write_lockfile(lockfile, oid)
245
+ return ref&.oid
246
+ end
247
+
248
+ begin
249
+ update_symref(@pathname.join(ref.path), oid)
250
+ ensure
251
+ lockfile.rollback
252
+ end
253
+ end
254
+
255
+ def write_lockfile(lockfile, oid)
256
+ lockfile.write(oid)
257
+ lockfile.write("\n")
258
+ lockfile.commit
259
+ end
260
+ end