Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

version-control-system #45

Closed
Closed
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
8545230
Create vcs.md
iamanandkr Jul 16, 2017
31bc7b1
Create vcs.rb
iamanandkr Aug 16, 2017
30df542
Create vcs_internals.rb
iamanandkr Aug 16, 2017
4c05fbf
Create blob.rb
iamanandkr Aug 16, 2017
d7d87d0
Create tree.rb
iamanandkr Aug 16, 2017
5332694
Create commit.rb
iamanandkr Aug 16, 2017
d1f1658
Create diff-utility.rb
iamanandkr Aug 16, 2017
338179b
Update vcs.rb
iamanandkr Aug 16, 2017
4bfc151
Update vcs.rb
iamanandkr Aug 29, 2017
d95ac6b
Update vcs_internals.rb
iamanandkr Aug 29, 2017
0bfea34
Create file_storage.rb
iamanandkr Aug 29, 2017
d4bb34e
Delete blob.rb
iamanandkr Aug 29, 2017
4c00cc7
Delete commit.rb
iamanandkr Aug 29, 2017
c42013e
Delete tree.rb
iamanandkr Aug 29, 2017
f062559
Update vcs_internals.rb
iamanandkr Aug 29, 2017
4a923c2
Update vcs_internals.rb
iamanandkr Aug 29, 2017
64d6b09
Update diff-utility.rb
iamanandkr Aug 29, 2017
1fe0d6f
Create vcs_test.rb
iamanandkr Aug 31, 2017
4fd8216
Update vcs.rb
iamanandkr Oct 3, 2017
b9b2cf3
Update vcs_internals.rb
iamanandkr Oct 3, 2017
fe852d3
Update file_storage.rb
iamanandkr Oct 3, 2017
147ee00
Update diff-utility.rb
iamanandkr Oct 3, 2017
c7ab2ad
Create lcs.rb
iamanandkr Oct 25, 2017
7829c50
Create file_diff.rb
iamanandkr Oct 25, 2017
73c03a2
Delete diff-utility.rb
iamanandkr Oct 29, 2017
bc025fe
Update file_diff.rb
iamanandkr Oct 29, 2017
4dc4f10
Rename file_diff.rb to diff_utility.rb
iamanandkr Oct 29, 2017
293ebfa
Update and rename file_storage.rb to vcs_objects.rb
iamanandkr Oct 29, 2017
d53985d
Update vcs.rb
iamanandkr Oct 29, 2017
256db12
Delete vcs_internals.rb
iamanandkr Oct 29, 2017
31bdf8e
Create vcs_commands.rb
iamanandkr Oct 29, 2017
a71f996
Create exceptions.rb
iamanandkr Oct 29, 2017
d0325b2
Create file_utilities.rb
iamanandkr Oct 29, 2017
b4aca5f
Update vcs_commands.rb
iamanandkr Oct 29, 2017
312f476
Changes to be committed:
iamanandkr Oct 31, 2017
a89399d
Update vcs.rb
iamanandkr Oct 31, 2017
398bed5
Update diff_utility.rb
iamanandkr Oct 31, 2017
cce4e35
Update file_utilities.rb
iamanandkr Oct 31, 2017
4f2a6f3
Update vcs_internals.rb
iamanandkr Oct 31, 2017
5710482
Update vcs.rb
iamanandkr Oct 31, 2017
34900b6
Update vcs_objects.rb
iamanandkr Oct 31, 2017
0c4c349
Update vcs.rb
iamanandkr Oct 31, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
223 changes: 223 additions & 0 deletions solutions/anand-kumar/src/diff-utility.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
require_relative 'vcs_internals'


NodeValue = Struct.new(:key, :parent_x, :parent_y)


def get_lines(input_file_path)
lines = []
open(input_file_path, "r") do |input_file|
while true
data = input_file.gets
if data.nil?
break
end
lines.push(data)
end
end
return lines
end


