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 all 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
264 changes: 264 additions & 0 deletions solutions/anand-kumar/src/diff_utility.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
require "ostruct"
require "./file_utilities"
require "./lcs"


EOL = "\n"


class FileDiff < LongestCommonSubsequence

@@hunk = Struct.new(:old_start, :old_end, :new_start, :new_end)
INSERT = '+'
DELETE = '-'
UNCHANGED = ' '

def generate(old_data, new_data, context_lines = 3)
# The method generates the unified format of diff.

old_data = old_data.lines()
new_data = new_data.lines()
hunks = get_hunks(old_data, new_data)
hunks_with_context = add_context_around_hunks(
hunks,
context_lines,
old_data.length(),
new_data.length(),
)
diff = String.new()
common_subsequence = get_lcs(old_data, new_data)
hunks_with_context.each do |hunk_with_context|
old_start = hunk_with_context.old_start
old_end = hunk_with_context.old_end
new_start = hunk_with_context.new_start
new_end = hunk_with_context.new_end
diff += get_context_header(hunk_with_context)
while (old_start <= old_end) || (new_start <= new_end)
if common_subsequence[old_start].nil?
diff += "#{DELETE}#{old_data[old_start - 1]}"
old_start += 1
elsif common_subsequence.index(new_start).nil?
diff += "#{INSERT}#{new_data[new_start - 1]}"
new_start += 1
else
diff += "#{UNCHANGED}#{old_data[old_start - 1]}"
old_start += 1
new_start += 1
end
end
end
return diff
end

def get_hunks(old_data, new_data)
common_subsequence = get_lcs(old_data, new_data)
hunks = []
old_start = 0
new_start = 0
common_subsequence.each_with_index do |value, position|
if value.nil?
next
end
if (position > old_start + 1) || (value > new_start + 1)
hunks << @@hunk.new(
old_start + 1,
position - 1,
new_start + 1,
value - 1,
)
end
old_start = position
new_start = value
end
return hunks
end

def add_context_around_hunks(
hunks,
context_lines,
old_data_length,
new_data_length
)
hunks_with_context = []

if not hunks.any?
return hunks_with_context
end

# Add context around each hunk.
hunks.each do |hunk|
old_start = hunk.old_start - 1
old_end = hunk.old_end + 1
new_start = hunk.new_start - 1
new_end = hunk.new_end + 1

# Context before the hunk.
(1..context_lines).each do
if (old_start < 1) || (new_start < 1)
break
end
hunk.old_start = old_start
hunk.new_start = new_start
old_start -= 1
new_start -= 1
end

# Context after the hunk.
(1..context_lines).each do
if (old_end > old_data_length) || (new_end > new_data_length)
break
end
hunk.old_end = old_end
hunk.new_end = new_end
old_end += 1
new_end += 1
end
end

# Merge hunks that have overlapping context.
hunks.each do |current_hunk|
if hunks_with_context.any?
previous_hunk = hunks_with_context.last()
if (
(previous_hunk.old_end < current_hunk.old_start) &&
(previous_hunk.new_end < current_hunk.new_start)
)
hunks_with_context << current_hunk
else
previous_hunk.old_end = current_hunk.old_end
previous_hunk.new_end = current_hunk.new_end
end
else
hunks_with_context << current_hunk
end
end
return hunks_with_context
end

def get_context_header(hunk)
old_hunk_length = hunk.old_end - hunk.old_start + 1
new_hunk_length = hunk.new_end - hunk.new_start + 1
header = String.new()
header += "@@ "
if old_hunk_length.zero?
header += "#{DELETE}#{hunk.old_start - 1}"
else
header += "#{DELETE}#{hunk.old_start}"
end
if old_hunk_length != 1
header += ",#{old_hunk_length}"
end
header += ' '
if new_hunk_length.zero?
header += "#{INSERT}#{hunk.new_start - 1}"
else
header += "#{INSERT}#{hunk.new_start}"
end
if new_hunk_length != 1
header += ",#{new_hunk_length}"
end
header += " @@#{EOL}"
return header
end
end


class DirectoryDiff

def generate(old_directory, new_directory)
hunks = get_changes_in_directory(old_directory, new_directory)
diff = String.new()
hunks.each do |hunk|
if hunk.old_file.nil?
diff += "Only in #{new_directory}: "\
"#{File.basename(hunk.new_file)}#{EOL}"
elsif hunk.new_file.nil?
diff += "Only in #{old_directory}: "\
"#{File.basename(hunk.old_file)}#{EOL}"
elsif (
(File.file? (hunk.old_file)) &&
(File.file? (hunk.new_file))
)
diff += "--- old/#{File.basename(hunk.old_file)} "\
"#{Time.now()}#{EOL}"
diff += "+++ new/#{File.basename(hunk.new_file)} "\
"#{Time.now()}#{EOL}"
diff += FileDiff.new().generate(
File.read(hunk.old_file),
File.read(hunk.new_file),
)
elsif File.file? (hunk.old_file)
diff += "File #{hunk.old_file} is a regular file "\
"while file #{hunk.new_file} is a directory#{EOL}"
else
diff += "File #{hunk.old_file} is a directory "\
"while file #{hunk.new_file} is a regular file#{EOL}"
end
end
return diff
end


