scvcs 0.2.0

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: eefc4bffd875b5d3790a245d07af5d33c806bdd1
4
+ data.tar.gz: bc962cb8cbd75e9315f5ca9cbad99a0faaee8a45
5
+ SHA512:
6
+ metadata.gz: 3fa4eb7036475bd632ff4e01928fd34815e86fa534d12e27ab28a1f1aaf19e36e1c5da461f15dd6444994a117e6dd068715ec98267c91a57f18339e13b289688
7
+ data.tar.gz: 02e00f9e40d47ac26016c98f079aac6a6c67fd09e00bd336576e16fc660603bbe4d0c49092dcac1b1f12dfba8b2c45ad63a9e4373615bbb3aa6ca6938939732b
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2013 Georgy Angelov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,152 @@
1
+ SCV
2
+ ===
3
+ The SCV is a tool that every terran player absolutely must use to have a stable and well-organized (code)base.
4
+
5
+ Seriously though...
6
+ ===================
7
+ This project was inspired by [the Git lecture](http://fmi.ruby.bg/lectures/15-git#1) I made for [this year's Ruby course](http://fmi.ruby.bg) at my university. It is also my course project.
8
+
9
+ The name SCV has two different meanings:
10
+
11
+ 1. It is `VCS` (Version Control System) in reverse
12
+ 2. It is the name of a StarCraft unit (a worker) which can gather resources and can also build and repair stuff.
13
+
14
+ Overview
15
+ ========
16
+ The goal is to create a working (you don't say) version control system in Ruby.
17
+
18
+ The project itself is split into two parts: [**VCSToolkit**](https://github.com/stormbreakerbg/vcs-toolkit) and **SCV**.
19
+ **VCSToolkit** is a Ruby gem that is supposed to provide the platform and common tools, upon which a VCS tool can be built. This is where most of the common operations for such a tool are (being) implemented. **SCV** only implements some of **VCSToolkit**'s interfaces, extends (minimally) its classes and provides a user-friendly command-line interface to its methods.
20
+
21
+ Features
22
+ ========
23
+ *Note: The examples below use the form `scv <command>`, but if you want to test it right now, follow the 3 steps in the **Try it!** section and use `./run_scv <command>`.*
24
+
25
+ Currently implemented features:
26
+
27
+ ---
28
+ `scv init`
29
+
30
+ Initializes an empty repository.
31
+
32
+ Actually creates a `.scv` directory in the current folder and the default `head` label (pointer to a `nil` commit).
33
+
34
+ ---
35
+ `scv status`
36
+
37
+ Shows the list of created, modified and deleted files since the last commit.
38
+
39
+ ---
40
+ `scv diff`
41
+
42
+ Shows the actual differences between the files in the last commit and the working directory.
43
+
44
+ ---
45
+ `scv commit`
46
+
47
+ Commits the current state of the working directory. All changed, new and deleted files are commited.
48
+ You can explicitly set the commit author on every commit using the `--author` option or set it once with `scv config author "Your Name <your@email.com>"`.
49
+
50
+ You can also set the date (`--date`), set the commit message (`-m` or `--message`) or amend the last commit (`--amend`). If the `-m` flag is not set the default terminal editor will be opened (as in Git).
51
+
52
+ Example: `scv commit --author "Georgy Angelov <test@test.test>"`
53
+
54
+ ---
55
+ `scv history` or `scv log`
56
+
57
+ Lists all commits, in reverse-chronological order with their **id**, **date**, **author** and **message**.
58
+
59
+ ---
60
+ `scv restore <paths>...`
61
+
62
+ Restores files to the state they were in the `head` commit. `paths` can be files or directories. New files will not be removed, only changed and deleted files are restored.
63
+
64
+ You can optionally specify the source commit with `-s` or `--source` by giving its object_id, a label name that references it or an object_id and a relative offset (for example `head~3`).
65
+
66
+ ---
67
+ `scv branch new <branch_name>` or `scv branch create <branch_name>`
68
+
69
+ Creates a new branch based on the current branch head.
70
+
71
+ ---
72
+ `scv branch delete <branch_name>` or `scv branch remove <branch_name>`
73
+
74
+ Deletes the specified branch. The commits are not lost, only the label is deleted.
75
+
76
+ ---
77
+ `scv branch switch <branch_name>`
78
+
79
+ Switches the current directory to the specified branch head. It works as follows:
80
+ - Detects the changes that should be made to switch from the current branch to the other
81
+ - If you have modified files that would have to be overrwriten (modified) fails with an error
82
+ - Keeps all of your new or modified files and only overwrites unmodified ones
83
+ - May restore any deleted files that are present in the other branch
84
+ - Switches the current branch to `branch_name` (the following commits will be on branch `branch_name`)
85
+
86
+ ---
87
+ `scv config`
88
+
89
+ Lists all configuration properties and values. The output is similar to the output of the `tree` tool, because the configuration options can be nested:
90
+
91
+ level_0
92
+ ├─ level_1_one
93
+ │ ├─ level_2_one: value
94
+ │ └─ level_2_two: true
95
+ └─ level_1_two: value
96
+
97
+ This configuration is stored in `.scv/config.yml` and is relative only to the current scv repository.
98
+
99
+ ---
100
+ `scv config <key>`
101
+
102
+ Shows the current value of `<key>`. A key of the form `one.two.three` can be used to reference nested properties.
103
+
104
+ ---
105
+ `scv config <key> <value>`
106
+
107
+ Sets the option `key` to `value`. As in the previous command, you can use the `one.two.three` form to reference nested properties. If the key doesn't exist it is created.
108
+
109
+
110
+ Try it!
111
+ =======
112
+ Since there are a lot of features currently missing, SCV is not yet available on RubyGems.
113
+
114
+ 1. Clone this repository
115
+ 2. `bundle install`
116
+ 3. `./run_scv help`
117
+
118
+ .scv structure
119
+ ================
120
+
121
+ .scv/
122
+
123
+ objects/
124
+ 59/
125
+ 59873e99cef61a60b3826e1cbb9d4b089ae78c2b.json
126
+ ...
127
+ ...
128
+
129
+ refs/
130
+ HEAD.json
131
+ master.json
132
+ ...
133
+
134
+ blobs/
135
+ 59/
136
+ 59873e99cef61a60b3826e1cbb9d4b089ae78c2b
137
+ ...
138
+ ...
139
+
140
+ Each object in `.scv/objects/` is stored in a directory with a name of the first two symbols of the object id.
141
+
142
+ The blob objects follow the same naming scheme as the regular ones, but they are just a copy of the original user files (not in `json` format).
143
+
144
+ The refs are named objects (object.named? == true) and can be enumerated. Currently the only named objects are labels which are used as pointers to unnamed ones.
145
+
146
+ Other
147
+ =====
148
+ Contributions are most welcome, but I doubt there will be any :)
149
+
150
+ If you are interested in learning more about this you can ask me on Twitter [@stormbreakerbg](https://twitter.com/stormbreakerbg).
151
+
152
+ ![SCV](http://static3.wikia.nocookie.net/__cb20080906211455/starcraft/images/2/24/SCV_SC2_Cncpt1.jpg)
@@ -0,0 +1,86 @@
1
+ desc 'A set of commands to manage branches.'
2
+ arg_name ''
3
+ command :branch do |c|
4
+
5
+ c.desc 'Create a branch'
6
+ c.arg_name '<branch name>'
7
+ c.command [:new, :create] do |create|
8
+ create.desc 'Specifies the commit/label that will be used as the branch head'
9
+ create.arg_name 'head'
10
+ create.default_value 'head'
11
+ create.flag [:b, :head]
12
+
13
+ create.action do |global_options, options, args|
14
+ branch_name = args.first
15
+ branch_head = options[:head]
16
+
17
+ raise 'No branch name specified' if branch_name.nil?
18
+
19
+ repository = global_options[:repository]
20
+
21
+ raise 'There is already a label with this name' if repository[branch_name]
22
+
23
+ repository.set_label branch_name, repository[branch_head, :commit].id
24
+ end
25
+ end
26
+
27
+ c.desc 'Delete a branch'
28
+ c.arg_name '<branch name>'
29
+ c.command [:delete, :remove] do |remove|
30
+ remove.action do |global_options, options, args|
31
+ branch_name = args.first
32
+
33
+ raise 'No branch name specified' if branch_name.nil?
34
+
35
+ repository = global_options[:repository]
36
+ branch = repository[branch_name]
37
+
38
+ raise 'The specified branch does not exits' if branch.nil?
39
+ raise 'The specified name is not a branch/label' if branch.object_type != :label
40
+
41
+ repository.delete_label branch_name
42
+ end
43
+ end
44
+
45
+ c.desc 'Switch head to another branch. Does not change any files'
46
+ c.arg_name '<branch name>'
47
+ c.command :switch do |switch|
48
+ switch.action do |global_options, options, args|
49
+ branch_name = args.first
50
+
51
+ raise 'No branch name specified' if branch_name.nil?
52
+
53
+ repository = global_options[:repository]
54
+ branch = repository[branch_name]
55
+
56
+ raise 'This is the current branch already' if repository.head == branch_name
57
+ raise 'There is no branch with this name' if branch.nil? or branch.object_type != :label
58
+
59
+ changes = repository.commit_status repository['head', :commit],
60
+ repository[branch_name, :commit]
61
+
62
+ status = repository.status repository['head', :commit],
63
+ ignore: [/^\.|\/\./]
64
+
65
+ # Check for conflicts
66
+ branch_changes = changes[:created] | changes[:changed] | changes[:deleted]
67
+ working_dir_changes = status[:created] | status[:changed] | status[:deleted]
68
+ conflicts = branch_changes & working_dir_changes
69
+
70
+ unless conflicts.empty?
71
+ raise 'Branch switch aborted due to conflics. Please commit or reset local changes'
72
+ end
73
+
74
+ repository.set_label :head, branch_name
75
+
76
+ # Reset unchanged files to their state in the new branch
77
+ commit = repository['head', :commit]
78
+ tree = repository[commit.tree]
79
+
80
+ tree.all_files(repository.object_store, ignore: working_dir_changes).each do |file, _|
81
+ repository.restore file, commit
82
+ end
83
+ end
84
+ end
85
+
86
+ end
@@ -0,0 +1,88 @@
1
+ desc 'Commits the current state of the working directory.'
2
+ arg_name ''
3
+ command :commit do |c|
4
+ c.desc 'The commit message'
5
+ c.arg_name 'message'
6
+ c.flag [:m, :message]
7
+
8
+ c.desc 'The commit author name and email.'
9
+ c.arg_name 'author'
10
+ c.flag :author
11
+
12
+ c.desc 'Use this to override the timestamp of the commit.'
13
+ c.arg_name 'date'
14
+ c.default_value DateTime.now
15
+ c.flag :date
16
+
17
+ c.desc 'Use this to replace the last commit'
18
+ c.arg_name 'amend'
19
+ c.switch :amend
20
+
21
+ c.action do |global_options, options, args|
22
+ repository = global_options[:repository]
23
+ repository_path = "#{global_options[:dir]}/.scv"
24
+
25
+ unless options[:amend]
26
+ status = repository.status repository[:head, :commit], ignore: [/^\.|\/\./]
27
+
28
+ if status.none? { |_, files| files.any? }
29
+ raise 'No changes since last commit'
30
+ end
31
+ end
32
+
33
+ if options[:author]
34
+ author = options[:author]
35
+ elsif repository.config['author']
36
+ author = repository.config['author']
37
+ else
38
+ raise 'Please provide an author with --author="..." or set it globally with `scv config author ...`'
39
+ end
40
+
41
+ if options[:amend] and repository.head.nil?
42
+ raise 'Amend requested but there are no commits'
43
+ end
44
+
45
+ if options[:message]
46
+ commit_message = options[:message].strip
47
+ else
48
+ commit_message_file = "#{repository_path}/COMMIT_MESSAGE"
49
+
50
+ if options[:amend]
51
+ File.write commit_message_file, repository[:head, :commit].message
52
+ end
53
+
54
+ system "$EDITOR #{commit_message_file}"
55
+ File.open(commit_message_file, 'r') do |file|
56
+ commit_message = file.read.strip
57
+ end
58
+ FileUtils.rm commit_message_file
59
+ end
60
+
61
+ if commit_message.empty?
62
+ raise 'The commit message cannot be empty'
63
+ end
64
+
65
+ date = options[:date].is_a?(String) ? DateTime.parse(options[:date]) : options[:date]
66
+
67
+ parents = nil
68
+
69
+ if options[:amend]
70
+ parents = repository[:head, :commit].parents
71
+ elsif repository.config['merge'] and repository.config['merge']['parents']
72
+ # There is a merge waiting for a commit creation
73
+ parents = repository.config['merge']['parents']
74
+
75
+ repository.config['merge'] = {}
76
+ end
77
+
78
+ repository.commit commit_message,
79
+ author,
80
+ date,
81
+ parents: parents,
82
+ ignore: [/^\.|\/\./]
83
+
84
+ if parents
85
+ repository.config.save
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,35 @@
1
+ desc 'Sets/changes config parameters for this repository'
2
+ arg_name '[<option> [<value>]]'
3
+ command :config do |c|
4
+ c.desc 'Delete the specified key'
5
+ c.arg_name 'delete'
6
+ c.switch [:d, :delete]
7
+
8
+ c.action do |global_options, options, args|
9
+ repository = global_options[:repository]
10
+
11
+ if args.empty?
12
+ # List all config options in a `tree`-like hierarchy
13
+ output { SCV::Formatters::Hierarchy.print(repository.config.data) }
14
+ elsif args.size == 1
15
+ if options[:delete]
16
+ repository.config.delete args.first
17
+ repository.config.save
18
+ else
19
+ # Print the specified option value
20
+ value = repository.config[args.first]
21
+
22
+ if value.is_a? Hash
23
+ SCV::Formatters::Hierarchy.print(value)
24
+ elsif not value.nil?
25
+ puts value
26
+ end
27
+ end
28
+ else
29
+ # Set the specified option
30
+ repository.config[args.first] = args[1..args.size].join(' ')
31
+ repository.config.save
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,19 @@
1
+ desc 'Displays the file changes in the working directory'
2
+ arg_name ''
3
+ command :diff do |c|
4
+ c.action do |global_options, options, args|
5
+ repository = global_options[:repository]
6
+ commit = repository[:head, :commit]
7
+ status = repository.status commit,
8
+ ignore: [/^\.|\/\./]
9
+
10
+ output do
11
+ status.each do |_, file_list|
12
+ file_list.each do |file_path|
13
+ changeset = repository.file_difference file_path, commit
14
+ SCV::Formatters::Changeset.print file_path, changeset
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ desc 'Displays the commit history'
2
+ arg_name ''
3
+ command [:history, :log] do |c|
4
+ c.action do |global_options, options, args|
5
+ repository = global_options[:repository]
6
+
7
+ output do
8
+ repository.history.each do |commit|
9
+ puts "Commit #{commit.id.yellow}"
10
+ puts "Author #{commit.author.blue}"
11
+ puts "Date #{commit.date.strftime "%A %Y-%m-%d %H:%M:%S %z".green}"
12
+
13
+ puts
14
+ puts commit.message.lines.map { |line| " #{line}" }.join ''
15
+ puts
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,17 @@
1
+ desc 'Initialize an empty repository.'
2
+ command :init do |c|
3
+
4
+ c.action do |global_options, options, args|
5
+ path = global_options[:dir]
6
+
7
+ if File.directory? File.join(path, '.scv')
8
+ raise "There is already an SCV repository #{path == '.' ? 'here' : 'at ' + path}"
9
+ end
10
+
11
+ SCV::Repository.create_at path
12
+
13
+ puts "Job's finished!"
14
+ puts "You can now use `scv commit` to create your first commit!"
15
+ end
16
+
17
+ end