treet 0.11.0 → 0.13.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -15,3 +15,4 @@ spec/reports
15
15
  test/tmp
16
16
  test/version_tmp
17
17
  tmp
18
+ .irb_history
data/lib/treet/gitrepo.rb CHANGED
@@ -37,13 +37,15 @@ class Treet::Gitrepo < Treet::Repo
37
37
  end
38
38
  rescue Rugged::ReferenceError
39
39
  # invalid string for source, e.g. blank or illegal punctuation (colons)
40
- raise ArgumentError "invalid source string '#{tagname}' for repository tagging"
40
+ raise ArgumentError, "invalid source string '#{tagname}' for repository tagging"
41
41
  end
42
42
  end
43
43
 
44
44
  def patch(patchdef)
45
45
  super
46
- add_and_commit!
46
+ if git_changes?(patchdef)
47
+ add_and_commit!
48
+ end
47
49
  end
48
50
 
49
51
  def to_hash(opts = {})
@@ -52,9 +54,8 @@ class Treet::Gitrepo < Treet::Repo
52
54
  elsif opts[:tag]
53
55
  tag_snapshot(opts[:tag])
54
56
  else
55
- # snapshot(head.target)
56
57
  super()
57
- end
58
+ end.merge(augmentation)
58
59
  end
59
60
 
60
61
  def entries
@@ -62,7 +63,7 @@ class Treet::Gitrepo < Treet::Repo
62
63
  end
63
64
 
64
65
  def branches
