scvcs 0.2.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.
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