chillfile 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/.rspec +1 -0
  2. data/Gemfile +18 -0
  3. data/Gemfile.lock +88 -0
  4. data/LICENSE +22 -0
  5. data/README.md +11 -0
  6. data/Rakefile +21 -0
  7. data/autotest/discover.rb +1 -0
  8. data/bin/chillfile +8 -0
  9. data/chillfile.gemspec +113 -0
  10. data/lib/chillfile/cli.rb +63 -0
  11. data/lib/chillfile/config.rb +40 -0
  12. data/lib/chillfile/database_server.rb +11 -0
  13. data/lib/chillfile/model/base.rb +3 -0
  14. data/lib/chillfile/model/sync_file.rb +28 -0
  15. data/lib/chillfile/model.rb +20 -0
  16. data/lib/chillfile/sync.rb +118 -0
  17. data/lib/chillfile.rb +56 -0
  18. data/spec/filesystem_after/bar.1.moved.untouched +1 -0
  19. data/spec/filesystem_after/bar.2.moved.copy +1 -0
  20. data/spec/filesystem_after/bar.3.moved.copy +0 -0
  21. data/spec/filesystem_after/foo.fx.copy +1 -0
  22. data/spec/filesystem_after/foo.untouched +1 -0
  23. data/spec/filesystem_after/moo.new +1 -0
  24. data/spec/filesystem_after/subdir_b/bar.4.moved.copy +1 -0
  25. data/spec/filesystem_before/bar.0.moved.deleted +1 -0
  26. data/spec/filesystem_before/bar.1.moved.untouched +0 -0
  27. data/spec/filesystem_before/foo.untouched +1 -0
  28. data/spec/filesystem_before/subdir/mii.deleted +3 -0
  29. data/spec/filesystem_before/wuu.deleted +3 -0
  30. data/spec/fixtures/filesystem_after.json +1 -0
  31. data/spec/fixtures/filesystem_before.json +1 -0
  32. data/spec/lib/chillfile/model/sync_file_spec.rb +18 -0
  33. data/spec/lib/chillfile_spec.rb +37 -0
  34. data/spec/spec_helper.rb +15 -0
  35. data/spec/support/db_helper.rb +10 -0
  36. data/spec/support/fixtures_helper.rb +10 -0
  37. data/spec/support/fs_helper.rb +10 -0
  38. data/spec/support/list_helper.rb +5 -0
  39. data/version.yml +5 -0
  40. metadata +235 -0
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,18 @@
1
+ source 'http://rubygems.org'
2
+ source 'http://rubygems.org'
3
+
4
+ group :default do
5
+ gem "couchrest"
6
+ gem 'couchrest_model', :git => 'git://github.com/couchrest/couchrest_model.git'
7
+ gem "treedisha", "~> 0.0.2", :git => 'git://github.com/dpree/treedisha.git'
8
+ gem "json"
9
+ gem "thor"
10
+ end
11
+
12
+ group :test do
13
+ gem "rspec"
14
+ end
15
+
16
+ group :gem do
17
+ gem "jeweler"
18
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,88 @@
1
+ GIT
2
+ remote: git://github.com/couchrest/couchrest_model.git
3
+ revision: 958616025db74bdea252e3108112c0afa439b439
4
+ specs:
5
+ couchrest_model (1.0.0.beta8)
6
+ activemodel (~> 3.0.0.rc)
7
+ couchrest (~> 1.0.1)
8
+ mime-types (~> 1.15)
9
+ railties (~> 3.0.0.rc)
10
+ tzinfo (~> 0.3.22)
11
+
12
+ GIT
13
+ remote: git://github.com/dpree/treedisha.git
14
+ revision: 926c6bb92b24972da1cad1b8cf27c32c13096674
15
+ specs:
16
+ treedisha (0.0.1)
17
+
18
+ GEM
19
+ remote: http://rubygems.org/
20
+ remote: http://rubygems.org/
21
+ specs:
22
+ abstract (1.0.0)
23
+ actionpack (3.0.3)
24
+ activemodel (= 3.0.3)
25
+ activesupport (= 3.0.3)
26
+ builder (~> 2.1.2)
27
+ erubis (~> 2.6.6)
28
+ i18n (~> 0.4)
29
+ rack (~> 1.2.1)
30
+ rack-mount (~> 0.6.13)
31
+ rack-test (~> 0.5.6)
32
+ tzinfo (~> 0.3.23)
33
+ activemodel (3.0.3)
34
+ activesupport (= 3.0.3)
35
+ builder (~> 2.1.2)
36
+ i18n (~> 0.4)
37
+ activesupport (3.0.3)
38
+ builder (2.1.2)
39
+ couchrest (1.0.1)
40
+ json (>= 1.4.6)
41
+ mime-types (>= 1.15)
42
+ rest-client (>= 1.5.1)
43
+ diff-lcs (1.1.2)
44
+ erubis (2.6.6)
45
+ abstract (>= 1.0.0)
46
+ git (1.2.5)
47
+ i18n (0.5.0)
48
+ jeweler (1.5.1)
49
+ bundler (~> 1.0.0)
50
+ git (>= 1.2.5)
51
+ rake
52
+ json (1.4.6)
53
+ mime-types (1.16)
54
+ rack (1.2.1)
55
+ rack-mount (0.6.13)
56
+ rack (>= 1.0.0)
57
+ rack-test (0.5.6)
58
+ rack (>= 1.0)
59
+ railties (3.0.3)
60
+ actionpack (= 3.0.3)
61
+ activesupport (= 3.0.3)
62
+ rake (>= 0.8.7)
63
+ thor (~> 0.14.4)
64
+ rake (0.8.7)
65
+ rest-client (1.6.1)
66
+ mime-types (>= 1.16)
67
+ rspec (2.3.0)
68
+ rspec-core (~> 2.3.0)
69
+ rspec-expectations (~> 2.3.0)
70
+ rspec-mocks (~> 2.3.0)
71
+ rspec-core (2.3.0)
72
+ rspec-expectations (2.3.0)
73
+ diff-lcs (~> 1.1.2)
74
+ rspec-mocks (2.3.0)
75
+ thor (0.14.6)
76
+ tzinfo (0.3.23)
77
+
78
+ PLATFORMS
79
+ ruby
80
+
81
+ DEPENDENCIES
82
+ couchrest
83
+ couchrest_model!
84
+ jeweler
85
+ json
86
+ rspec
87
+ thor
88
+ treedisha!
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,11 @@
1
+ # Chillfile
2
+
3
+ sync your files with a couchdb
4
+
5
+ ## Description
6
+
7
+ Upload the latest changes you made on the filesystem into a couchdb
8
+
9
+ ## License
10
+
11
+ Chillfile is covered by the MIT License. See LICENSE for more information.
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "chillfile"
5
+ gemspec.summary = "Tiny tool to sync filesystem with couchdb"
6
+ gemspec.description = "Let your files chill on the couch"
7
+ gemspec.email = "whiterabbit.init@gmail.com"
8
+ gemspec.homepage = "http://github.com/dpree/chillfile"
9
+ gemspec.authors = ["dpree"]
10
+ gemspec.add_dependency("thor", "~> 0.14.6")
11
+ gemspec.add_dependency("couchrest", "~> 1.0.1")
12
+ #gemspec.add_dependency("couchrest_model", "~> 1.0.0.beta8") # currently you have to clone, build and install it yourself from HEAD
13
+ gemspec.add_dependency("treedisha", "~> 0.0.2")
14
+ gemspec.add_development_dependency('rspec', '~> 2.0.0')
15
+ gemspec.date = Time.now.strftime("%Y-%m-%d")
16
+ gemspec.executables = ["chillfile"]
17
+ end
18
+ Jeweler::GemcutterTasks.new
19
+ rescue LoadError
20
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
21
+ end
@@ -0,0 +1 @@
1
+ Autotest.add_discovery { "rspec2" }
data/bin/chillfile ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+ require "chillfile"
5
+
6
+ #require File.join(File.dirname(__FILE__), "../lib/chillfile")
7
+
8
+ Chillfile::CLI.start
data/chillfile.gemspec ADDED
@@ -0,0 +1,113 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{chillfile}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["dpree"]
12
+ s.date = %q{2010-12-08}
13
+ s.default_executable = %q{chillfile}
14
+ s.description = %q{Let your files chill on the couch}
15
+ s.email = %q{whiterabbit.init@gmail.com}
16
+ s.executables = ["chillfile"]
17
+ s.extra_rdoc_files = [
18
+ "LICENSE",
19
+ "README.md"
20
+ ]
21
+ s.files = [
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE",
26
+ "README.md",
27
+ "Rakefile",
28
+ "autotest/discover.rb",
29
+ "bin/chillfile",
30
+ "chillfile.gemspec",
31
+ "lib/chillfile.rb",
32
+ "lib/chillfile/cli.rb",
33
+ "lib/chillfile/config.rb",
34
+ "lib/chillfile/database_server.rb",
35
+ "lib/chillfile/model.rb",
36
+ "lib/chillfile/model/base.rb",
37
+ "lib/chillfile/model/sync_file.rb",
38
+ "lib/chillfile/sync.rb",
39
+ "spec/filesystem_after/bar.1.moved.untouched",
40
+ "spec/filesystem_after/bar.2.moved.copy",
41
+ "spec/filesystem_after/bar.3.moved.copy",
42
+ "spec/filesystem_after/foo.fx.copy",
43
+ "spec/filesystem_after/foo.untouched",
44
+ "spec/filesystem_after/moo.new",
45
+ "spec/filesystem_after/subdir_b/bar.4.moved.copy",
46
+ "spec/filesystem_before/bar.0.moved.deleted",
47
+ "spec/filesystem_before/bar.1.moved.untouched",
48
+ "spec/filesystem_before/foo.untouched",
49
+ "spec/filesystem_before/subdir/mii.deleted",
50
+ "spec/filesystem_before/wuu.deleted",
51
+ "spec/fixtures/filesystem_after.json",
52
+ "spec/fixtures/filesystem_before.json",
53
+ "spec/lib/chillfile/model/sync_file_spec.rb",
54
+ "spec/lib/chillfile_spec.rb",
55
+ "spec/spec_helper.rb",
56
+ "spec/support/db_helper.rb",
57
+ "spec/support/fixtures_helper.rb",
58
+ "spec/support/fs_helper.rb",
59
+ "spec/support/list_helper.rb",
60
+ "version.yml"
61
+ ]
62
+ s.homepage = %q{http://github.com/dpree/chillfile}
63
+ s.require_paths = ["lib"]
64
+ s.rubygems_version = %q{1.3.7}
65
+ s.summary = %q{Tiny tool to sync filesystem with couchdb}
66
+ s.test_files = [
67
+ "spec/lib/chillfile/model/sync_file_spec.rb",
68
+ "spec/lib/chillfile_spec.rb",
69
+ "spec/spec_helper.rb",
70
+ "spec/support/db_helper.rb",
71
+ "spec/support/fixtures_helper.rb",
72
+ "spec/support/fs_helper.rb",
73
+ "spec/support/list_helper.rb"
74
+ ]
75
+
76
+ if s.respond_to? :specification_version then
77
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
78
+ s.specification_version = 3
79
+
80
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
81
+ s.add_runtime_dependency(%q<couchrest>, [">= 0"])
82
+ s.add_runtime_dependency(%q<couchrest_model>, [">= 0"])
83
+ s.add_runtime_dependency(%q<treedisha>, ["~> 0.0.2"])
84
+ s.add_runtime_dependency(%q<json>, [">= 0"])
85
+ s.add_runtime_dependency(%q<thor>, [">= 0"])
86
+ s.add_runtime_dependency(%q<thor>, ["~> 0.14.6"])
87
+ s.add_runtime_dependency(%q<couchrest>, ["~> 1.0.1"])
88
+ s.add_runtime_dependency(%q<treedisha>, ["~> 0.0.2"])
89
+ s.add_development_dependency(%q<rspec>, ["~> 2.0.0"])
90
+ else
91
+ s.add_dependency(%q<couchrest>, [">= 0"])
92
+ s.add_dependency(%q<couchrest_model>, [">= 0"])
93
+ s.add_dependency(%q<treedisha>, ["~> 0.0.2"])
94
+ s.add_dependency(%q<json>, [">= 0"])
95
+ s.add_dependency(%q<thor>, [">= 0"])
96
+ s.add_dependency(%q<thor>, ["~> 0.14.6"])
97
+ s.add_dependency(%q<couchrest>, ["~> 1.0.1"])
98
+ s.add_dependency(%q<treedisha>, ["~> 0.0.2"])
99
+ s.add_dependency(%q<rspec>, ["~> 2.0.0"])
100
+ end
101
+ else
102
+ s.add_dependency(%q<couchrest>, [">= 0"])
103
+ s.add_dependency(%q<couchrest_model>, [">= 0"])
104
+ s.add_dependency(%q<treedisha>, ["~> 0.0.2"])
105
+ s.add_dependency(%q<json>, [">= 0"])
106
+ s.add_dependency(%q<thor>, [">= 0"])
107
+ s.add_dependency(%q<thor>, ["~> 0.14.6"])
108
+ s.add_dependency(%q<couchrest>, ["~> 1.0.1"])
109
+ s.add_dependency(%q<treedisha>, ["~> 0.0.2"])
110
+ s.add_dependency(%q<rspec>, ["~> 2.0.0"])
111
+ end
112
+ end
113
+
@@ -0,0 +1,63 @@
1
+ module Chillfile
2
+ # CLI handles the command line interface for the `chillfile` binary. It is a `Thor` application.
3
+ class CLI < ::Thor
4
+
5
+ class_option "path",
6
+ :default => ".",
7
+ :aliases => '-p',
8
+ :banner => "Path to files"
9
+
10
+ class_option "couchdb_server",
11
+ :default => "http://localhost:5984",
12
+ :aliases => '-s',
13
+ :banner => "CouchDB Server URL"
14
+
15
+ class_option "couchdb_database",
16
+ :default => "chillfile",
17
+ :aliases => '-db',
18
+ :banner => "CouchDB Database name"
19
+
20
+ class_option "couchdb_type_key",
21
+ :default => "type",
22
+ :aliases => '-tk',
23
+ :banner => "Attribute name of a CouchDB doc to describe its type"
24
+
25
+ class_option "version",
26
+ :type => :boolean,
27
+ :aliases => '-v',
28
+ :banner => "print version and exit"
29
+
30
+ # create a new instance with the args passed from the command line i.e. ARGV
31
+ def initialize(*)
32
+ super
33
+
34
+ cfg = {}
35
+ cfg["path"] = options[:path]
36
+ cfg["couchdb_server"] = options[:couchdb_server]
37
+ cfg["couchdb_database"] = options[:couchdb_database]
38
+ cfg["couchdb_type_key"] = options[:couchdb_type_key]
39
+
40
+ Chillfile.boot!(cfg)
41
+
42
+ if options[:version]
43
+ say "chillfile v#{Chillfile::VERSION}", :red
44
+ exit
45
+ end
46
+ end
47
+
48
+ desc 'sync', 'sync filesystem into db'
49
+ def sync
50
+ Chillfile.sync!
51
+ end
52
+
53
+ desc 'fslist', 'json list of files in the filesystem'
54
+ def fslist
55
+ say Chillfile.fs_list
56
+ end
57
+
58
+ desc 'dblist', 'json list of files in the couchdb'
59
+ def dblist
60
+ say Chillfile.db_list
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,40 @@
1
+ module Chillfile
2
+ class Config
3
+ CONFIG_FILE = ".chillfile"
4
+
5
+ DEFAULTS = {
6
+ "path" => ".",
7
+ "couchdb_server" => "http://localhost:5984",
8
+ "couchdb_database" => "chillfile",
9
+ "couchdb_type_key" => "type"
10
+ }.freeze
11
+
12
+ def initialize(options = {})
13
+ @config = {}.merge(DEFAULTS)
14
+ if File.exists?(CONFIG_FILE)
15
+ file = File.read(CONFIG_FILE)
16
+ @config.merge(JSON.parse(file))
17
+ else
18
+ #TODO use a logger
19
+ #TODO only show the following line in debug loglevel
20
+ #puts "no config file ('#{CONFIG_FILE}') found => using defaults"
21
+ end
22
+ @config.merge!(options) if options
23
+ @config.freeze
24
+ end
25
+
26
+ def [](key)
27
+ if @config.has_key? key
28
+ @config[key]
29
+ else
30
+ false
31
+ end
32
+ end
33
+
34
+ def with_path
35
+ Dir.chdir self["path"] do
36
+ yield
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,11 @@
1
+ module Chillfile
2
+ module DatabaseServer
3
+ class << self
4
+ def new
5
+ server = CouchRest.new Chillfile.config["couchdb_server"]
6
+ server.default_database = Chillfile.config["couchdb_database"]
7
+ server
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,3 @@
1
+ class Chillfile::Model::Base < CouchRest::Model::Base
2
+ use_database Chillfile.db
3
+ end
@@ -0,0 +1,28 @@
1
+ class Chillfile::Model::SyncFile < Chillfile::Model::Base
2
+ timestamps!
3
+ property :checksum, String
4
+ property :paths, [String]
5
+
6
+ # alternative to paths.empty?
7
+ property :deleted, TrueClass, :default => false
8
+
9
+ validates_uniqueness_of :checksum
10
+
11
+ view_by :checksum
12
+
13
+ view_by :filesystem, :map => "
14
+ function(doc) {
15
+ if (doc['type'] == 'Chillfile::Model::SyncFile') {
16
+ for (var i = 0; i < doc['paths'].length; i++) {
17
+ emit(null, [doc['checksum'], doc['paths'][i]]);
18
+ }
19
+ }
20
+ }
21
+ "
22
+
23
+ def self.by_filesystem_raw
24
+ self.by_filesystem(:include_docs => false)["rows"].map do |f|
25
+ f["value"]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ module Chillfile
2
+ module Model
3
+ def self.load!
4
+ configure!
5
+
6
+ # all models
7
+ require File.join(File.dirname(__FILE__), "model/base")
8
+ require File.join(File.dirname(__FILE__), "model/sync_file")
9
+ end
10
+
11
+ private
12
+
13
+ def self.configure!
14
+ CouchRest::Model::Base.configure do |config|
15
+ config.mass_assign_any_attribute = true
16
+ config.model_type_key = Chillfile.config["couchdb_type_key"]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,118 @@
1
+ module Chillfile
2
+ module Sync
3
+ class << self
4
+ def process!(comparator)
5
+
6
+ # created files
7
+ comparator.created.each do |checksum, path|
8
+ for_doc_with(checksum) do |doc|
9
+ if doc
10
+ update_doc_add_path(doc, path)
11
+ else
12
+ create_doc(checksum, path)
13
+ end
14
+ end
15
+ end
16
+
17
+ # moved files
18
+ comparator.moved.each do |checksum, paths|
19
+ for_doc_with(checksum) do |doc|
20
+ update_doc_paths(doc, paths[:old_paths], paths[:new_paths])
21
+ end
22
+ end
23
+
24
+ # modified files
25
+ comparator.modified.each do |path, checksums|
26
+ for_doc_with(checksums[:old_checksum]) do |doc|
27
+
28
+ # split it up if there is more than one path
29
+ if doc.paths.size > 1
30
+ base_doc = update_doc_paths(doc, [path]),
31
+ forked_doc = create_doc(checksums[:new_checksum], path)
32
+
33
+ [base_doc, forked_doc]
34
+ else
35
+ update_doc_attachment(doc)
36
+ end
37
+ end
38
+ end
39
+
40
+ # deleted
41
+ comparator.deleted.each do |checksum, path|
42
+ for_doc_with(checksum) do |doc|
43
+ if doc.paths.size > 1
44
+ update_doc_paths(doc, [path])
45
+ else
46
+ delete_doc(doc)
47
+ end
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+
54
+ # CREATED
55
+ def create_doc(checksum, path)
56
+ doc = Chillfile::Model::SyncFile.new(:checksum => checksum, :paths => [path])
57
+ doc.save
58
+ begin
59
+ file = File.open(path)
60
+ doc.create_attachment(:file => file, :name => "master")
61
+ ensure
62
+ file.close
63
+ end
64
+ doc
65
+ end
66
+
67
+ # COPIED
68
+ def update_doc_add_path(doc, path)
69
+ doc.paths << path
70
+
71
+ doc
72
+ end
73
+
74
+ # MOVED
75
+ def update_doc_paths(doc, del_paths = [], add_paths = [])
76
+ # del old paths
77
+ del_paths.each do |path|
78
+ doc.paths.delete(path)
79
+ end
80
+
81
+ # add new paths
82
+ doc.paths = doc.paths + add_paths
83
+
84
+ doc
85
+ end
86
+
87
+ # MODIFIED
88
+ def update_doc_attachment(doc)
89
+ doc.checksum = checksums[:new_checksum]
90
+ begin
91
+ file = File.open(doc.paths.first)
92
+ doc.update_attachment(:file => file, :name => "master")
93
+ ensure
94
+ file.close
95
+ end
96
+ doc
97
+ end
98
+
99
+ # DELETED
100
+ def delete_doc(doc)
101
+ doc.deleted = true
102
+ doc.paths = []
103
+ doc
104
+ end
105
+
106
+ # wrapper
107
+ def for_doc_with(checksum, &block)
108
+ old_doc = Chillfile::Model::SyncFile.by_checksum(:key => checksum).first
109
+ new_doc_or_docs = block.call(old_doc)
110
+ if new_doc_or_docs.is_a? Array
111
+ new_doc_or_docs.each{|d| d.save}
112
+ else
113
+ new_doc_or_docs.save
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
data/lib/chillfile.rb ADDED
@@ -0,0 +1,56 @@
1
+ require "yaml"
2
+
3
+ require 'rubygems'
4
+ require "couchrest"
5
+ require 'couchrest_model'
6
+ require "treedisha"
7
+ require "json"
8
+ require "thor"
9
+
10
+ require File.join(File.dirname(__FILE__), "chillfile/config")
11
+ require File.join(File.dirname(__FILE__), "chillfile/cli")
12
+ require File.join(File.dirname(__FILE__), "chillfile/database_server")
13
+ require File.join(File.dirname(__FILE__), "chillfile/sync")
14
+ require File.join(File.dirname(__FILE__), "chillfile/model")
15
+
16
+ module Chillfile
17
+ get_version = lambda do
18
+ v = YAML.parse_file(File.join(File.dirname(__FILE__), "../version.yml"))
19
+ "#{v[:major].value}.#{v[:minor].value}.#{v[:patch].value}"
20
+ end
21
+ VERSION = get_version.call
22
+
23
+ class << self
24
+ def boot!(config = {})
25
+ @@config = Chillfile::Config.new(config)
26
+ @@dbserver = Chillfile::DatabaseServer.new
27
+ Chillfile::Model.load!
28
+ true
29
+ end
30
+
31
+ def config
32
+ @@config
33
+ end
34
+ def db
35
+ @@dbserver.default_database
36
+ end
37
+
38
+ def sync!
39
+ fs = fs_list
40
+ db = db_list
41
+ comparator = Treedisha::Comparator.new(fs_list, db_list)
42
+
43
+ Chillfile::Sync.process!(comparator)
44
+ end
45
+
46
+ # filesystem
47
+ def fs_list
48
+ Treedisha::Filesystem.all_files_with_sha1(config["path"])
49
+ end
50
+
51
+ # databse
52
+ def db_list
53
+ Chillfile::Model::SyncFile.by_filesystem_raw
54
+ end
55
+ end
56
+ end
@@ -0,0 +1 @@
1
+ i moved using this special code: 1337
@@ -0,0 +1 @@
1
+ i moved using this special code: 1337
File without changes
@@ -0,0 +1 @@
1
+ foo :D
@@ -0,0 +1 @@
1
+ foo :D
@@ -0,0 +1 @@
1
+ i am a new file :D
@@ -0,0 +1 @@
1
+ i moved using this special code: 1337
@@ -0,0 +1 @@
1
+ i moved using this special code: 1337
File without changes
@@ -0,0 +1 @@
1
+ foo :D
@@ -0,0 +1,3 @@
1
+ i was another deleted file :'(
2
+
3
+ just sooo sad..
@@ -0,0 +1,3 @@
1
+ i will be deleted :/
2
+
3
+ stop staring at me!!! stfu!
@@ -0,0 +1 @@
1
+ [["ab4b262b83ad979d10a2c3c633242bb222ba74e7", "./bar.1.moved.untouched"], ["ab4b262b83ad979d10a2c3c633242bb222ba74e7", "./bar.2.moved.copy"], ["da39a3ee5e6b4b0d3255bfef95601890afd80709", "./bar.3.moved.copy"], ["83a4f6db0964dd03480be5f781eec6c5c2f7f5f2", "./foo.fx.copy"], ["83a4f6db0964dd03480be5f781eec6c5c2f7f5f2", "./foo.untouched"], ["cd84598b6fcb747a2b1954934b964e5a5c27836e", "./moo.new"], ["ab4b262b83ad979d10a2c3c633242bb222ba74e7", "./subdir_b/bar.4.moved.copy"]]
@@ -0,0 +1 @@
1
+ [["ab4b262b83ad979d10a2c3c633242bb222ba74e7", "./bar.0.moved.deleted"], ["da39a3ee5e6b4b0d3255bfef95601890afd80709", "./bar.1.moved.untouched"], ["83a4f6db0964dd03480be5f781eec6c5c2f7f5f2", "./foo.untouched"], ["5ab7aa2b4aaa458fd89089ce4384102a33bf7765", "./subdir/mii.deleted"], ["c0ae0100acd4b0063535dd8fbbdf87919741e320", "./wuu.deleted"]]
@@ -0,0 +1,18 @@
1
+ require "spec_helper"
2
+
3
+ describe Chillfile::Model::SyncFile do
4
+ include DbHelper
5
+
6
+ before(:each) do
7
+ reset_db!
8
+ end
9
+
10
+ it "should be possible create a file" do
11
+ Chillfile::Model::SyncFile.new(:paths => ["./foo/bar.baz"], :checksum => "13123f6casdd03480be5f781ee12312asdasd232").save.persisted?.should be_true
12
+ end
13
+
14
+ it "should be possible to find using a checksum" do
15
+ Chillfile::Model::SyncFile.new(:paths => ["./foo/bar.baz", "./woo_lands"], :checksum => "13123f6casdd03480be5f781ee12312asdasd232").save
16
+ Chillfile::Model::SyncFile.by_checksum(:key => "13123f6casdd03480be5f781ee12312asdasd232").first[:paths].should == ["./foo/bar.baz", "./woo_lands"]
17
+ end
18
+ end
@@ -0,0 +1,37 @@
1
+ require "spec_helper"
2
+
3
+ describe Chillfile do
4
+ include ListHelper
5
+ include FsHelper
6
+ include DbHelper
7
+
8
+ before(:each) do
9
+ @before_list = sort_by_path(FixturesHelper.parse_json_file("filesystem_before.json"))
10
+ @after_list = sort_by_path(FixturesHelper.parse_json_file("filesystem_after.json"))
11
+ reset_db!
12
+ switch_fs!
13
+ end
14
+
15
+ it "should be possible to list from different fs" do
16
+ @before_list.should_not == @after_list
17
+ Chillfile.fs_list.should == @before_list
18
+
19
+ switch_fs!(:after)
20
+ Chillfile.fs_list.should == @after_list
21
+ end
22
+
23
+ it "should be possible to list from db" do
24
+ Chillfile::Model::SyncFile.new(:paths => ["./foo/bar.baz"], :checksum => "13123f6casdd03480be5f781ee12312asdasd232").save
25
+ Chillfile.db_list.should == [["13123f6casdd03480be5f781ee12312asdasd232", "./foo/bar.baz"]]
26
+ end
27
+
28
+ it "should be possible to sync from fs to db" do
29
+ Chillfile.sync!
30
+ sort_by_path(Chillfile.db_list).should == @before_list
31
+
32
+ switch_fs!(:after)
33
+
34
+ Chillfile.sync!
35
+ sort_by_path(Chillfile.db_list).should == @after_list
36
+ end
37
+ end
@@ -0,0 +1,15 @@
1
+ require "rubygems"
2
+ require "rspec"
3
+
4
+ require File.join(File.dirname(__FILE__), "../lib/chillfile")
5
+
6
+ require File.join(File.dirname(__FILE__), "support/fixtures_helper")
7
+ require File.join(File.dirname(__FILE__), "support/list_helper")
8
+ require File.join(File.dirname(__FILE__), "support/db_helper")
9
+ require File.join(File.dirname(__FILE__), "support/fs_helper")
10
+
11
+ FsHelper.switch_fs!
12
+
13
+ Chillfile.boot!("couchdb_database" => "chillfile-tests")
14
+
15
+ DbHelper.reset_db!
@@ -0,0 +1,10 @@
1
+ module DbHelper
2
+ def self.reset_db!
3
+ Chillfile.db.recreate!
4
+ end
5
+
6
+ # alias
7
+ def reset_db!
8
+ DbHelper.reset_db!
9
+ end
10
+ end
@@ -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.parse_json_file(filename)
8
+ JSON.parse(read_file(filename))
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module FsHelper
2
+ def self.switch_fs!(state = :before)
3
+ Dir.chdir(File.join(File.dirname(__FILE__), "../filesystem_#{state}"))
4
+ end
5
+
6
+ # alias
7
+ def switch_fs!(*args)
8
+ FsHelper.switch_fs!(*args)
9
+ end
10
+ end
@@ -0,0 +1,5 @@
1
+ module ListHelper
2
+ def sort_by_path(list)
3
+ list.sort!{|a,b| a.last <=> b.last}
4
+ end
5
+ end
data/version.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :major: 0
3
+ :minor: 0
4
+ :patch: 1
5
+ :build:
metadata ADDED
@@ -0,0 +1,235 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: chillfile
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
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: chillfile
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: couchrest
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :runtime
31
+ prerelease: false
32
+ version_requirements: *id001
33
+ - !ruby/object:Gem::Dependency
34
+ name: couchrest_model
35
+ requirement: &id002 !ruby/object:Gem::Requirement
36
+ none: false
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ segments:
41
+ - 0
42
+ version: "0"
43
+ type: :runtime
44
+ prerelease: false
45
+ version_requirements: *id002
46
+ - !ruby/object:Gem::Dependency
47
+ name: treedisha
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ segments:
54
+ - 0
55
+ - 0
56
+ - 2
57
+ version: 0.0.2
58
+ type: :runtime
59
+ prerelease: false
60
+ version_requirements: *id003
61
+ - !ruby/object:Gem::Dependency
62
+ name: json
63
+ requirement: &id004 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: *id004
74
+ - !ruby/object:Gem::Dependency
75
+ name: thor
76
+ requirement: &id005 !ruby/object:Gem::Requirement
77
+ none: false
78
+ requirements:
79
+ - - ">="
80
+ - !ruby/object:Gem::Version
81
+ segments:
82
+ - 0
83
+ version: "0"
84
+ type: :runtime
85
+ prerelease: false
86
+ version_requirements: *id005
87
+ - !ruby/object:Gem::Dependency
88
+ name: thor
89
+ requirement: &id006 !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ~>
93
+ - !ruby/object:Gem::Version
94
+ segments:
95
+ - 0
96
+ - 14
97
+ - 6
98
+ version: 0.14.6
99
+ type: :runtime
100
+ prerelease: false
101
+ version_requirements: *id006
102
+ - !ruby/object:Gem::Dependency
103
+ name: couchrest
104
+ requirement: &id007 !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ segments:
110
+ - 1
111
+ - 0
112
+ - 1
113
+ version: 1.0.1
114
+ type: :runtime
115
+ prerelease: false
116
+ version_requirements: *id007
117
+ - !ruby/object:Gem::Dependency
118
+ name: treedisha
119
+ requirement: &id008 !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ~>
123
+ - !ruby/object:Gem::Version
124
+ segments:
125
+ - 0
126
+ - 0
127
+ - 2
128
+ version: 0.0.2
129
+ type: :runtime
130
+ prerelease: false
131
+ version_requirements: *id008
132
+ - !ruby/object:Gem::Dependency
133
+ name: rspec
134
+ requirement: &id009 !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ~>
138
+ - !ruby/object:Gem::Version
139
+ segments:
140
+ - 2
141
+ - 0
142
+ - 0
143
+ version: 2.0.0
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: *id009
147
+ description: Let your files chill on the couch
148
+ email: whiterabbit.init@gmail.com
149
+ executables:
150
+ - chillfile
151
+ extensions: []
152
+
153
+ extra_rdoc_files:
154
+ - LICENSE
155
+ - README.md
156
+ files:
157
+ - .rspec
158
+ - Gemfile
159
+ - Gemfile.lock
160
+ - LICENSE
161
+ - README.md
162
+ - Rakefile
163
+ - autotest/discover.rb
164
+ - bin/chillfile
165
+ - chillfile.gemspec
166
+ - lib/chillfile.rb
167
+ - lib/chillfile/cli.rb
168
+ - lib/chillfile/config.rb
169
+ - lib/chillfile/database_server.rb
170
+ - lib/chillfile/model.rb
171
+ - lib/chillfile/model/base.rb
172
+ - lib/chillfile/model/sync_file.rb
173
+ - lib/chillfile/sync.rb
174
+ - spec/filesystem_after/bar.1.moved.untouched
175
+ - spec/filesystem_after/bar.2.moved.copy
176
+ - spec/filesystem_after/bar.3.moved.copy
177
+ - spec/filesystem_after/foo.fx.copy
178
+ - spec/filesystem_after/foo.untouched
179
+ - spec/filesystem_after/moo.new
180
+ - spec/filesystem_after/subdir_b/bar.4.moved.copy
181
+ - spec/filesystem_before/bar.0.moved.deleted
182
+ - spec/filesystem_before/bar.1.moved.untouched
183
+ - spec/filesystem_before/foo.untouched
184
+ - spec/filesystem_before/subdir/mii.deleted
185
+ - spec/filesystem_before/wuu.deleted
186
+ - spec/fixtures/filesystem_after.json
187
+ - spec/fixtures/filesystem_before.json
188
+ - spec/lib/chillfile/model/sync_file_spec.rb
189
+ - spec/lib/chillfile_spec.rb
190
+ - spec/spec_helper.rb
191
+ - spec/support/db_helper.rb
192
+ - spec/support/fixtures_helper.rb
193
+ - spec/support/fs_helper.rb
194
+ - spec/support/list_helper.rb
195
+ - version.yml
196
+ has_rdoc: true
197
+ homepage: http://github.com/dpree/chillfile
198
+ licenses: []
199
+
200
+ post_install_message:
201
+ rdoc_options: []
202
+
203
+ require_paths:
204
+ - lib
205
+ required_ruby_version: !ruby/object:Gem::Requirement
206
+ none: false
207
+ requirements:
208
+ - - ">="
209
+ - !ruby/object:Gem::Version
210
+ segments:
211
+ - 0
212
+ version: "0"
213
+ required_rubygems_version: !ruby/object:Gem::Requirement
214
+ none: false
215
+ requirements:
216
+ - - ">="
217
+ - !ruby/object:Gem::Version
218
+ segments:
219
+ - 0
220
+ version: "0"
221
+ requirements: []
222
+
223
+ rubyforge_project:
224
+ rubygems_version: 1.3.7
225
+ signing_key:
226
+ specification_version: 3
227
+ summary: Tiny tool to sync filesystem with couchdb
228
+ test_files:
229
+ - spec/lib/chillfile/model/sync_file_spec.rb
230
+ - spec/lib/chillfile_spec.rb
231
+ - spec/spec_helper.rb
232
+ - spec/support/db_helper.rb
233
+ - spec/support/fixtures_helper.rb
234
+ - spec/support/fs_helper.rb
235
+ - spec/support/list_helper.rb