vcs_toolkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ module VCSToolkit
2
+ module Serializable
3
+ def serialize_on(*attributes)
4
+ define_method :to_hash do
5
+ attribute_values = attributes.map { |attribute| public_send attribute }
6
+
7
+ Hash[attributes.zip(attribute_values)]
8
+ end
9
+ end
10
+
11
+ def from_hash(hash, **other_args)
12
+ kwargs = {}
13
+
14
+ hash.each do |key, value|
15
+ kwargs[key.to_sym] = value
16
+ end
17
+
18
+ kwargs.merge! other_args
19
+
20
+ new **kwargs
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,45 @@
1
+ module VCSToolkit
2
+ module Utils
3
+
4
+ module HashableObject
5
+ module ClassMethods
6
+ def hash_on(*attributes)
7
+ if attributes.size == 1
8
+ define_method :hash_objects do
9
+ public_send attributes.first
10
+ end
11
+ else
12
+ define_method :hash_objects do
13
+ attributes.map { |attribute| public_send attribute }.to_a.inspect
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ module InstanceMethods
20
+ def hash_objects
21
+ raise NotImplementedError
22
+ end
23
+
24
+ protected
25
+
26
+ def generate_id
27
+ hash_data = hash_objects
28
+ hash_data = hash_data.inspect unless hash_data.is_a? String
29
+
30
+ Digest::SHA1.hexdigest(hash_data)
31
+ end
32
+
33
+ def id_valid?
34
+ @id == generate_id
35
+ end
36
+ end
37
+
38
+ def self.included(receiver)
39
+ receiver.extend ClassMethods
40
+ receiver.send :include, InstanceMethods
41
+ end
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,101 @@
1
+ require 'vcs_toolkit/file_store'
2
+
3
+ module VCSToolkit
4
+ module Utils
5
+
6
+ class MemoryFileStore < FileStore
7
+ def initialize(file_hash = {})
8
+ @files = {}
9
+
10
+ file_hash.each do |path, content|
11
+ store path, content
12
+ end
13
+ end
14
+
15
+ def store(path, content)
16
+ path = sanitize_path(path, false)
17
+
18
+ if path.end_with? '/'
19
+ raise 'You can store only files. The directories will be infered from the path'
20
+ end
21
+
22
+ @files[path] = content
23
+ end
24
+
25
+ def delete_file(path)
26
+ @files.delete sanitize_path(path, false)
27
+ end
28
+
29
+ def delete_dir(path)
30
+ # Do nothing as the directories are infered from the file paths
31
+ end
32
+
33
+ def fetch(path)
34
+ @files.fetch sanitize_path(path, false)
35
+ end
36
+
37
+ def file?(path)
38
+ @files.key? sanitize_path(path, false)
39
+ end
40
+
41
+ def directory?(path)
42
+ return false if file? path
43
+
44
+ path = sanitize_path(path, true)
45
+
46
+ @files.keys.any? do |file_path|
47
+ file_path.start_with? path
48
+ end
49
+ end
50
+
51
+ def changed?(path, blob)
52
+ content = fetch path
53
+
54
+ content != blob.content
55
+ end
56
+
57
+ def each_file(path='')
58
+ path = path.sub(/\/+$/, '')
59
+ path = "#{path}/" unless path.empty?
60
+
61
+ @files.each do |file_path, file|
62
+ name = file_path.sub(path, '').sub(/^\/+/, '')
63
+
64
+ if file_path.start_with?(path) and not name.empty? and not name.include?('/')
65
+ yield name
66
+ end
67
+ end
68
+ end
69
+
70
+ def each_directory(path='')
71
+ yielded_dirs = {}
72
+
73
+ path = sanitize_path(path, true) + '/' unless path.empty?
74
+
75
+ @files.each do |file_path, _|
76
+ name = file_path.sub(path, '')
77
+
78
+ if file_path.start_with?(path) and not name.empty? and name.include?('/')
79
+ name = name.split('/').first
80
+
81
+ yield name unless name.empty? or yielded_dirs.key? name
82
+ yielded_dirs[name] = true
83
+ end
84
+ end
85
+ end
86
+
87
+ private
88
+
89
+ def sanitize_path(path, remove_trailing_slash)
90
+ path.gsub(/\/+|\\+/, '/').gsub(/^\//, '')
91
+
92
+ if remove_trailing_slash
93
+ path.sub(/\/$/, '')
94
+ else
95
+ path
96
+ end
97
+ end
98
+ end
99
+
100
+ end
101
+ end
@@ -0,0 +1,60 @@
1
+ module VCSToolkit
2
+ module Utils
3
+
4
+ class Status
5
+ class << self
6
+
7
+ def compare_tree_and_store(tree, file_store, object_store, ignore: [])
8
+ store_file_paths = file_store.all_files(ignore: ignore).to_a
9
+
10
+ return {created: store_file_paths, changed: [], deleted: []} if tree.nil?
11
+
12
+ tree_files = Hash[tree.all_files(object_store, ignore: ignore).to_a]
13
+ tree_file_paths = tree_files.keys
14
+
15
+ created_files = store_file_paths - tree_file_paths
16
+ deleted_files = tree_file_paths - store_file_paths
17
+
18
+ changed_files = (tree_file_paths & store_file_paths).select do |file|
19
+ file_store.changed?(file, object_store.fetch(tree_files[file]))
20
+ end
21
+
22
+ {created: created_files, changed: changed_files, deleted: deleted_files}
23
+ end
24
+
25
+ def compare_trees(base_tree, new_tree, object_store, ignore: [])
26
+ created_files = []
27
+ changed_files = []
28
+ deleted_files = []
29
+
30
+ if base_tree.nil? and new_tree.nil?
31
+ # Do nothing... No changed or deleted files.
32
+ elsif new_tree.nil?
33
+ deleted_files = base_tree.all_files(object_store, ignore: ignore).map(&:first)
34
+ elsif base_tree.nil?
35
+ created_files = new_tree.all_files(object_store, ignore: ignore).map(&:first)
36
+ else
37
+ base_files = Hash[base_tree.all_files(object_store, ignore: ignore).to_a]
38
+ new_files = Hash[new_tree.all_files(object_store, ignore: ignore).to_a]
39
+
40
+ base_file_paths = base_files.keys
41
+ new_file_paths = new_files.keys
42
+
43
+ created_files = new_file_paths - base_file_paths
44
+ deleted_files = base_file_paths - new_file_paths
45
+
46
+ changed_files = (base_file_paths & new_file_paths).select do |file|
47
+ # A file has changed if the ID of it's blob is different
48
+ base_files[file] != new_files[file]
49
+ end
50
+
51
+ end
52
+
53
+ {created: created_files, changed: changed_files, deleted: deleted_files}
54
+ end
55
+
56
+ end
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,73 @@
1
+ module VCSToolkit
2
+ module Utils
3
+
4
+ class Sync
5
+ def self.sync(*args)
6
+ new(*args).sync
7
+ end
8
+
9
+ def initialize(source_store, source_label_name, destination_store, destination_label_name)
10
+ @source_store = source_store
11
+ @source_label = source_store.fetch source_label_name
12
+ @destination_store = destination_store
13
+ @destination_label = destination_store.fetch destination_label_name
14
+ end
15
+
16
+ ##
17
+ # Syncs source history starting at `source_label` to
18
+ # `destination_store` starting at `destination_label`.
19
+ #
20
+ def sync
21
+ raise 'Nothing to sync' if @source_label.reference_id.nil?
22
+
23
+ destination_commit_id = @destination_label.reference_id
24
+ raise DivergedHistoriesError unless destination_commit_id.nil? or @source_store.key? destination_commit_id
25
+
26
+ source_commit = @source_store.fetch @source_label.reference_id
27
+ commits_to_push = source_commit.history_diff(@source_store) do |commit|
28
+ # Do not follow parent references for commits
29
+ # that are already on the remote.
30
+ @destination_store.key? commit.id
31
+ end
32
+
33
+ commits_to_push.each do |commit|
34
+ transfer_commit commit
35
+ end
36
+
37
+ # Now that every object is transferred change the destination label
38
+ @destination_label.reference_id = source_commit.id
39
+ @destination_store.store @destination_label.id, @destination_label
40
+ end
41
+
42
+ private
43
+
44
+ def transfer_commit(commit)
45
+ transfer_tree @source_store.fetch(commit.tree)
46
+ @destination_store.store commit.id, commit
47
+ end
48
+
49
+ def transfer_tree(tree)
50
+ # Transfer all blobs
51
+ tree.files.each do |_, blob_id|
52
+ blob = @source_store.fetch blob_id
53
+ @destination_store.store blob.id, blob
54
+ end
55
+
56
+ # Transfer all nested trees
57
+ tree.trees.each do |_, tree_id|
58
+ nested_tree = @source_store.fetch tree_id
59
+ transfer_tree nested_tree
60
+ end
61
+
62
+ @destination_store.store tree.id, tree
63
+ end
64
+ end
65
+
66
+ class DivergedHistoriesError < VCSToolkitError
67
+ def initialize(message='The local and remote histories have diverged')
68
+ super
69
+ end
70
+ end
71
+
72
+ end
73
+ end
@@ -0,0 +1,3 @@
1
+ module VCSToolkit
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vcs_toolkit
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Georgy Angelov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-02-21 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: diff-lcs
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: fuubar
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Allows easy to use platform for building a Version Control System. It's
70
+ a proof-of-concept that VCS systems such as Git are simple in their implementation
71
+ email:
72
+ - georgyangelov@gmail.com
73
+ executables: []
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - LICENSE
78
+ - README.md
79
+ - lib/vcs_toolkit.rb
80
+ - lib/vcs_toolkit/conflict.rb
81
+ - lib/vcs_toolkit/diff.rb
82
+ - lib/vcs_toolkit/exceptions.rb
83
+ - lib/vcs_toolkit/file_store.rb
84
+ - lib/vcs_toolkit/merge.rb
85
+ - lib/vcs_toolkit/object_store.rb
86
+ - lib/vcs_toolkit/objects.rb
87
+ - lib/vcs_toolkit/objects/blob.rb
88
+ - lib/vcs_toolkit/objects/commit.rb
89
+ - lib/vcs_toolkit/objects/label.rb
90
+ - lib/vcs_toolkit/objects/object.rb
91
+ - lib/vcs_toolkit/objects/tree.rb
92
+ - lib/vcs_toolkit/repository.rb
93
+ - lib/vcs_toolkit/serializable.rb
94
+ - lib/vcs_toolkit/utils/hashable_object.rb
95
+ - lib/vcs_toolkit/utils/memory_file_store.rb
96
+ - lib/vcs_toolkit/utils/status.rb
97
+ - lib/vcs_toolkit/utils/sync.rb
98
+ - lib/vcs_toolkit/version.rb
99
+ homepage: http://github.com/stormbreakerbg/vcs-toolkit
100
+ licenses:
101
+ - MIT
102
+ metadata: {}
103
+ post_install_message:
104
+ rdoc_options: []
105
+ require_paths:
106
+ - lib
107
+ required_ruby_version: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - ">="
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ requirements:
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ version: '0'
117
+ requirements: []
118
+ rubyforge_project:
119
+ rubygems_version: 2.2.1
120
+ signing_key:
121
+ specification_version: 4
122
+ summary: A Ruby gem designed to allow its users to easily implement their own Version
123
+ Control System
124
+ test_files: []