def get_lcs(old_lines, new_lines)
lcs = Array.new(old_lines.length + 1) \
{Array.new(new_lines.length + 1, NodeValue.new(0, 0, 0))}
for ii in (1..old_lines.length)
for jj in (1..new_lines.length)
if old_lines[ii - 1] == new_lines[jj - 1]
lcs[ii][jj] = NodeValue.new(
lcs[ii - 1][jj - 1].key + 1,
ii - 1,
jj - 1,
)
else
lcs[ii][jj] = NodeValue.new(lcs[ii][jj - 1].key, ii, jj - 1)
if lcs[ii - 1][jj].key > lcs[ii][jj].key
lcs[ii][jj].key = lcs[ii - 1][jj].key
lcs[ii][jj].parent_x = ii - 1
lcs[ii][jj].parent_y = jj
end
end
end
end
equivalent_line_in_new_file = Array.new(old_lines.length + 1, 0)
equivalent_line_in_old_file = Array.new(new_lines.length + 1, 0)
current_x = old_lines.length
current_y = new_lines.length
while current_x != 0 || current_y != 0
parent_x = lcs[current_x][current_y].parent_x
parent_y = lcs[current_x][current_y].parent_y
if current_x - 1 == parent_x && current_y - 1 == parent_y
equivalent_line_in_new_file[current_x] = current_y
equivalent_line_in_old_file[current_y] = current_x
end
current_x = parent_x
current_y = parent_y
end
return equivalent_line_in_new_file, equivalent_line_in_old_file
end


def display_diff_delete(lines, lcs, index, line_new)
start_index = index
end_index = index
index += 1
while index <= lines.length && lcs[index] == 0
end_index += 1
index += 1
end
if start_index == end_index
puts "#{start_index}d#{line_new}"
puts "< #{lines[start_index - 1]}"
else
puts "#{start_index},#{end_index}d#{line_new}"
while start_index <= end_index
puts "< #{lines[start_index - 1]}"
start_index += 1
end
end
return index
end


def display_diff_append(lines, lcs, index, line_old, line_new)
line_new += 1
start_index = index
end_index = index
index += 1
while index <= lines.length && lcs[index] == 0
index += 1
end_index += 1
end
if start_index == end_index
puts "#{line_old}a#{line_new}"
puts "> #{lines[start_index - 1]}"
else
puts "#{line_old}a#{line_new},#{line_new + (end_index - start_index)}"
line_new += (end_index - start_index)
while start_index <= end_index
puts "> #{lines[start_index - 1]}"
start_index += 1
end
end
return index, line_new
end


def display_diff_change(
old_lines,
new_lines,
equivalent_line_in_new_file,
equivalent_line_in_old_file,
start_old_index,
start_new_index,
line_new
)
line_new += 1
start_old = start_old_index
start_new = start_new_index
end_old = start_old_index
end_new = start_new_index

start_old_index += 1
start_new_index += 1
while (
start_old_index <= old_lines.length &&
start_new_index <= new_lines.length &&
equivalent_line_in_new_file[start_old_index] == 0 &&
equivalent_line_in_old_file[start_new_index] == 0
)
start_old_index += 1
end_old += 1
start_new_index += 1
end_new += 1
end
if start_old == end_old
puts "#{start_old}c#{line_new}"
puts "< #{old_lines[start_old - 1]}"
puts "---"
puts "> #{new_lines[start_new - 1]}"
else
print "#{start_old},#{end_old}c#{line_new},"
print "#{line_new + (end_old - start_old)}\n"
line_new += (end_old - start_old)
while start_old <= end_old
puts "< #{old_lines[start_old - 1]}"
start_old += 1
end
puts "---"
while start_new <= end_new
puts "> #{new_lines[start_new - 1]}"
start_new += 1
end
end
return start_old_index, start_new_index, line_new
end


def find_diff(file1, file2)
old_lines = []
new_lines = []
if File.file?(file1)
old_lines = get_lines(file1)
else
old_lines.push(file1)
end
if File.file?(file2)
new_lines = get_lines(file2)
else
new_lines.push(file2)
end
equivalent_line_in_new_file, equivalent_line_in_old_file = \
get_lcs(old_lines, new_lines)
line_number_new = 0
old_index = 1
new_index = 1
while old_index <= old_lines.length || new_index <= new_lines.length
if (
equivalent_line_in_new_file[old_index] == 0 &&
(
new_index > new_lines.length ||
equivalent_line_in_old_file[new_index] != 0
)
)
old_index = display_diff_delete(
old_lines,
equivalent_line_in_new_file,
old_index,
line_number_new,
)
elsif (
equivalent_line_in_old_file[new_index] == 0 &&
(
old_index > old_lines.length ||
equivalent_line_in_new_file[old_index] != 0
)
)
new_index, line_number_new = display_diff_append(
new_lines,
equivalent_line_in_old_file,
new_index,
old_index - 1,
line_number_new,
)
elsif (
equivalent_line_in_new_file[old_index] == 0 &&
equivalent_line_in_old_file[new_index] == 0
)
old_index, new_index, line_number_new = display_diff_change(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO display_diff_change can handle the display_diff_append/display_diff_delete cases too, so you shouldn't need them.

old_lines,
new_lines,
equivalent_line_in_new_file,
equivalent_line_in_old_file,
old_index,
new_index,
line_number_new,
)
else equivalent_line_in_old_file[new_index] == old_index
line_number_new += 1
old_index += 1
new_index += 1
end
end
end
161 changes: 161 additions & 0 deletions solutions/anand-kumar/src/file_storage.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
require 'fileutils'
require_relative 'vcs_internals'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is non-intuitive that a module called "file storage" depends on "vcs". Might want to rename this to "vcs-objects" or something.