65
- refs(/heads/).map(&:name) - ['refs/heads/master']
66
+ refs(/heads/).map {|ref| ref.name.gsub(/^refs\/heads\//, '')} - ['master']
66
67
  end
67
68
 
68
69
  # always branch from tip of master (private representation)
@@ -70,15 +71,22 @@ class Treet::Gitrepo < Treet::Repo
70
71
  Rugged::Reference.create(gitrepo, "refs/heads/#{name}", head.target)
71
72
  end
72
73
 
74
+ def tagged?(tagname)
75
+ ! commit_id_for(tagname).nil?
76
+ end
77
+
73
78
  def version(opts = {})
74
- if tag = opts[:tag]
75
- ref = Rugged::Reference.lookup(gitrepo, "refs/tags/#{tag}")
76
- ref && ref.target
79
+ if tagname = opts[:tag]
80
+ commit_id_for(tagname)
77
81
  else
78
82
  head.target
79
83
  end
80
84
  end
81
85
 
86
+ def current?(tagname)
87
+ commit_id_for(tagname) == head.target
88
+ end
89
+
82
90
  private
83
91
 
84
92
  attr_reader :gitrepo, :author
@@ -113,6 +121,7 @@ class Treet::Gitrepo < Treet::Repo
113
121
  def add_and_commit!
114
122
  current_index = entries
115
123
  Dir.chdir(root) do
124
+ # automatically ignores dotfiles
116
125
  current_files = Dir.glob('**/*')
117
126
 
118
127
  # additions
@@ -135,11 +144,22 @@ class Treet::Gitrepo < Treet::Repo
135
144
  # `index#remove` handles directories
136
145
  index.remove(file)
137
146
  end
147
+
148
+ index.write
149
+ tree_sha = index.write_tree
150
+ commit!(tree_sha)
138
151
  end
152
+ end
139
153
 
140
- index.write
141
- tree_sha = index.write_tree
142
- commit!(tree_sha)
154
+ def gitget(obj)
155
+ data = gitrepo.read(obj[:oid]).data
156
+ begin
157
+ JSON.load(data)
158
+ rescue JSON::ParserError
159
+ # parser errors are not fatal
160
+ # this just indicates a string entry rather than a hash
161
+ data.empty? ? obj[:name] : data
162
+ end
143
163
  end
144
164
 
145
165
  def snapshot(commit_sha)
@@ -150,31 +170,39 @@ class Treet::Gitrepo < Treet::Repo
150
170
  tree.each do |obj|
151
171
  data[obj[:name]] = case obj[:type]
152
172
  when :blob
153
- begin
154
- JSON.load(gitrepo.read(obj[:oid]).data)
155
- rescue JSON::ParserError
156
- raise JSON::ParserError, "bad JSON in blob #{obj[:name]}: #{gitrepo.read(obj[:oid]).data}"
157
- end
173
+ gitget(obj)
158
174
  when :tree
159
- begin
160
- gitrepo.lookup(obj[:oid]).each_with_object([]) do |subobj,d|
161
- d << JSON.load(gitrepo.read(subobj[:oid]).data)
162
- end
163
- rescue JSON::ParserError
164
- raise JSON::ParserError, "bad JSON in tree #{obj[:name]}: #{gitrepo.read(obj[:oid]).data}"
175
+ gitrepo.lookup(obj[:oid]).each_with_object([]) do |subobj,d|
176
+ d << gitget(subobj)
165
177
  end
166
178
  else
167
179
  raise TypeError, "UNRECOGNIZED GIT OBJECT TYPE #{obj[:type]}"
168
180
  end
169
181
  end
170
182
 
171
- # decorate(data)
172
183
  data
173
184
  end
174
185
 
186
+ def commit_id_for(tagname)
187
+ (ref = Rugged::Reference.lookup(gitrepo, "refs/tags/#{tagname}")) && ref.target
188
+ end
189
+
175
190
  def tag_snapshot(tagname)
176
- tag_ref = Rugged::Reference.lookup(gitrepo, "refs/tags/#{tagname}")
177
- raise ArgumentError, "tag '#{tagname}' does not exist in this repo" unless tag_ref
178
- snapshot(tag_ref.target)
191
+ if commitid = version(:tag => tagname)
192
+ snapshot(commitid)
193
+ else
194
+ # this tag does not appear in the repo; this is NOT an exception
195
+ {}
196
+ end
197
+ end
198
+
199
+ def augmentation(path = root)
200
+ dotfiles = Dir.entries(path).select {|f| f =~ /^\./ && f !~ /^(\.|\.\.|\.git)$/}
201
+ dotfiles.each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
202
+ end
203
+
204
+ # any patches in here that affect anything that must be recorded in git?
205
+ def git_changes?(patchdef)
206
+ patchdef.find {|p| p[1] =~ /^[^.]/}
179
207
  end
180
208
  end
data/lib/treet/repo.rb CHANGED
@@ -27,7 +27,8 @@ class Treet::Repo
27
27
  [keyname, '', nil]
28
28
  elsif keyname =~ /\./
29
29
  # subelement
30
- filename,field = keyname.split('.')
30
+ # negative lookbehind; don't split on a dot at beginning of string
31
+ filename,field = keyname.split(/(?<!^)\./)
31
32
  ['.', filename, field]
32
33
  else
33
34
  ['.', keyname]
@@ -143,7 +144,10 @@ class Treet::Repo
143
144
  end
144
145
 
145
146
  def expand(path)
146
- files = Dir.entries(path).select {|f| f !~ /^\./}
147
- files.each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
147
+ filenames(path).each_with_object({}) {|f,h| h[f] = expand_json("#{path}/#{f}")}
148
+ end
149
+
150
+ def filenames(path)
151
+ Dir.entries(path).select {|f| f !~ /^\./}
148
152
  end
149
153
  end
data/lib/treet/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Treet
2
- VERSION = "0.11.0"
2
+ VERSION = "0.13.1"
3
3
  end
@@ -1,6 +1,5 @@
1
1
  # encoding: UTF-8
2
2
  require "test_helper"
3
- require "pp"
4
3
 
5
4
  # convert a hash to a gitrepo
6
5
  # convert a plain repo to a gitrepo
@@ -42,13 +41,18 @@ describe Treet::Gitrepo do
42
41
  }
43
42
  thash = Treet::Hash.new(data)
44
43
  trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
45
- Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
44
+ r = Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
45
+ r.patch([]) # should be no-op, trigger no commit
46
+ r
46
47
  end
47
48
  end
48
49
 
49
50
  let(:johnb) { self.class.make_johnb }
50
51
 
51
52
  it "should have exactly one commit" do
53
+ Dir.chdir(johnb.root) do
54
+ `git log --oneline`.lines.count.must_equal 1
55
+ end
52
56
  johnb.head.wont_be_nil
53
57
  johnb.refs.count.must_equal 1
54
58
  johnb.refs.first.target.must_equal johnb.head.target
@@ -69,10 +73,6 @@ describe Treet::Gitrepo do
69
73
  johnb.tags.must_be_empty
70
74
  end
71
75
 
72
- it "should fail on unknown tag lookups" do
73
- ->{johnb.to_hash(:tag => 'nosuchtag')}.must_raise ArgumentError
74
- end
75
-
76
76
  it "should have no branches" do
77
77
  johnb.branches.must_be_empty
78
78
  end
@@ -81,8 +81,43 @@ describe Treet::Gitrepo do
81
81
  johnb.version.must_equal johnb.head.target
82
82
  end
83
83
 
84
- it "should return nil for unknown tag versions" do
85
- johnb.version(:tag => 'nosuchtag').must_be_nil
84
+ describe "an unknown tag" do
85
+ it "should have no commit" do
86
+ johnb.version(:tag => 'nosuchtag').must_be_nil
87
+ end
88
+ it "should not be present" do
89
+ refute johnb.tagged?('nosuchtag')
90
+ end
91
+ it "should return empty data" do
92
+ assert johnb.to_hash(:tag => 'nosuchtag').empty?
93
+ end
94
+ end
95
+ end
96
+
97
+ describe "a gitrepo with an array of strings" do
98
+ def self.make_repo
99
+ @repo ||= begin
100
+ data = {
101
+ "label" => "Rainbow Colors",
102
+ "colors" => %w{red orange yellow green blue purple}
103
+ }
104
+ thash = Treet::Hash.new(data)
105
+ trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
106
+ Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
107
+ end
108
+ end
109
+
110
+ let(:repo) { self.class.make_repo }
111
+
112
+ it "should fetch directly from file system" do
113
+ repo.to_hash.wont_be_nil
114
+ end
115
+
116
+ it "should fetch via git" do
117
+ data = repo.to_hash(:commit => repo.head.target)
118
+ data.wont_be_nil
119
+ assert data['label'] == 'Rainbow Colors'
120
+ assert data['colors'].to_set == %w{red orange yellow green blue purple}.to_set
86
121
  end
87
122
  end
88
123
 
@@ -191,7 +226,7 @@ describe Treet::Gitrepo do
191
226
  :xrefkey => 'app1',
192
227
  :xref => 'APP1_ID'
193
228
  )
