copernicium 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: cffaf1f93a4556043ac0a484ef0e10c24f7ea692
4
+ data.tar.gz: 41ece5cd459baf3690d2701e153b232293f3a433
5
+ SHA512:
6
+ metadata.gz: 215e18ebaa93fb182b3ea4407bbf266cee5004baef77e1ff195cbcd32061a7314e7c49b02b1f762482c950436c495b802f302d8d2bf976c0b17518bd17d5444c
7
+ data.tar.gz: ebf39e146f63bc17bc70de329ea98c2b5f0cbea79f6a4aa620f9f21719f96879ea7737864e34a2d747ee75861ba2c5f9daad1c9a6f55c81a509a6a95a324f265
data/bin/cn ADDED
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # copernicium - a distributed version control system
4
+
5
+ require_relative "../lib/required.rb"
6
+
7
+ include Copernicium
8
+
9
+ Copernicium::Driver.new.run(ARGV)
10
+
data/lib/RevLog.rb ADDED
@@ -0,0 +1,141 @@
1
+ # Revlog Top Level Function Definitions (Xiangru)
2
+ #
3
+ # add_file: add a file to the revision history
4
+ # in - file name, content
5
+ # out - hash id of file (file_id)
6
+ #
7
+ # delete_file: a delete a file from revision history
8
+ # in - file_id
9
+ # out - exit status code
10
+ #
11
+ # diff_files: generate the differences between 2 files
12
+ # in - two file_ids
13
+ # out - list of differences
14
+ #
15
+ # get_file: get the contents of a file based on hash id
16
+ # in - file_id
17
+ # out - content of specified file
18
+ #
19
+ # hash_file: generate hash id for a given file
20
+ # in - file name, content
21
+ # out - hashed id
22
+ #
23
+ # merge: given two files, try to merge them
24
+ # in - file_id_1, file_id_2
25
+ # out - success and merged file name/content, or failure and conflict
26
+
27
+ module Copernicium
28
+ class RevLog
29
+ def initialize(project_path)
30
+ @project_path = project_path
31
+ @cop_path = File.join(project_path, ".cop")
32
+ @log_path = File.join(@cop_path, "logmap.yaml")
33
+ @hash_path = File.join(@cop_path, "hashmap.yaml")
34
+ if File.exist?(@log_path) and File.exist?(@hash_path) then
35
+ @logmap = default_hash_factory.merge(YAML.load_file(@log_path))
36
+ @hashmap = default_hash_factory.merge(YAML.load_file(@hash_path))
37
+ else
38
+ @logmap = default_hash_factory()
39
+ @hashmap = default_hash_factory()
40
+ unless File.exist?(@cop_path)
41
+ Dir.mkdir(@cop_path)
42
+ end
43
+ end
44
+ end
45
+
46
+ def default_hash_factory()
47
+ Hash.new {[]}
48
+ end
49
+
50
+ def add_file(file_name, content)
51
+ hash = hash_file(file_name, content)
52
+ File.open(File.join(@cop_path, hash), "w") { |f|
53
+ f.write(content)
54
+ }
55
+ @logmap[file_name] = @logmap[file_name] << {:time => Time.now,
56
+ :hash => hash}
57
+ @hashmap[hash] = @hashmap[hash] << {:time => Time.now,
58
+ :filename => file_name}
59
+ update_log_file()
60
+ return hash
61
+ end
62
+
63
+ ## return 1 if succeed, otherwise 0
64
+ def delete_file(file_id)
65
+ begin
66
+ file_name = @hashmap[file_id][0][:filename]
67
+ @hashmap[file_id].delete_if { |e|
68
+ e[:filename] == file_name
69
+ }
70
+ @logmap[file_name].delete_if { |e|
71
+ e[:hash] == file_id
72
+ }
73
+ update_log_file()
74
+ File.delete(File.join(@cop_path, file_id))
75
+ return 1
76
+ rescue Exception
77
+ return 0
78
+ end
79
+ end
80
+
81
+
82
+ def get_file(file_id)
83
+ file_path = File.join(@cop_path, file_id)
84
+ if File.exist?(file_path)
85
+ File.open(file_path, "r") { |f|
86
+ return f.read
87
+ }
88
+ else
89
+ raise Exception, "Invalid file_id!"
90
+ end
91
+ end
92
+
93
+
94
+ def diff_files(file_id1, file_id2)
95
+ return Diffy::Diff.new(get_file(file_id1),
96
+ get_file(file_id2)).to_s()
97
+ end
98
+
99
+ def hash_file(file_name, content)
100
+ Digest::SHA256.hexdigest(file_name + content.to_s)
101
+ end
102
+
103
+ def merge(file_id1, file_id2)
104
+ diff_a = Diffy::Diff.new(get_file(file_id1),
105
+ get_file(file_id2)).each_chunk.to_a()
106
+ if diff_a.all? { |d| d[0]!="-"}
107
+ return get_file(file_id2)
108
+ end
109
+ # if diff_a.all? { |d| d[0]!="+"}
110
+ # return get_file(file_id1)
111
+ # end
112
+ return diff_a
113
+ end
114
+
115
+ def history(file_name)
116
+ hashs = []
117
+ for m in @logmap[file_name]
118
+ hashs << m[:hash]
119
+ end
120
+ return hashs
121
+ end
122
+
123
+ def update_log_file()
124
+ File.open(File.join(@cop_path, "logmap.yaml"), "w") { |f|
125
+ f.write(@logmap.to_yaml)
126
+ }
127
+ File.open(File.join(@cop_path, "hashmap.yaml"), "w") { |f|
128
+ f.write(@hashmap.to_yaml)
129
+ }
130
+ end
131
+
132
+ # def alterFile(fileObject, fileReferenceString, versionReferenceString)
133
+ # end
134
+
135
+ # def deleteFileVersion(fileReferenceString, versionReferenceString)
136
+ # end
137
+
138
+ # def viewFileHistory(fileReferenceString)
139
+ # end
140
+ end
141
+ end
data/lib/banners.rb ADDED
@@ -0,0 +1,23 @@
1
+ # file for large constant strings
2
+
3
+
4
+ HELP_BANNER = <<-EOS
5
+ Copernicium - simple DVCS
6
+
7
+ Starting:
8
+ init - create a new repository
9
+ status - check repo status
10
+
11
+ Commands:
12
+ commit <files> -m [message]
13
+ checkout [branch name]
14
+ merge [branch name]
15
+ clone [remote url]
16
+ push <remote name>
17
+ pull <remote name>
18
+
19
+ Options:
20
+ -v: print version
21
+ -h: show help
22
+ EOS
23
+
data/lib/pushpull.rb ADDED
@@ -0,0 +1,168 @@
1
+ # Frank Tamburrino
2
+ # CSC 253
3
+ # PushPull Module
4
+ # November 6, 2015
5
+
6
+
7
+ module Copernicium
8
+ class PushPull
9
+
10
+ def connect(remote, user = nil, passwd = nil, &block)
11
+ exit_code = false
12
+ if(block.nil?)
13
+ begin
14
+ if(user.nil?)
15
+ print "Username for remote repo?: "
16
+ user = (STDIN.readline).strip
17
+ end
18
+ if(passwd.nil?)
19
+ print "Password for #{user}: "
20
+ passwd = (STDIN.noecho(&:gets)).strip
21
+ puts
22
+ end
23
+ Net::SSH.start(remote, user, :password => passwd) do |ssh|
24
+ result = ssh.exec!("echo Successful Connection!")
25
+ puts result
26
+ exit_code = true;
27
+ end
28
+ rescue
29
+ puts "Connection Unsuccessful"
30
+ end
31
+ else
32
+ begin
33
+ if(user.nil?)
34
+ print "Username for remote repo: "
35
+ user = (STDIN.readline).strip
36
+ end
37
+ if(passwd.nil?)
38
+ print "Password for #{user}: "
39
+ passwd = (STDIN.noecho(&:gets)).strip
40
+ puts
41
+ end
42
+ Net::SSH.start(remote, user, :password => passwd) do |ssh|
43
+ yield ssh
44
+ end
45
+ exit_code = true;
46
+ rescue
47
+ puts "Unable to execute command!"
48
+ end
49
+ end
50
+ return exit_code
51
+ end
52
+
53
+ def transfer(remote, local, dest, user = nil, passwd = nil)
54
+ exit_code = false
55
+ if(user.nil?)
56
+ print "Username for remote repo: "
57
+ user = (STDIN.readline).strip
58
+ end
59
+ if(passwd.nil?)
60
+ print "Password for #{user}: "
61
+ passwd = (STDIN.noecho(&:gets)).strip
62
+ puts
63
+ end
64
+ begin
65
+ Net::SCP.start(remote, user, :password => passwd) do |scp|
66
+ scp.upload!(local, dest)
67
+ end
68
+ exit_code = true
69
+ rescue
70
+ puts "Unable to upload file!"
71
+ end
72
+ end
73
+
74
+ def fetch(remote, dest, local, user = nil, passwd = nil)
75
+ exit_code = false
76
+ if(user.nil?)
77
+ print "Username for remote repo: "
78
+ user = (STDIN.readline).strip
79
+ end
80
+ if(passwd.nil?)
81
+ print "Password for #{user}: "
82
+ passwd = (STDIN.noecho(&:gets)).strip
83
+ puts
84
+ end
85
+ begin
86
+ Net::SCP.start(remote, user, :password => passwd) do |scp|
87
+ scp.download!(dest, local, :recursive => true)
88
+ end
89
+ exit_code = true
90
+ rescue
91
+ puts "Unable to fetch file(s)!"
92
+ end
93
+
94
+ return exit_code
95
+ end
96
+
97
+ def push(remote, branch, remote_dir)
98
+ ################ One way we can handle it ###################
99
+ ################ Needs Repos and Revlog Functionality! ######
100
+ # snap_id = (Repos::Repo.history(branch)).last
101
+ # snap = RevLog::RevLog.get_file(snap_id)
102
+ # connect(remote) do |x|
103
+ # result = test.exec!("<call to Repos to diff the snapshots>")
104
+ # end
105
+ # print "Username for remote repo: "
106
+ # user = (STDIN.readline).strip
107
+ # print "Password for #{user}: "
108
+ # passwd = (STDIN.noecho(&:gets)).strip
109
+ # puts
110
+ # for result.each do |x|
111
+ # transfer(remote, "./#{x}", remote_dir, user, passwd)
112
+ # end
113
+ # connect(remote) do |x|
114
+ # test.exec!("<call to Repos to merge the files>")
115
+ # test.exec!("<clean up the files>")
116
+ # end
117
+ #############################################################
118
+ end
119
+
120
+ def pull(remote, branch, remote_dir)
121
+ ################ One way we can handle it ###################
122
+ ################ Needs Repos and Revlog Functionality! ######
123
+ # snap_id = (Repos::Repo.history(branch)).last
124
+ # snap = RevLog::RevLog.get_file(snap_id)
125
+ # connect(remote) do |x|
126
+ # result = test.exec!("<call to Repos to diff the snapshots>")
127
+ # end
128
+ # print "Username for remote repo: "
129
+ # user = (STDIN.readline).strip
130
+ # print "Password for #{user}: "
131
+ # passwd = (STDIN.noecho(&:gets)).strip
132
+ # puts
133
+ # for result.each do |x|
134
+ # fetch(remote, remote_dir, "./#{x}", user, passwd)
135
+ # RevLog::Revlog.merge(x, local_x)
136
+ # File.delete(x)
137
+ # end
138
+ #############################################################
139
+ end
140
+
141
+ def clone(remote, dir, user = nil, passwd = nil)
142
+ exit_code = false
143
+ if(user.nil?)
144
+ print "Username for remote repo: "
145
+ user = (STDIN.readline).strip
146
+ end
147
+ if(passwd.nil?)
148
+ print "Password for #{user}: "
149
+ passwd = (STDIN.noecho(&:gets)).strip
150
+ puts
151
+ end
152
+ begin
153
+ fetch(remote, dir, ".", user, passwd)
154
+ nd = File.basename(dir)
155
+ ################ Needs Repos Functionality! #################
156
+ # Initializes the folder as a Repo
157
+ # Repos::Repos.make_branch(nd)
158
+ #############################################################
159
+ exit_code = true;
160
+ rescue
161
+ puts "Failed to clone the remote branch!"
162
+ end
163
+
164
+ return exit_code
165
+ end
166
+
167
+ end
168
+ end
data/lib/repos.rb ADDED
@@ -0,0 +1,165 @@
1
+ # repos module
2
+
3
+ #require 'marshal'
4
+ # Details from this link:
5
+ # https://docs.google.com/document/d/1r3-NquhyRLbCncqTOQPwsznSZ-en6G6xzLbWIAmxhys/edit#heading=h.7pyingf1unu
6
+
7
+
8
+ # Repos Top Level Function Definitions (Logan)
9
+
10
+ # make_snapshot: Creates new snapshot from current files and versions
11
+ # in - array of file objects. file object = array of all versions: {id, content}
12
+ # out - hash id of snapshot
13
+
14
+ # restore_snapshot: Set current file versions to specified snapshot
15
+ # in - id of target snapshot
16
+ # out - Comm object with status
17
+
18
+ # history: Returns ids for all snapshots
19
+ # in - branch name
20
+ # out - Array of snapshot ids
21
+
22
+ # delete_snapshot: delete specified a snapshot
23
+ # in - target snapshot
24
+ # out - Comm object with status
25
+
26
+ # diff_snapshots: Returns diff between two different snapshots
27
+ # in - two ids of snapshots to perform diff on
28
+ # out - list of filenames and versions
29
+
30
+ # make_branch: make a new branch
31
+ # in - branch name
32
+ # out - hash id of new branch
33
+
34
+ # delete_branch: delete a branch
35
+ # in - branch name
36
+ # out - exit status code
37
+
38
+ # Also do a get_snapshot
39
+
40
+ module Copernicium
41
+ class Snapshot
42
+ def initialize(in_array)
43
+ @files = in_array
44
+ @id = ""
45
+ # id = hash of in array?
46
+ end
47
+
48
+ def set_id(in_id)
49
+ @id = in_id
50
+ end
51
+
52
+ # drop get prefix?
53
+ def get_id()
54
+ @id
55
+ end
56
+
57
+ def get_files()
58
+ @files
59
+ end
60
+ # Initialize hash at startup
61
+ # Possible? Or problem with self object?
62
+ end
63
+
64
+ class Repos
65
+ def initialize()
66
+ # Create manifest
67
+ # It's a list of snapshots in chronological order
68
+ @manifest = {"default" => []}
69
+ @curr_branch = "default"
70
+ # what to do about branch IDs?
71
+ # Read in project path and make manifest file?
72
+ # Create current
73
+ end
74
+
75
+ def manifest()
76
+ @manifest
77
+ end
78
+
79
+ def make_snapshot(file_array)
80
+ # Return hash ID of snapshot
81
+ new_snap = Snapshot.new(file_array)
82
+ # Set ID, consider breaking up that line
83
+ new_snap.set_id(Digest::SHA256.hexdigest(Marshal.dump(new_snap)))
84
+ @manifest[@curr_branch].push(new_snap)
85
+ # Update manifest file?
86
+ return new_snap.get_id()
87
+ end
88
+
89
+ def get_snapshot(target_id)
90
+ # Return snapshot (or just contents) given id
91
+ # Find snapshot
92
+ found_index = @manifest[@curr_branch].index{ |x| x.get_id() == target_id }
93
+ # Handle not found case
94
+ # Return it
95
+ if(found_index)
96
+ return @manifest[@curr_branch][found_index]
97
+ else
98
+ return found_index
99
+ end
100
+ #return ret_snap
101
+ end
102
+
103
+ # Not sure how I'm gonna do this one
104
+ def restore_snapshot(target_id)
105
+ # Return comm object with status
106
+ # Need a way to change files in workspace
107
+ return 1
108
+ end
109
+
110
+ #def history(branch_name)
111
+ def history()
112
+ # Return array of snapshot IDs
113
+ names_list = []
114
+ @manifest[@curr_branch].each {|x| names_list.push(x.get_id())}
115
+ return names_list
116
+ end
117
+
118
+ def delete_snapshot(target_id)
119
+ # Return comm object with status
120
+ # Find snapshot, delete from manifest/memory
121
+ @manifest[@curr_branch].delete_if { |x| x.get_id() == target_id }
122
+ # catch error
123
+ # update manifest file?
124
+ end
125
+
126
+ # Finds the files in snap1 that aren't in snap2, change this?
127
+ # Consider using diffy?
128
+ def diff_snapshots(id1, id2)
129
+ # Return list of filenames and versions
130
+ diff_files = []
131
+ # Put in error catching
132
+ files1 = get_snapshot(id1).get_files()
133
+ files2 = get_snapshot(id2).get_files()
134
+ # Find snapshot1 and snapshot2
135
+ files1.each do |x|
136
+ if(!files2.include?(x))
137
+ diff_files.push(x)
138
+ end
139
+ end
140
+ return diff_files
141
+ # Use revlog diff on each set of files? Look at Diffy
142
+ end
143
+
144
+ def make_branch(branch_name)
145
+ # Return hash ID of new branch
146
+ # Not sure where to store branches
147
+ # What goes in to the hash?
148
+ @manifest[branch_name] = @manifest[@curr_branch]
149
+ @curr_branch = branch_name
150
+ return 1
151
+ end
152
+
153
+ def delete_branch(branch_name)
154
+ # Exit status code
155
+ @manifest.delete("branch_name")
156
+ end
157
+
158
+ def clear()
159
+ # Just a placeholder for now
160
+ end
161
+
162
+ end
163
+ end
164
+
165
+
data/lib/required.rb ADDED
@@ -0,0 +1,21 @@
1
+ # gem requirements
2
+
3
+ require 'yaml'
4
+ require 'diffy'
5
+ require 'digest'
6
+ require 'pathname'
7
+ require 'singleton'
8
+ require 'socket' # Socket needed for communicating over the network
9
+ require 'io/console' # Needed to hide password at console
10
+ require 'net/ssh' # Needed to communicate with the remote
11
+ require 'net/scp' # Needed for file transfer between servers
12
+
13
+ # coperncicium files
14
+
15
+ require_relative "ui"
16
+ require_relative "repos"
17
+ require_relative "RevLog"
18
+ require_relative "banners"
19
+ require_relative "pushpull"
20
+ require_relative "workspace"
21
+
data/lib/ui.rb ADDED
@@ -0,0 +1,161 @@
1
+ # user interface module - parse and execute commands
2
+ # integrates all modules, central module
3
+
4
+
5
+ VERSION = "0.0.1"
6
+
7
+ module Copernicium
8
+ class Driver
9
+ # Get some info from the user when they dont specify it
10
+ def get(info)
11
+ puts "Hi, #{info} not specified. Enter #{info}:"
12
+ gets.chomp # read a line from user, and return it
13
+ end
14
+
15
+ # Print and exit with a specific code
16
+ def pexit(msg, sig)
17
+ puts msg
18
+ exit sig
19
+ end
20
+
21
+ # Executes the required action for a given user command.
22
+ #
23
+ # Parameters:
24
+ # * args - an array containing the tokenized argv from the user
25
+ # For instance: "cn hello world" -> ['hello', 'world']
26
+ #
27
+ # Return value:
28
+ # A UIComm object containing details of the command to be
29
+ # executed by the respective backend module.
30
+ #
31
+ def run(args)
32
+
33
+ # if no arguments given show help information
34
+ pexit HELP_BANNER, 0 if args.empty?
35
+
36
+ # get first command
37
+ cmd = args.shift
38
+
39
+ # if no arguments given show help information
40
+ pexit HELP_BANNER, 0 if cmd == '-h'
41
+
42
+ # if -v flag givem show version
43
+ pexit VERSION, 0 if cmd == '-v'
44
+
45
+ # Handle standard commands
46
+ case cmd
47
+ when 'init'
48
+ init args
49
+ when 'status'
50
+ status args
51
+ when 'clone'
52
+ clone args
53
+ when 'commit'
54
+ commit args
55
+ when 'checkout'
56
+ checkout args
57
+ when 'merge'
58
+ merge args
59
+ when 'push'
60
+ push args
61
+ when 'pull'
62
+ pull args
63
+ else # handle an unrecognized argument, show help and exit
64
+ pexit "Unrecognized command #{cmd}\n" + HELP_BANNER, 1
65
+ end
66
+ end # run
67
+
68
+ def init(args)
69
+ UIComm.new(command: 'init', opts: args)
70
+ # todo - make call to repos to create repo
71
+ end
72
+
73
+ def status(args)
74
+ UIComm.new(command: 'status', opts: args)
75
+ # todo - make call to workspace, get and show status
76
+ end
77
+
78
+ def push(args)
79
+ UIComm.new(command: 'push', opts: args)
80
+ # todo - make call to pushpull, push remote
81
+ end
82
+
83
+ def pull(args)
84
+ UIComm.new(command: 'pull', opts: args)
85
+ # todo - make call to pushpull, pull remote
86
+ end
87
+
88
+ def checkout(args)
89
+ if args.empty?
90
+ rev = get 'branch or revision'
91
+ else
92
+ rev = args.shift
93
+ files = args
94
+ end
95
+
96
+ # todo - call repos checkout the given / branch
97
+ # todo - also, figure out if is branch or rev id
98
+ # this can be done by checking if it is a branch, and if not, then just
99
+ # assume it is a rev id. if it isnt, then something will break :/
100
+
101
+ UIComm.new(command: 'checkout', rev: rev, files: files)
102
+ end
103
+
104
+ def clone(args)
105
+ # todo - optionally check for folder to clone into, instead of cwd
106
+ if args.empty?
107
+ repo = get 'repo url to clone'
108
+ else
109
+ repo = args.first
110
+ end
111
+
112
+ # todo - actually clone remote locally
113
+
114
+ UIComm.new(command: 'clone', repo: repo)
115
+ end
116
+
117
+ def commit(args)
118
+ messflag = args.find_index('-m')
119
+ if messflag.nil?
120
+ message = get 'commit message'
121
+ else # mash everything after -m into a single string
122
+ message = args[messflag + 1..-1].join ' '
123
+ end
124
+
125
+ # todo parse file list, in case just commiting some files
126
+ # todo call revlog, commit files
127
+ # todo call repos, update commit
128
+
129
+ UIComm.new(command: 'commit', commit_message: message)
130
+ end
131
+
132
+ def merge(args)
133
+ if args.empty?
134
+ puts 'I need a commit to merge.'
135
+ rev = get 'single commit to merge'
136
+ else # use given
137
+ rev = args.first
138
+ end
139
+
140
+ # todo - call repos merge command
141
+
142
+ UIComm.new(command: 'merge', rev: rev)
143
+ end
144
+ end
145
+
146
+ # Communication object that will pass commands to backend modules
147
+ # rev - A single revision indicator (commit #, branch name, HEAD, etc.)
148
+ # repo - URL/path to a remote repository
149
+ class UIComm
150
+ attr_reader :command, :arguments, :files, :rev, :commit_message, :repo
151
+ def initialize(command: nil, files: nil, rev: nil,
152
+ commit_message: nil, repo: nil, opts: nil)
153
+ @commit_message = commit_message
154
+ @command = command
155
+ @files = files
156
+ @opts = opts
157
+ @repo = repo
158
+ @rev = rev
159
+ end
160
+ end
161
+ end
data/lib/workspace.rb ADDED
@@ -0,0 +1,212 @@
1
+ # This is the workspace module
2
+ # The functions are clean, commit, checkout and status
3
+
4
+ module Copernicium
5
+ class FileObj
6
+ attr_reader :path, :history_hash_ids
7
+ def initialize(path, ids)
8
+ @path = path
9
+ @history_hash_ids = ids
10
+ end
11
+
12
+ def ==(rhs)
13
+ if rhs.is_a? String
14
+ @path == rhs
15
+ else
16
+ @path == rhs.path
17
+ end
18
+ end
19
+ end
20
+
21
+ class Workspace
22
+ def writeFile(path, content)
23
+ f = open(path, 'w')
24
+ f.write(content)
25
+ f.close
26
+ end
27
+
28
+ def readFile(path)
29
+ f = open(path, 'r')
30
+ txt = f.read
31
+ f.close
32
+ txt
33
+ end
34
+
35
+ #private_class_method :writeFile
36
+ #private_class_method :readFile
37
+
38
+ def initialize(bname = 'master', rootdir = './workspace')
39
+ @files = []
40
+ @branch_name = bname
41
+ @revlog = Copernicium::RevLog.new('.')
42
+ @repos = Copernicium::Repos.new
43
+ @root = rootdir
44
+ if !File.directory?(@root)
45
+ Dir.mkdir(@root)
46
+ end
47
+ end
48
+
49
+ def indexOf(x)
50
+ index = -1
51
+ @files.each_with_index do |e,i|
52
+ if e.path == x
53
+ index = i
54
+ break
55
+ end
56
+ end
57
+ index
58
+ end
59
+
60
+ # if include all the elements in list_files
61
+ def include?(list_files)
62
+ list_files.each do |x|
63
+ if indexOf(x) == -1
64
+ return false
65
+ end
66
+ end
67
+ true
68
+ end
69
+
70
+ # if list_files is nil, then rollback the list of files from the branch
71
+ # or rollback to the entire branch head pointed
72
+ def clean(comm)
73
+ list_files = comm.files
74
+ if list_files.nil? # reset first: delete them from disk and reset @files
75
+ @files.each{|x| File.delete(x.path)}
76
+ @files = []
77
+ # restore it with checkout() if we have had a branch name
78
+ if @branch_name != ''
79
+ # or it is the initial state, no commit and no checkout
80
+ return checkout(@branch_name)
81
+ else
82
+ return 0
83
+ end
84
+
85
+ else #list_files are not nil
86
+ # check that every file need to be reset should have been recognized by the workspace
87
+ #workspace_files_paths = @files.each{|x| x.path}
88
+ return -1 if (self.include? list_files) == false
89
+
90
+ # the actual action, delete all of them from the workspace first
91
+ list_files.each do |x|
92
+ File.delete(x)
93
+ idx = indexOf(x)
94
+ if !idx==-1
95
+ @files.delete_at(idx)
96
+ end
97
+ end
98
+
99
+ # if we have had a branch, first we get the latest snapshot of it
100
+ # and then checkout with the restored version of them
101
+ if @branch_name != ''
102
+ return checkout(list_files)
103
+ else
104
+ return 0
105
+ end
106
+ end
107
+ end
108
+
109
+ # commit a list of files or the entire workspace to make a new snapshot
110
+ def commit(comm)
111
+ # for this commented version, we first get all files in the workspace and then add files from comm obj
112
+ # it's not used at this time
113
+ # Linfeng Song
114
+ #list_files = @files.each{|x| x.path}
115
+ #if comm.files != nil
116
+ # comm.files.each do |x|
117
+ # if indexOf(x) == -1
118
+ # list_files.push(x)
119
+ # end
120
+ # end
121
+ #end
122
+ list_files = Dir[ File.join(@root, '**', '*') ].reject { |p| File.directory? p }
123
+ if list_files != nil
124
+ list_files.each do |x|
125
+ if indexOf(x) == -1
126
+ content = readFile(x)
127
+ hash = @revlog.add_file(x, content)
128
+ fobj = FileObj.new(x, [hash,])
129
+ @files.push(fobj)
130
+ else
131
+ content = readFile(x)
132
+ hash = @revlog.add_file(x, content)
133
+ if @files[indexOf(x)].history_hash_ids[-1] != hash
134
+ @files[indexOf(x)].history_hash_ids << hash
135
+ end
136
+ end
137
+ end
138
+ end
139
+ return @repos.make_snapshot(@files)
140
+ end
141
+
142
+ def checkout(comm)
143
+ argu = comm.files
144
+ # if argu is an Array Object, we assume it is a list of files to be added to the workspace
145
+ if argu != nil
146
+ # we add the list of files to @files regardless whether it has been in it.
147
+ # that means there may be multiple versions of a file.
148
+ list_files = argu
149
+ snapshot_id = @repos.history()[-1]
150
+ returned_snapshot = @repos.get_snapshot(snapshot_id)
151
+ list_files_last_commit = returned_snapshot.get_files()
152
+ list_files_last_commit.each do |x|
153
+ if list_files.include? x.path
154
+ path = x.path
155
+ content = @revlog.get_file(x.history_hash_ids[-1])
156
+ idx = indexOf(x.path)
157
+ if idx == -1
158
+ @files.push(x)
159
+ else
160
+ @files[idx] = x
161
+ end
162
+ writeFile(path,content)
163
+ end
164
+ end
165
+ # if argu is not an Array, we assume it is a String, representing the branch name
166
+ # we first get the last snapshot id of the branch, and then get the commit object
167
+ # and finally push all files of it to the workspace
168
+ else
169
+ argu = comm.rev #branch name
170
+ snapshot_id = @repos.history()[-1]
171
+ snapshot_obj = @repos.get_snapshot(snapshot_id).get_files()
172
+ snapshot_obj.each do |fff|
173
+ idx = indexOf(fff.path)
174
+ if idx == -1
175
+ @files.push(fff)
176
+ else
177
+ @files[idx] = fff
178
+ end
179
+ path = fff.path
180
+ content = @revlog.get_file(fff.history_hash_ids[-1])
181
+ writeFile(path,content)
182
+ end
183
+ end
184
+ end
185
+
186
+ def status(comm)
187
+ adds = []
188
+ deletes = []
189
+ edits = []
190
+ wsFiles = Dir[ File.join(@root, '**', '*') ].reject { |p| File.directory? p }
191
+ wsFiles.each do |f|
192
+ idx = indexOf(f)
193
+ if idx != -1
194
+ x1 = @revlog.get_file(@files[idx].history_hash_ids[-1])
195
+ x2 = readFile(f)
196
+ if x1 != x2
197
+ edits.push(f)
198
+ end
199
+ else
200
+ adds.push(f)
201
+ end
202
+ end
203
+ @files.each do |f|
204
+ if ! (wsFiles.include? f.path)
205
+ deletes.push(f.path)
206
+ end
207
+ end
208
+ return [adds, edits, deletes]
209
+ end
210
+ end
211
+ end
212
+
metadata ADDED
@@ -0,0 +1,152 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: copernicium
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Team Copernicium
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: diffy
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 3.0.7
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 3.0.7
33
+ - !ruby/object:Gem::Dependency
34
+ name: net-scp
35
+ requirement: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - "~>"
38
+ - !ruby/object:Gem::Version
39
+ version: '1.2'
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: 1.2.1
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: !ruby/object:Gem::Requirement
46
+ requirements:
47
+ - - "~>"
48
+ - !ruby/object:Gem::Version
49
+ version: '1.2'
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: 1.2.1
53
+ - !ruby/object:Gem::Dependency
54
+ name: net-ssh
55
+ requirement: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - "~>"
58
+ - !ruby/object:Gem::Version
59
+ version: '3.0'
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 3.0.1
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '3.0'
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ version: 3.0.1
73
+ - !ruby/object:Gem::Dependency
74
+ name: minitest
75
+ requirement: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - "~>"
78
+ - !ruby/object:Gem::Version
79
+ version: '5.8'
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: 5.8.1
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '5.8'
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: 5.8.1
93
+ - !ruby/object:Gem::Dependency
94
+ name: minitest-reporters
95
+ requirement: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - "~>"
98
+ - !ruby/object:Gem::Version
99
+ version: '1.1'
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: 1.1.4
103
+ type: :development
104
+ prerelease: false
105
+ version_requirements: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - "~>"
108
+ - !ruby/object:Gem::Version
109
+ version: '1.1'
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: 1.1.4
113
+ description: A simple distributed version control system written in Ruby.
114
+ email: jeremywrnr@gmail.com
115
+ executables:
116
+ - cn
117
+ extensions: []
118
+ extra_rdoc_files: []
119
+ files:
120
+ - bin/cn
121
+ - lib/RevLog.rb
122
+ - lib/banners.rb
123
+ - lib/pushpull.rb
124
+ - lib/repos.rb
125
+ - lib/required.rb
126
+ - lib/ui.rb
127
+ - lib/workspace.rb
128
+ homepage: http://github.com/jeremywrnr/copernicium
129
+ licenses:
130
+ - MIT
131
+ metadata: {}
132
+ post_install_message:
133
+ rdoc_options: []
134
+ require_paths:
135
+ - lib
136
+ required_ruby_version: !ruby/object:Gem::Requirement
137
+ requirements:
138
+ - - ">="
139
+ - !ruby/object:Gem::Version
140
+ version: '0'
141
+ required_rubygems_version: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ requirements: []
147
+ rubyforge_project:
148
+ rubygems_version: 2.4.8
149
+ signing_key:
150
+ specification_version: 4
151
+ summary: Simple DVCS in Ruby.
152
+ test_files: []