treedisha 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2010 dpree
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,20 @@
1
+ # Treedisha
2
+
3
+ diffing filesystem-trees using sha1-checksums
4
+
5
+ ## Description
6
+
7
+ Treedisha is a little ruby gem for comparing two file trees.
8
+ like git, it uses sha1-checksums to differentiate files from each other and it also doesn't rely on directories. (actually, i was using a wrapper around git for the same job, before i wrote this)
9
+
10
+ after comparing the two file trees, it should provide the following information:
11
+
12
+ * files that weren't changed
13
+ * files that were moved (from path => to path)
14
+ * files that were modified (from sha1 => to sha1)
15
+ * files that were created
16
+ * files that were deleted
17
+
18
+ ## License
19
+
20
+ Treedisha is covered by the MIT License. See LICENSE for more information.
data/lib/treedisha.rb ADDED
@@ -0,0 +1,15 @@
1
+ # stdlib
2
+ require "digest/sha1"
3
+
4
+ require File.join(File.dirname(__FILE__), "treedisha/filesystem")
5
+ require File.join(File.dirname(__FILE__), "treedisha/comparator")
6
+
7
+ module Treedisha
8
+ def self.list(root_path)
9
+ Treedisha::Filesystem.all_files_with_sha1(root_path)
10
+ end
11
+
12
+ def self.compare(list_after, list_before)
13
+ Treedisha::Comparator.new(list_after, list_before)
14
+ end
15
+ end
@@ -0,0 +1,102 @@
1
+ module Treedisha
2
+ class Comparator
3
+
4
+ attr_reader :untouched
5
+ attr_reader :created, :deleted
6
+ attr_reader :moved_old_locations, :moved_new_locations
7
+ attr_reader :modified_new_content, :modified_old_content
8
+ attr_reader :modified, :moved
9
+
10
+ def initialize(new_tree, old_tree)
11
+ @new_tree = new_tree
12
+ @old_tree = old_tree
13
+
14
+ compare!
15
+ end
16
+
17
+ private
18
+
19
+ def compare!
20
+ @untouched = @new_tree & @old_tree
21
+
22
+ new_tree_without_shared = @new_tree - untouched
23
+ old_tree_without_shared = @old_tree - untouched
24
+
25
+ @moved_new_locations, created_or_modified_new_content = diff(new_tree_without_shared, old_tree_without_shared)
26
+ @moved_old_locations, deleted_or_modified_old_content = diff(old_tree_without_shared, new_tree_without_shared)
27
+
28
+ @moved = merge_moved_by_checksum(moved_new_locations, moved_old_locations)
29
+
30
+ @modified_new_content, @created = diff_paths(created_or_modified_new_content, deleted_or_modified_old_content)
31
+ @modified_old_content, @deleted = diff_paths(deleted_or_modified_old_content, created_or_modified_new_content)
32
+
33
+ @modified = merge_modified_by_path(modified_new_content, modified_old_content)
34
+ end
35
+
36
+ def diff(base_list_without_shared, search_list_without_shared)
37
+ different_paths_by_hash = []
38
+ different_hashes = []
39
+
40
+ base_list_without_shared.each do |base_hash, base_path|
41
+ found_pair_by_hash = search_list_without_shared.assoc(base_hash)
42
+
43
+ # shared hash but different path
44
+ if found_pair_by_hash
45
+ different_paths_by_hash << [base_hash, base_path]
46
+
47
+ # different hash
48
+ else
49
+ different_hashes << [base_hash, base_path]
50
+ end
51
+ end
52
+ [different_paths_by_hash, different_hashes]
53
+ end
54
+
55
+ def diff_paths(base_list, search_list)
56
+ shared_paths = []
57
+ different_paths = []
58
+
59
+ base_list.each do |base_hash, base_path|
60
+ found_pair_by_path = search_list.rassoc(base_path)
61
+
62
+ # shared path
63
+ if found_pair_by_path
64
+ shared_paths << [base_hash, base_path]
65
+
66
+ # different path
67
+ else
68
+ different_paths << [base_hash, base_path]
69
+ end
70
+ end
71
+
72
+ [shared_paths, different_paths]
73
+ end
74
+
75
+ def merge_moved_by_checksum(new_list, old_list)
76
+ moved = {}
77
+ new_list.each do |new_checksum, new_path|
78
+ if moved[new_checksum]
79
+ moved[new_checksum][:new_paths] << new_path
80
+ else
81
+ found_pairs_by_checksum = old_list.find_all{|old_checksum, old_path| new_checksum == old_checksum}
82
+ moved[new_checksum] = {
83
+ :new_paths => [new_path],
84
+ :old_paths => found_pairs_by_checksum.map{|a,b| b}
85
+ }
86
+ end
87
+ end
88
+ moved
89
+ end
90
+
91
+ def merge_modified_by_path(new_list, old_list)
92
+ modified = {}
93
+ new_list.each do |new_checksum, new_path|
94
+ modified[new_path] = {:new_checksum => new_checksum}
95
+ end
96
+ old_list.each do |old_checksum, old_path|
97
+ modified[old_path][:old_checksum] = old_checksum
98
+ end
99
+ modified
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,20 @@
1
+ module Treedisha
2
+ module Filesystem
3
+
4
+ def self.all_files(root_path)
5
+ Dir.glob("#{root_path}/**/*").find_all do |f|
6
+ !File.directory? f
7
+ end
8
+ end
9
+
10
+ def self.all_files_with_sha1(root_path)
11
+ all_files(root_path).map do |f|
12
+ [sha1_for_file(f), f]
13
+ end
14
+ end
15
+
16
+ def self.sha1_for_file(file)
17
+ Digest::SHA1.file(file).to_s
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,97 @@
1
+ require "spec_helper"
2
+
3
+ describe Treedisha::Comparator do
4
+ before(:each) do
5
+ new_tree = FixturesHelper.read_json_file("comparator_a/state_after.json")
6
+ old_tree = FixturesHelper.read_json_file("comparator_a/state_before.json")
7
+
8
+ @comparator = Treedisha::Comparator.new(new_tree, old_tree)
9
+ end
10
+
11
+ it "should throw no error" do
12
+ new_tree = FixturesHelper.read_json_file("comparator_b/state_after.json")
13
+ old_tree = FixturesHelper.read_json_file("comparator_b/state_before.json")
14
+
15
+ comparator = Treedisha::Comparator.new(new_tree, old_tree)
16
+ end
17
+
18
+ it "should be possible find unmodified files" do
19
+ @comparator.untouched.size.should == 3
20
+ @comparator.untouched.each do |hash,path|
21
+ path.should =~ /untouched/
22
+ end
23
+ end
24
+
25
+ it "should be possible find moved files and their new location" do
26
+ @comparator.moved_new_locations.size.should == 2
27
+ @comparator.moved_new_locations.each do |hash, path|
28
+ path.should =~ /file_moved_new_location/
29
+ end
30
+ end
31
+
32
+ it "should be possible find moved files and their old location" do
33
+ @comparator.moved_old_locations.size.should == 3
34
+ @comparator.moved_old_locations.each do |hash, path|
35
+ path.should =~ /file_moved_old_location/
36
+ end
37
+ end
38
+
39
+ it "should be possible find modified files and their new content" do
40
+ @comparator.modified_new_content.size.should == 1
41
+ @comparator.modified_new_content.each do |hash, path|
42
+ path.should =~ /file_changed_content/
43
+ hash.should =~ /new_content/
44
+ end
45
+ end
46
+
47
+ it "should be possible find modified files and their old content" do
48
+ @comparator.modified_old_content.size.should == 1
49
+ @comparator.modified_old_content.each do |hash, path|
50
+ path.should =~ /file_changed_content/
51
+ hash.should =~ /old_content/
52
+ end
53
+ end
54
+
55
+ it "should be possible find created files" do
56
+ @comparator.created.size.should == 2
57
+ @comparator.created.each do |hash,path|
58
+ path.should =~ /hereby_created/
59
+ end
60
+ end
61
+
62
+ it "should be possible find deleted files" do
63
+ @comparator.deleted.size.should == 2
64
+ @comparator.deleted.each do |hash,path|
65
+ path.should =~ /hereby_deleted/
66
+ end
67
+ end
68
+
69
+ it "should be possible to track modified files" do
70
+ @comparator.modified.keys.size.should == 1
71
+ @comparator.modified.each do |path, checksums|
72
+ path.should =~ /file_changed_content/
73
+ checksums[:old_checksum].should =~ /old_content/
74
+ checksums[:new_checksum].should =~ /new_content/
75
+ end
76
+ end
77
+
78
+ it "should be possible to track moved files" do
79
+ old_paths_count = 0
80
+ new_paths_count = 0
81
+ @comparator.moved.keys.size.should == 2
82
+ @comparator.moved.each do |checksum, paths|
83
+ paths[:old_paths].empty?.should be_false
84
+ old_paths_count += paths[:old_paths].size
85
+ paths[:old_paths].each do |path|
86
+ path.should =~ /file_moved_old_location/
87
+ end
88
+ paths[:new_paths].empty?.should be_false
89
+ new_paths_count += paths[:new_paths].size
90
+ paths[:new_paths].each do |path|
91
+ path.should =~ /file_moved_new_location/
92
+ end
93
+ end
94
+ old_paths_count.should == 3
95
+ new_paths_count.should == 2
96
+ end
97
+ end
@@ -0,0 +1,14 @@
1
+ require "spec_helper"
2
+
3
+ describe Treedisha::Filesystem do
4
+ it "should be possible to list all files" do
5
+ path = TestDirHelper.path(".")
6
+ Treedisha::Filesystem.all_files(path).empty?.should be_false
7
+ Treedisha::Filesystem.all_files(path).size == 1
8
+ end
9
+
10
+ it "should be possible to get sha1 for a file" do
11
+ path = TestDirHelper.path("foo.fx")
12
+ Treedisha::Filesystem.sha1_for_file(path).should == "83a4f6db0964dd03480be5f781eec6c5c2f7f5f2"
13
+ end
14
+ end
@@ -0,0 +1,7 @@
1
+ require "rubygems"
2
+ require "rspec"
3
+ require "json"
4
+
5
+ require File.join(File.dirname(__FILE__), "support/fixtures_helper")
6
+ require File.join(File.dirname(__FILE__), "support/test_dir_helper")
7
+ require File.join(File.dirname(__FILE__), "../lib/treedisha")
@@ -0,0 +1,10 @@
1
+ module FixturesHelper
2
+ def self.read_file(filename)
3
+ path = File.join(File.dirname(__FILE__), "..", "fixtures", filename)
4
+ File.read(path)
5
+ end
6
+
7
+ def self.read_json_file(filename)
8
+ JSON.parse(read_file(filename))
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module TestDirHelper
2
+ def self.path(subpath)
3
+ File.join(File.dirname(__FILE__), "..", "test_dir", subpath)
4
+ end
5
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: treedisha
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - dpree
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-12-08 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description: Tiny file tree comparison library using sha1-checksums
22
+ email: whiterabbit.init@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - LICENSE
29
+ - README.md
30
+ files:
31
+ - lib/treedisha.rb
32
+ - lib/treedisha/comparator.rb
33
+ - lib/treedisha/filesystem.rb
34
+ - LICENSE
35
+ - README.md
36
+ - spec/lib/comparator_spec.rb
37
+ - spec/lib/filesystem_spec.rb
38
+ - spec/spec_helper.rb
39
+ - spec/support/fixtures_helper.rb
40
+ - spec/support/test_dir_helper.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/dpree/treedisha
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options: []
47
+
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Tiny file tree comparison library
73
+ test_files:
74
+ - spec/lib/comparator_spec.rb
75
+ - spec/lib/filesystem_spec.rb
76
+ - spec/spec_helper.rb
77
+ - spec/support/fixtures_helper.rb
78
+ - spec/support/test_dir_helper.rb