treet 0.11.0 → 0.13.1

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