git-ds 0.9.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. data/README.rdoc +795 -0
  2. data/doc/Examples.rdoc +36 -0
  3. data/doc/examples/key_value/kv_get.rb +29 -0
  4. data/doc/examples/key_value/kv_init.rb +20 -0
  5. data/doc/examples/key_value/kv_list.rb +28 -0
  6. data/doc/examples/key_value/kv_remove.rb +29 -0
  7. data/doc/examples/key_value/kv_set.rb +39 -0
  8. data/doc/examples/key_value/model.rb +156 -0
  9. data/doc/examples/key_value/test.rb +50 -0
  10. data/doc/examples/test_suite/model.rb +503 -0
  11. data/doc/examples/test_suite/test.rb +173 -0
  12. data/doc/examples/test_suite/ts_add_bug.rb +65 -0
  13. data/doc/examples/test_suite/ts_add_module.rb +74 -0
  14. data/doc/examples/test_suite/ts_add_module_to_test.rb +78 -0
  15. data/doc/examples/test_suite/ts_add_test.rb +77 -0
  16. data/doc/examples/test_suite/ts_add_test_suite.rb +65 -0
  17. data/doc/examples/test_suite/ts_add_test_to_bug.rb +76 -0
  18. data/doc/examples/test_suite/ts_init.rb +20 -0
  19. data/doc/examples/test_suite/ts_list.rb +118 -0
  20. data/doc/examples/test_suite/ts_perform_test.rb +104 -0
  21. data/doc/examples/test_suite/ts_update_bugs.rb +58 -0
  22. data/doc/examples/user_group/model.rb +265 -0
  23. data/doc/examples/user_group/test.rb +64 -0
  24. data/doc/examples/user_group/ug_add_group.rb +39 -0
  25. data/doc/examples/user_group/ug_add_group_user.rb +36 -0
  26. data/doc/examples/user_group/ug_add_user.rb +39 -0
  27. data/doc/examples/user_group/ug_init.rb +20 -0
  28. data/doc/examples/user_group/ug_list.rb +32 -0
  29. data/lib/git-ds.rb +14 -0
  30. data/lib/git-ds/config.rb +53 -0
  31. data/lib/git-ds/database.rb +289 -0
  32. data/lib/git-ds/exec_cmd.rb +107 -0
  33. data/lib/git-ds/index.rb +205 -0
  34. data/lib/git-ds/model.rb +136 -0
  35. data/lib/git-ds/model/db_item.rb +42 -0
  36. data/lib/git-ds/model/fs_item.rb +51 -0
  37. data/lib/git-ds/model/item.rb +428 -0
  38. data/lib/git-ds/model/item_list.rb +97 -0
  39. data/lib/git-ds/model/item_proxy.rb +128 -0
  40. data/lib/git-ds/model/property.rb +144 -0
  41. data/lib/git-ds/model/root.rb +46 -0
  42. data/lib/git-ds/repo.rb +455 -0
  43. data/lib/git-ds/shared.rb +17 -0
  44. data/lib/git-ds/transaction.rb +77 -0
  45. data/tests/ut_database.rb +304 -0
  46. data/tests/ut_git_grit_equiv.rb +195 -0
  47. data/tests/ut_index.rb +203 -0
  48. data/tests/ut_model.rb +360 -0
  49. data/tests/ut_repo.rb +260 -0
  50. data/tests/ut_user_group_model.rb +316 -0
  51. metadata +142 -0
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # Initialize a user/group database repo
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ BASE=File.dirname(File.expand_path(__FILE__)\
6
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
7
+ $: << BASE + File::SEPARATOR + 'lib'
8
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
9
+
10
+ require 'user_group/model'
11
+
12
+ if __FILE__ == $0
13
+ if ARGV.count != 1
14
+ puts "Usage : #{$0} FILENAME"
15
+ exit -1
16
+ end
17
+
18
+ UserGroupModel.new(GitDS::Database.connect(ARGV.shift, true))
19
+ exit 0
20
+ end
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ # List User/Group database contents
3
+ # Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
4
+
5
+ BASE=File.dirname(File.expand_path(__FILE__)\
6
+ ).split(File::SEPARATOR)[0..-4].join(File::SEPARATOR)
7
+ $: << BASE + File::SEPARATOR + 'lib'
8
+ $: << BASE + File::SEPARATOR + 'doc' + File::SEPARATOR + 'examples'
9
+
10
+ require 'user_group/model'
11
+
12
+ if __FILE__ == $0
13
+
14
+ path = ARGV.count == 1 ? ARGV.shift : GitDS::Database.top_level
15
+ model = UserGroupModel.new(GitDS::Database.connect(path, false))
16
+ raise "Could not connect to model" if not model
17
+
18
+ puts "Users:"
19
+ model.users.each do |user|
20
+ u = model.user(user)
21
+ puts "\t#{u.id}\t#{u.username}\t#{u.created}\t#{u.full_name}"
22
+ end
23
+
24
+ puts "\nGroups:"
25
+ model.groups.each do |grp|
26
+ puts "\t#{grp}"
27
+ g = model.group(grp)
28
+ puts "\t#{g.id}\t#{g.name}\t#{g.owner.username}\t#{g.users.inspect}"
29
+ end
30
+
31
+ exit 0
32
+ end
data/lib/git-ds.rb ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # :title: GitDS
3
+ =begin rdoc
4
+ <i>Copyright 2011 Thoughtgang <http://www.thoughtgang.org></i>
5
+ =end
6
+
7
+ require 'git-ds/shared'
8
+ require 'git-ds/index'
9
+ require 'git-ds/repo'
10
+ require 'git-ds/config'
11
+ require 'git-ds/database'
12
+ require 'git-ds/exec_cmd'
13
+ require 'git-ds/transaction'
14
+ require 'git-ds/model'
@@ -0,0 +1,53 @@
1
+ #!/usr/bin/env ruby
2
+ # :title: Git-DS::RepoConfig
3
+ =begin rdoc
4
+
5
+ Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
6
+ =end
7
+
8
+ module GitDS
9
+
10
+ =begin rdoc
11
+ Provides access to the repo .git/config file as a hash.
12
+
13
+ Note that this limits access to a specific section of the config file,
14
+ named by the parameter 'section'.
15
+ =end
16
+ class RepoConfig
17
+
18
+ def initialize(db, section='misc')
19
+ @db = db
20
+ @section = clean(section)
21
+ end
22
+
23
+ =begin rdoc
24
+ Clean key so it is a valid Config token
25
+ =end
26
+ def clean(str)
27
+ str.gsub(/[^-[:alnum:]]/, '-')
28
+ end
29
+
30
+ =begin rdoc
31
+ Return the full path to the variable for 'key'.
32
+ =end
33
+ def path(key)
34
+ @section + '.' + clean(key)
35
+ end
36
+
37
+ =begin rdoc
38
+ Return the String value of the variable 'key'.
39
+ =end
40
+ def [](key)
41
+ rv = @db.repo_config[path(key)]
42
+ rv ? rv : ''
43
+ end
44
+
45
+ =begin rdoc
46
+ Writes the String representation of 'value' to the variable 'key'.
47
+ =end
48
+ def []=(key, value)
49
+ @db.repo_config[path(key)] = value.to_s
50
+ end
51
+ end
52
+
53
+ end
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env ruby
2
+ # :title: Git-DS::Database
3
+ =begin rdoc
4
+
5
+ Copyright 2011 Thoughtgang <http://www.thoughtgang.org>
6
+ =end
7
+
8
+ require 'fileutils'
9
+
10
+ require 'git-ds/repo'
11
+ require 'git-ds/config'
12
+ require 'git-ds/model'
13
+ require 'git-ds/shared'
14
+ require 'git-ds/exec_cmd'
15
+ require 'git-ds/transaction'
16
+
17
+ module GitDS
18
+
19
+ =begin rdoc
20
+ Exception raised when a closed database is accessed
21
+ =end
22
+ class InvalidDbError < RuntimeError
23
+ end
24
+
25
+ =begin rdoc
26
+ Actually DbConnection to the repository.
27
+
28
+ Note: all operations should be in exec or transaction blocks. These use a
29
+ persistent staging index, and are more efficient.
30
+ =end
31
+ class Database < Repo
32
+
33
+ =begin rdoc
34
+ Flag to mark if database has been closed (i.e. connection is invalid).
35
+ =end
36
+ attr_reader :stale
37
+
38
+ =begin rdoc
39
+ Actor to use when performing Database operations. All Transaction and
40
+ ExecCmd objects will use this actor by default.
41
+
42
+ Default is nil (i.e. let Git read actor from .git/config or ENV).
43
+ =end
44
+ attr_accessor :actor
45
+
46
+ =begin rdoc
47
+ Return a connection to the Git DB.
48
+ Creates the DB if it does not already exist.
49
+ =end
50
+ def initialize(path, username=nil, email=nil)
51
+ init = false
52
+ if not File.exist? path
53
+ Repo.create(path)
54
+ init = true
55
+ end
56
+
57
+ @stale = false
58
+ super(path)
59
+
60
+ if init
61
+ # initial commit is needed for branches to work smoothly
62
+ stage { |idx| idx.add('.git-ds/version', "1.0\n") }
63
+ staging.commit('Database initialized.')
64
+ unstage
65
+ end
66
+
67
+ @actor = Grit::Actor.new(username, email) if username
68
+ end
69
+
70
+ =begin rdoc
71
+ Open a connection to database.
72
+
73
+ If 'create' is true (the default), a database will be created if one does
74
+ not exist at 'path'.
75
+ =end
76
+ def self.connect(path, create=true)
77
+ return nil if (not create) && (not File.exist? path)
78
+ connect_as(path, nil, nil, create)
79
+ end
80
+
81
+ =begin rdoc
82
+ Connect to a git database as the specified user.
83
+ =end
84
+ def self.connect_as(path, username, email, create=true)
85
+ return nil if (not create) && (not File.exist? path)
86
+ new(path, username, email)
87
+ end
88
+
89
+ =begin rdoc
90
+ Close DB connection, writing all changes to disk.
91
+
92
+ NOTE: This does not create a commit! Ony the staging index changes.
93
+ =end
94
+ def close(save=true)
95
+ raise InvalidDbError if @stale
96
+
97
+ if save && self.staging?
98
+ self.staging.write
99
+ end
100
+ self.staging = nil
101
+ @stale = true
102
+
103
+ # TODO: remove all locks etc
104
+ end
105
+
106
+ =begin rdoc
107
+ Delete Database (including entire repository) from disk.
108
+ =end
109
+ def purge
110
+ raise InvalidDbError if @stale
111
+
112
+ close(false)
113
+ FileUtils.remove_dir(@path) if ::File.exist?(@path)
114
+ end
115
+
116
+ =begin rdoc
117
+ Grit::Repo#config is wrapped by Database#config.
118
+ =end
119
+ alias :repo_config :config
120
+
121
+ =begin rdoc
122
+ Provides access to the Hash of Git-DS config variables.
123
+ =end
124
+ def config
125
+ @git_config ||= RepoConfig.new(self, 'git-ds')
126
+ end
127
+
128
+ =begin rdoc
129
+ Set the Git author information for the database connection. Wrapper for
130
+ actor=.
131
+ =end
132
+ def set_author(name, email=nil)
133
+ self.actor = name ? Grit::Actor.new(name, (email ? email : '')) : nil
134
+ end
135
+
136
+ =begin rdoc
137
+ Execute a block in the context of the staging index.
138
+
139
+ See ExecCmd.
140
+ =end
141
+ def exec(&block)
142
+ raise InvalidDbError if @stale
143
+
144
+ return exec_in_staging(true, &block) if self.staging?
145
+
146
+ begin
147
+ self.staging
148
+ exec_in_staging(false, &block)
149
+ self.staging.write
150
+ ensure
151
+ self.staging = nil
152
+ end
153
+
154
+ end
155
+
156
+ =begin
157
+ Execute a transaction in the context of the staging index.
158
+
159
+ See Transaction.
160
+ =end
161
+ def transaction(&block)
162
+ raise InvalidDbError if @stale
163
+
164
+ return transaction_in_staging(true, &block) if self.staging?
165
+
166
+ begin
167
+ self.staging
168
+ transaction_in_staging(false, &block)
169
+ ensure
170
+ self.staging = nil
171
+ end
172
+ end
173
+
174
+ =begin rdoc
175
+ Add files to the database. Calls exec to ensure that a write is not performed
176
+ if a staging index already exists.
177
+ =end
178
+ def add(path, data='', on_fs=false)
179
+ exec { index.add(path, data, on_fs) }
180
+ end
181
+
182
+ =begin rdoc
183
+ Delete an object from the database.
184
+ =end
185
+ def delete(path)
186
+ exec { index.delete(path) }
187
+ end
188
+
189
+ =begin rdoc
190
+ Wrapper for Grit::Repo#index that checks if Database has been closed.
191
+ =end
192
+ def index_new
193
+ raise InvalidDbError if @stale
194
+ super
195
+ end
196
+
197
+ =begin rdoc
198
+ Wrapper for Grit::Repo#staging that checks if Database has been closed.
199
+ =end
200
+ def staging
201
+ raise InvalidDbError if @stale
202
+ super
203
+ end
204
+
205
+ =begin rdoc
206
+ Wrapper for Grit::Repo#head that checks if Database has been closed.
207
+ =end
208
+ def head
209
+ raise InvalidDbError if @stale
210
+ super
211
+ end
212
+
213
+ =begin rdoc
214
+ Wrapper for Grit::Repo#tree that checks if Database has been closed.
215
+ =end
216
+ def tree(treeish = 'master', paths = [])
217
+ raise InvalidDbError if @stale
218
+ super
219
+ end
220
+
221
+ =begin rdoc
222
+ Generate a tag object for the most recent commit.
223
+ =end
224
+ def mark(msg)
225
+ tag_object(msg, commits.first.id)
226
+ end
227
+
228
+ =begin rdoc
229
+ Branch-and-merge:
230
+ Run block in a transaction under a new branch. If the transaction succeeds,
231
+ the branch is merged back into master.
232
+
233
+ See Database#transaction .
234
+ =end
235
+ def branch_and_merge(name=next_branch_tag(), actor=nil, &block)
236
+ raise InvalidDbError if @stale
237
+
238
+
239
+ # save old actor
240
+ old_actor = self.actor
241
+ self.actor = actor if actor
242
+
243
+ # save old staging
244
+ saved_stage = (self.staging?) ? self.staging : nil
245
+
246
+ sha = commits.first ? commits.first.id : nil
247
+ tag = create_branch(name, sha)
248
+ set_branch(tag, self.actor)
249
+
250
+ # ensure staging index is nil [in case branch name was re-used]
251
+ unstage
252
+
253
+ # execute block in a transaction
254
+ rv = true
255
+ begin
256
+ transaction(&block)
257
+ merge_branch(tag, self.actor)
258
+ rescue Exception =>e
259
+ rv = false
260
+ end
261
+
262
+ # restore actor
263
+ self.actor = old_actor if actor
264
+
265
+ rv
266
+ end
267
+
268
+ private
269
+
270
+ =begin rdoc
271
+ Execute code block in context of current DB index
272
+ =end
273
+ def exec_in_staging(nested, &block)
274
+ cmd = ExecCmd.new(self.staging, nested, &block)
275
+ cmd.actor = self.actor
276
+ cmd.perform
277
+ end
278
+
279
+ =begin rdoc
280
+ Perform transaction in context of current DB index
281
+ =end
282
+ def transaction_in_staging(nested, &block)
283
+ t = Transaction.new(self.staging, nested, &block)
284
+ t.actor = self.actor
285
+ t.perform
286
+ end
287
+
288
+ end
289
+ end
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env ruby
2
+ # :title: Git-DS::ExecCmd
3
+ =begin rdoc
4
+
5
+ Copyright 2010 Thoughtgang <http://www.thoughtgang.org>
6
+ =end
7
+
8
+ require 'git-ds/shared'
9
+
10
+ module GitDS
11
+
12
+ =begin rdoc
13
+ A command to be executed in a database context (i.e. an Index).
14
+
15
+ Usage:
16
+
17
+ db.exec { |idx| ... }
18
+
19
+ See also Transaction.
20
+ =end
21
+ class ExecCmd
22
+
23
+ =begin rdoc
24
+ The GitDS::Index on which the command operates.
25
+ =end
26
+ attr_reader :index
27
+ =begin rdoc
28
+ The GitDS::Database on which the command operates. Useful for nesting.
29
+ =end
30
+ attr_reader :database
31
+ =begin rdoc
32
+ The message to use for the commit at the end of the command.
33
+ =end
34
+ attr_reader :commit_msg
35
+ DEFAULT_MESSAGE = 'auto-commit on transaction'
36
+ =begin rdoc
37
+ The Git author for the commit performed at the end of the command.
38
+ See commit_msg.
39
+ =end
40
+ attr_reader :commit_author
41
+ =begin rdoc
42
+ The body of the command.
43
+ =end
44
+ attr_reader :block
45
+ =begin rdoc
46
+ Is command nested (inside a parent)?
47
+ If true, a write and commit will not be performed.
48
+ =end
49
+ attr_reader :nested
50
+
51
+ def initialize(index, nested, msg=DEFAULT_MESSAGE, &block)
52
+ @index = index
53
+ @database = index.repo
54
+ @nested = nested
55
+ @block = block
56
+ # Default to no commit
57
+ @commit_msg = msg
58
+ # Default to config[user.name] and config[user.email]
59
+ @commit_author = nil
60
+ end
61
+
62
+ =begin rdoc
63
+ Set a commit message for this command.
64
+ =end
65
+ def message(str)
66
+ @commit_msg = str
67
+ end
68
+
69
+ =begin rdoc
70
+ Set the Git Author info for the commit. By default, this information
71
+ is pulled from the Git config file.
72
+ =end
73
+ def author(name, email)
74
+ @commit_author = Grit::Actor.new(name, email)
75
+ end
76
+
77
+ =begin rdoc
78
+ Set actor for commit.
79
+ =end
80
+ def actor=(actor)
81
+ @commit_author = actor
82
+ end
83
+
84
+ =begin rdoc
85
+ Commit index.
86
+ =end
87
+ def commit
88
+ self.index.commit(@commit_msg, @commit_author)
89
+ end
90
+
91
+ =begin rdoc
92
+ Perform command.
93
+ =end
94
+ def perform
95
+ rv = instance_eval(&self.block)
96
+
97
+ #self.index.build
98
+ if not self.nested
99
+ self.index.build
100
+ commit
101
+ end
102
+
103
+ rv
104
+ end
105
+ end
106
+
107
+ end