def get_changes_in_directory(old_directory, new_directory)
old_files = FileUtilities.get_files(old_directory)
new_files = FileUtilities.get_files(new_directory)
hunks = []
ii = 0
jj = 0
while (ii < old_files.size()) || (jj < new_files.size())
if (
(ii < old_files.size()) &&
(jj < new_files.size()) &&
(old_files[ii] == new_files[jj])
)
old_file = File.join(old_directory, old_files[ii])
new_file = File.join(new_directory, new_files[jj])
if (File.file? (old_file)) && (File.file? (new_file))
diff = FileDiff.new().generate(
File.read(old_file),
File.read(new_file),
)
if not diff.empty?
hunks << modified(old_file, new_file)
end
elsif (
(File.directory? (old_file)) &&
(File.directory? (new_file))
)
hunks += generate(old_file, new_file)
else
hunks << modified(old_file, new_file)
end
ii += 1
jj += 1
elsif (ii < old_files.size()) && (jj < new_files.size())
if old_files[ii] < new_files[jj]
hunks << delete(File.join(old_directory, old_files[ii]))
ii += 1
else
hunks << insert(File.join(new_directory, new_files[jj]))
jj += 1
end
elsif ii < old_files.size()
hunks << delete(File.join(old_directory, old_files[ii]))
ii += 1
else
hunks << insert(File.join(new_directory, new_files[jj]))
jj += 1
end
end
return hunks
end

def insert(file)
return OpenStruct.new(old_file: nil, new_file: file)
end

def delete(file)
return OpenStruct.new(old_file: file, new_file: nil)
end

def modified(old_file, new_file)
return OpenStruct.new(old_file: old_file, new_file: new_file)
end
end
34 changes: 34 additions & 0 deletions solutions/anand-kumar/src/exceptions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
class VCSError < Exception

def initialize(message = nil)
super(message)
end

end


class ObjectFileError < VCSError

# The exception indicates that the object file may be missing or may have
# been corrupt or the data format(type of object) is not acceptable.
end


class MissingConfigParameter < VCSError

# The exception indicates that the config file does not
# contain the argument queried for.
end


class NotVCSRepository < VCSError

# The exception indicates that directory has not been initialized or
# is missing files within the .vcs directory.
end


class MissingCommitParameter < VCSError

# The exception indicates that the commit was missing message.
end
96 changes: 96 additions & 0 deletions solutions/anand-kumar/src/file_utilities.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
require 'digest/sha1'


module FileUtilities

BLOCK_SIZE = 1024

def self.concatenate(file1_path, file2_path, offset = 0)
# The content of file2 is concatenated to file1.

File.open(file1_path, 'ab') do |file1|
File.open(file2_path, 'rb') do |file2|
file2.seek(offset)
while true
data = file2.read(BLOCK_SIZE)
if data.nil?
break
end
file1.write(data)
end
end
end
end

def self.read(file_path, delimiter = '\n', offset = 0)
# The method returns the file content before the delimiter
# is encountered, if the delimiter (default: new line) is not present
# then it returns the entire content available.

content = String.new()
File.open(file_path, 'rb') do |file|
file.seek(offset)
while not content.include? delimiter
data = file.read(BLOCK_SIZE)
if data.nil?
break
end
content += data
end
end
content, _separator, _data = content.partition(delimiter)
return content
end

def self.split_into_lines(file_path, offset = 0)
lines = []
File.open(file_path, 'rb') do |file|
file.seek(offset)
while true
data = file.gets()
if data.nil?
break
end
lines << data
end
end
return lines
end

def self.write(file_path, data, mode = 'wb')
File.open(file_path, mode) {|file| file.write(data)}
end

def self.get_sha1_hash(header, file_path)
hash = Digest::SHA1.new()
hash.update(header)
open(file_path, 'rb') do |file|
while true
data = file.read(BLOCK_SIZE)
if data.nil?
break
end
hash.update(data)
end
end
return hash.hexdigest
end

def self.get_files(directory_path = Dir.getwd(), recursive = false)
# Returns the list of file paths, dot files are ignored.

files = []
original_path = Dir.getwd()
begin
Dir.chdir(directory_path)
if recursive
files = Dir["*/*"] - ['.', '..']
else
files = Dir["*"] - ['.', '..']
end
ensure
Dir.chdir(original_path)
end
return files
end
end
Loading