SHA_SIZE = 40


class Blob

def self.create_blob(content_file_path)
header = "blob #{File.size(content_file_path)}#{NULL}"
sha_hash = get_sha_hash(header, content_file_path)
create_object_file(header, content_file_path, sha_hash)
return sha_hash
end

def self.restore_blob(sha_hash, output_file_path)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ehh ... using static methods defeats the point of objects too.
blob = Blob.create(content); Blob(hash).restore() is how this should look.

input_file_path = File.join(FilePath::OBJECTS, sha_hash)
open(input_file_path, "r") do |input_file|
open(output_file_path, "w") do |output_file|
data = ""
_header, data = extract_header(input_file)
output_file.write(data)
while true
data = input_file.read(BLOCK_SIZE)
if data.nil?
break
end
output_file.write(data)
end
end
end
end
end


class Tree

def self.build_tree(directory_path)
files = {}
for element in Dir.glob(File.join(directory_path, '*'))
file_name = File.basename(element)
if File.file?(element)
sha_hash = Blob.create_blob(element)
files[file_name] = sha_hash
else
sha_hash = Tree.build_tree(element)
files[file_name] = sha_hash
end
end
content = ""
files.each do |file_name, sha_hash|
content = content + file_name + NULL + sha_hash
end
header = "tree #{content.length}#{NULL}"
sha_hash = get_sha_hash(header, content)
create_object_file(header, content, sha_hash)
return sha_hash
end

def self.build_working_directory(sha_hash, directory_path)
files = Tree.get_directory_content(sha_hash)
files.each do |file_name, sha_hash|
if type(sha_hash).eql? "blob"
restore_blob(sha_hash, File.join(directory_path, file_name))
else
Dir.mkdir(File.join(directory_path, file_name))
build_working_directory(
sha_hash,
File.join(directory_path, file_name),
)
end
end
end

def self.get_directory_content(sha_hash)
input_file_path = File.join(FilePath::OBJECTS, sha_hash)
header = nil
files = {}
open(input_file_path, "r") do |input_file|
data = ""
header, data = extract_header(input_file)
while true
while not data.include? NULL
current_data = input_file.read(BLOCK_SIZE)
if current_data.nil?
break
end
data += current_data
end
if data.empty?
break
end
file_name, _separator, data = data.partition(NULL)
while data.length < SHA_SIZE
current_data = input_file.read(BLOCK_SIZE)
if current_data.nil?
break
end
data += current_data
end
file_sha_hash = data[0,SHA_SIZE]
data = data[SHA_SIZE..-1]
files[file_name] = file_sha_hash
end
end
return files
end
end


class Commit

def self.create_commit(commit_message, parent)
config_parameters = {}
open(FilePath::CONFIG, "r") do |config_file|
while true
data = config_file.gets
if data.nil?
break
end
key, _separator, value = data.partition(':')
config_parameters[key] = value
end
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading config should probably be through API methods on a VCS class, instead of reading the file directly.

header = ""
content = ""
content = "sha:#{Tree.build_tree(Dir.getwd)}#{EOL}"
content += "parent:#{parent}#{EOL}"
content += "author:#{config_parameters.fetch("author")}#{EOL}"
content += "email:#{config_parameters.fetch("email")}#{EOL}"
content += "time:#{Time.now}#{EOL}"
content += "message:#{commit_message}"
header = "commit #{content.length}#{NULL}"
commit_hash = get_sha_hash(header, content)
create_object_file(header, content, commit_hash)
return commit_hash
end

def self.parse_commit_object(commit_hash)
content = {}
input_file_path = File.join(FilePath::OBJECTS, commit_hash)
open(input_file_path, "r") do |input_file|
data = ""
_header, data = extract_header(input_file)
while true
current_data = input_file.read(BLOCK_SIZE)
if current_data.nil?
break
end
data += current_data
end
data = data.split(EOL)
for parameter in data
key, _separator, value = parameter.partition(':')
content[key] = value
end
end
return content
end
end
Loading