git-ds 0.9.2

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