194
- r.tag('app1')
229
+ r.tag('pre-edit')
195
230
  r.patch([
196
231
  [
197
232
  "-",
@@ -220,24 +255,31 @@ describe Treet::Gitrepo do
220
255
  repo.index.count.must_equal 2
221
256
  end
222
257
 
223
- it "should have tag not pointing to HEAD" do
258
+ it "should have one tag" do
224
259
  repo.tags.count.must_equal 1
225
- repo.tags.first.name.must_equal "refs/tags/app1"
226
- repo.tags.first.target.wont_equal repo.head.target
227
- end
228
-
229
- it "should have the original image for the tag" do
230
- refute hashalike(repo.to_hash, repo.to_hash(:tag => 'app1'))
231
- assert hashalike(repo.to_hash(:tag => 'app1'), load_json('two'))
232
260
  end
233
261
 
234
262
  it "should have no branches" do
235
263
  repo.branches.must_be_empty
236
264
  end
237
265
 
238
- it "should track version label by tag" do
239
- repo.version.must_equal repo.head.target
240
- repo.version(:tag => 'app1').must_equal repo.tags.first.target
266
+ describe "head state" do
267
+ it "should track version label by tag" do
268
+ assert repo.version == repo.head.target
269
+ end
270
+ end
271
+
272
+ describe "pre-patch state" do
273
+ it "should not be same as HEAD" do
274
+ assert repo.tagged?("pre-edit")
275
+ refute repo.current?("pre-edit")
276
+ assert repo.version(:tag => "pre-edit") != repo.version
277
+ end
278
+
279
+ it "should have the original image" do
280
+ refute hashalike(repo.to_hash, repo.to_hash(:tag => 'pre-edit'))
281
+ assert hashalike(repo.to_hash(:tag => 'pre-edit'), load_json('two'))
282
+ end
241
283
  end
242
284
  end
243
285
 
@@ -251,6 +293,8 @@ describe Treet::Gitrepo do
251
293
  it "should have tags" do
252
294
  repo.tags.count.must_equal 1
253
295
  repo.tags.first.name.must_equal "refs/tags/source1"
296
+ assert repo.tagged?("source1")
297
+ assert repo.current?("source1")
254
298
  end
255
299
 
256
300
  it "should have no branches" do
@@ -330,6 +374,9 @@ describe Treet::Gitrepo do
330
374
  versions = ['app1', 'app2', 'app3', 'app4'].map {|s| repo[:repo].version(:tag => s)}
331
375
  versions.uniq.count.must_equal 4
332
376
  end
377
+
378
+ it "should know which tag matches the HEAD state" do
379
+ end
333
380
  end
334
381
 
335
382
  describe "a branched gitrepo" do
@@ -340,7 +387,44 @@ describe Treet::Gitrepo do
340
387
  end
341
388
 
342
389
  it "should show a branch" do
343
- repo.branches.must_equal ['refs/heads/mybranch']
390
+ repo.branches.must_equal ['mybranch']
391
+ end
392
+ end
393
+
394
+ describe "repo with non-gitified attributes" do
395
+ let(:repo) do
396
+ @data = {'foo' => 'bar', '.attr' => {'key' => 'value'}}
397
+ thash = Treet::Hash.new(@data)
398
+ trepo = thash.to_repo(Dir.mktmpdir('repo', $topdir))
399
+ r = Treet::Gitrepo.new(trepo.root, :author => {:name => 'Bob', :email => 'bob@example.com'})
400
+ r.tag('testing')
401
+ r.patch([["~", ".attr.key", "newvalue"]])
402
+ @updated = {'foo' => 'bar', '.attr' => {'key' => 'newvalue'}}
403
+ r
404
+ end
405
+
406
+ it "should retrieve all attributes" do
407
+ repo.to_hash.must_equal @updated
408
+ end
409
+
410
+ it "should not create new commits for edits to dot attributes" do
411
+ Dir.chdir(repo.root) do
412
+ `git log --oneline`.lines.count.must_equal 1
413
+ end
414
+ end
415
+
416
+ it "should retrieve non-gitified attrs even via tags and commits" do
417
+ repo.to_hash(:tag => 'testing').must_equal @updated
418
+ repo.to_hash(:commit => repo.version(:tag => 'testing')).must_equal @updated
419
+ repo.to_hash(:commit => repo.version).must_equal @updated
420
+ end
421
+
422
+ it "should not commit the dot-prefixed attributes" do
423
+ Dir.chdir(repo.root) do
424
+ gitified = `git ls-tree --name-only HEAD`
425
+ gitified.must_include('foo')
426
+ gitified.wont_include('.attr')
427
+ end
344
428
  end
345
429
  end
346
430
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: treet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.13.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-11 00:00:00.000000000 Z
12
+ date: 2013-03-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: thor
@@ -206,7 +206,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
206
206
  version: '0'
207
207
  segments:
208
208
  - 0
209
- hash: -2853716979805169129
209
+ hash: 1191802132244638868
210
210
  required_rubygems_version: !ruby/object:Gem::Requirement
211
211
  none: false
212
212
  requirements:
@@ -215,7 +215,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
215
215
  version: '0'
216
216
  segments:
217
217
  - 0
218
- hash: -2853716979805169129
218
+ hash: 1191802132244638868
219
219
  requirements: []
220
220
  rubyforge_project:
221
221
  rubygems_version: 1.8.24