reflection 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,21 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ *.tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ coverage
18
+ rdoc
19
+ pkg
20
+
21
+ ## PROJECT::SPECIFIC
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Andreas Wolff
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,20 @@
1
+ = reflection
2
+
3
+ Helps you keeping your development machine in sync with production.
4
+ Currently just a snapshot, so don't use it for any important stuff (you could loose important data).
5
+
6
+
7
+ == Note on Patches/Pull Requests
8
+
9
+ * Fork the project.
10
+ * Make your feature addition or bug fix.
11
+ * Add tests for it. This is important so I don't break it in a
12
+ future version unintentionally.
13
+ * Commit, do not mess with rakefile, version, or history.
14
+ (if you want to have your own version, that is fine but
15
+ bump version in a commit by itself I can ignore when I pull)
16
+ * Send me a pull request. Bonus points for topic branches.
17
+
18
+ == Copyright
19
+
20
+ Copyright (c) 2009 Andreas Wolff. See LICENSE for details.
@@ -0,0 +1,75 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "reflection"
8
+ gem.summary = %Q{Helps you keeping your development machine in sync with production.}
9
+ gem.description = %Q{
10
+ Reflection is designed to keep your production assets (database comming soon) in sync with your development system.
11
+ It uses a shared git repository to store these files, which allows you to mirror your production environment without the need of
12
+ direct access to your production servers.
13
+ }
14
+ gem.email = "rubyphunk@gmail.com"
15
+ gem.homepage = "http://github.com/rubyphunk/reflection"
16
+ gem.authors = ["Andreas Wolff"]
17
+ gem.add_development_dependency "rspec", ">= 1.2.9"
18
+ gem.add_dependency "git", ">= 1.2.5"
19
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
20
+ end
21
+ Jeweler::GemcutterTasks.new
22
+ rescue LoadError
23
+ puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
24
+ end
25
+
26
+ require 'spec/rake/spectask'
27
+ Spec::Rake::SpecTask.new(:spec) do |spec|
28
+ spec.libs << 'lib' << 'spec'
29
+ spec.spec_files = FileList['spec/**/*_spec.rb']
30
+ end
31
+
32
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
33
+ spec.libs << 'lib' << 'spec'
34
+ spec.pattern = 'spec/**/*_spec.rb'
35
+ spec.rcov = true
36
+ end
37
+
38
+ task :spec => :check_dependencies
39
+
40
+ begin
41
+ require 'reek/adapters/rake_task'
42
+ Reek::RakeTask.new do |t|
43
+ t.fail_on_error = true
44
+ t.verbose = false
45
+ t.source_files = 'lib/**/*.rb'
46
+ end
47
+ rescue LoadError
48
+ task :reek do
49
+ abort "Reek is not available. In order to run reek, you must: sudo gem install reek"
50
+ end
51
+ end
52
+
53
+ begin
54
+ require 'roodi'
55
+ require 'roodi_task'
56
+ RoodiTask.new do |t|
57
+ t.verbose = false
58
+ end
59
+ rescue LoadError
60
+ task :roodi do
61
+ abort "Roodi is not available. In order to run roodi, you must: sudo gem install roodi"
62
+ end
63
+ end
64
+
65
+ task :default => :spec
66
+
67
+ require 'rake/rdoctask'
68
+ Rake::RDocTask.new do |rdoc|
69
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
70
+
71
+ rdoc.rdoc_dir = 'rdoc'
72
+ rdoc.title = "reflection #{version}"
73
+ rdoc.rdoc_files.include('README*')
74
+ rdoc.rdoc_files.include('lib/**/*.rb')
75
+ end
@@ -0,0 +1,93 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{reflection}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andreas Wolff"]
12
+ s.date = %q{2009-11-15}
13
+ s.default_executable = %q{reflection}
14
+ s.description = %q{
15
+ Reflection is designed to keep your production assets (database comming soon) in sync with your development system.
16
+ It uses a shared git repository to store these files, which allows you to mirror your production environment without the need of
17
+ direct access to your production servers.
18
+ }
19
+ s.email = %q{rubyphunk@gmail.com}
20
+ s.executables = ["reflection"]
21
+ s.extra_rdoc_files = [
22
+ "LICENSE",
23
+ "README.rdoc"
24
+ ]
25
+ s.files = [
26
+ ".document",
27
+ ".gitignore",
28
+ "LICENSE",
29
+ "README.rdoc",
30
+ "Rakefile",
31
+ "Reflection.gemspec",
32
+ "TODO",
33
+ "VERSION",
34
+ "bin/reflection",
35
+ "lib/reflection.rb",
36
+ "lib/reflection/cli.rb",
37
+ "lib/reflection/command.rb",
38
+ "lib/reflection/command/apply.rb",
39
+ "lib/reflection/command/base.rb",
40
+ "lib/reflection/command/stash.rb",
41
+ "lib/reflection/directory.rb",
42
+ "lib/reflection/directory/base.rb",
43
+ "lib/reflection/directory/stash.rb",
44
+ "lib/reflection/repository.rb",
45
+ "lib/reflection/support.rb",
46
+ "lib/reflection/support/home.rb",
47
+ "lib/reflection/support/log.rb",
48
+ "lib/reflection/validations.rb",
49
+ "spec/reflection/cli_spec.rb",
50
+ "spec/reflection/command/stash_spec.rb",
51
+ "spec/reflection/directory/base_spec.rb",
52
+ "spec/reflection/directory/stash_spec.rb",
53
+ "spec/reflection/repository_spec.rb",
54
+ "spec/reflection/support/home_spec.rb",
55
+ "spec/reflection/support_spec.rb",
56
+ "spec/reflection_spec.rb",
57
+ "spec/spec.opts",
58
+ "spec/spec_helper.rb"
59
+ ]
60
+ s.homepage = %q{http://github.com/rubyphunk/reflection}
61
+ s.rdoc_options = ["--charset=UTF-8"]
62
+ s.require_paths = ["lib"]
63
+ s.rubygems_version = %q{1.3.5}
64
+ s.summary = %q{Helps you keeping your development machine in sync with production.}
65
+ s.test_files = [
66
+ "spec/reflection/cli_spec.rb",
67
+ "spec/reflection/command/stash_spec.rb",
68
+ "spec/reflection/directory/base_spec.rb",
69
+ "spec/reflection/directory/stash_spec.rb",
70
+ "spec/reflection/repository_spec.rb",
71
+ "spec/reflection/support/home_spec.rb",
72
+ "spec/reflection/support_spec.rb",
73
+ "spec/reflection_spec.rb",
74
+ "spec/spec_helper.rb"
75
+ ]
76
+
77
+ if s.respond_to? :specification_version then
78
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
79
+ s.specification_version = 3
80
+
81
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
82
+ s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
83
+ s.add_runtime_dependency(%q<git>, [">= 1.2.5"])
84
+ else
85
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
86
+ s.add_dependency(%q<git>, [">= 1.2.5"])
87
+ end
88
+ else
89
+ s.add_dependency(%q<rspec>, [">= 1.2.9"])
90
+ s.add_dependency(%q<git>, [">= 1.2.5"])
91
+ end
92
+ end
93
+
data/TODO ADDED
@@ -0,0 +1,7 @@
1
+ + Add DB Dumper (include in cli-opt-parser)
2
+ + Remove stash directory if its empty (on reinit)
3
+ + Add Logger (Reflection::Support.log)
4
+ + After command callbacks: Twitter, Campfire on Serverside
5
+ + List existing reflections in client side
6
+ + Allow to apply any (git) version, not just the latest
7
+ + Allow collection of assets from Akamai and/or CloudFront
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'reflection'
4
+
5
+ Reflection::boot!(ARGV)
@@ -0,0 +1,24 @@
1
+ require 'rubygems'
2
+
3
+ module Reflection
4
+ autoload :CLI, 'reflection/cli'
5
+ autoload :Command, 'reflection/command'
6
+ autoload :Directory, 'reflection/directory'
7
+ autoload :Repository, 'reflection/repository'
8
+ autoload :Support, 'reflection/support'
9
+ autoload :Validations, 'reflection/validations'
10
+
11
+ class << self
12
+
13
+ attr_accessor :home
14
+ attr_accessor :log
15
+
16
+ def boot!(args)
17
+ @log = Reflection::Support::Log.new
18
+ @home = Reflection::Support::Home.new
19
+ @home.create
20
+ Reflection::CLI.run!(args)
21
+ end
22
+
23
+ end
24
+ end
@@ -0,0 +1,65 @@
1
+ require 'optparse'
2
+ require 'ostruct'
3
+
4
+ module Reflection
5
+ module CLI
6
+ class << self
7
+
8
+ def run!(args = nil)
9
+ options = parse_options(args)
10
+ if options == false
11
+ Reflection::Support.exit_with_error("Ahh ja, missing arguments. Please read 'reflection --help' to get a feeling of how it works.")
12
+ else
13
+ case options.command
14
+ when :apply
15
+ Reflection::Command::Apply.run!(options)
16
+ when :stash
17
+ Reflection::Command::Stash.run!(options)
18
+ else
19
+ Reflection::Support.exit_with_error("Couldn't identify command. Please run 'reflection --help'.")
20
+ end
21
+ end
22
+ end
23
+
24
+ def parse_options(args)
25
+ options = OpenStruct.new
26
+
27
+ opt_parser = OptionParser.new do |opts|
28
+ opts.banner = "Usage: reflection --COMMAND --repository=GIT_REPO --directory=PATH"
29
+
30
+ opts.separator " "
31
+ opts.separator "On the server side:"
32
+
33
+ opts.on("-s", "--stash", "Store your assets and/or a database dump in a git-repository.") do |stash|
34
+ options.command = :stash
35
+ end
36
+
37
+ opts.separator "On the client side:"
38
+ opts.on("-a", "--apply", "Apply assets and/or a database dump loaded from a git-repository.") do |apply|
39
+ options.command = :apply
40
+ end
41
+
42
+ opts.separator " "
43
+ opts.separator "Required options for both:"
44
+ opts.on("-r", "--repository GIT_URL", "A Git repository(url) to be used as storage") do |repository|
45
+ options.repository = repository
46
+ end
47
+
48
+ opts.on("-d", "--directory PATH", "Path to your asset directory") do |directory|
49
+ options.directory = directory
50
+ end
51
+ end
52
+
53
+ opt_parser.parse!(args)
54
+ verify_options(options)
55
+ end
56
+
57
+
58
+ private
59
+
60
+ def verify_options(options)
61
+ return ([:stash, :apply].include?(options.command) && !options.repository.nil? && !options.directory.nil?) ? options : false
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,7 @@
1
+ module Reflection
2
+ module Command
3
+ autoload :Apply, 'reflection/command/apply'
4
+ autoload :Base, 'reflection/command/base'
5
+ autoload :Stash, 'reflection/command/stash'
6
+ end
7
+ end
@@ -0,0 +1,52 @@
1
+ require 'fileutils'
2
+
3
+ module Reflection
4
+ module Command
5
+ class Apply < Reflection::Command::Base
6
+
7
+ def validate!
8
+ validate.existence_of options.directory
9
+ end
10
+
11
+ def run!
12
+ stash_directory = Directory::Stash.new(Reflection::Repository.new(options.repository), 'apply')
13
+ target_directory = Directory::Base.new(options.directory)
14
+
15
+ get_user_approval_for_cleaning_target(target_directory)
16
+ verify_that_target_is_not_a_repository(target_directory)
17
+
18
+ Reflection.log.info "Applying '#{options.repository}' >> '#{options.directory}'.."
19
+
20
+ target_directory.clean!
21
+
22
+ if stash_directory.exists?
23
+ stash_directory.validate_repository
24
+ stash_directory.copy_git_index_to(target_directory.path)
25
+ repo = Repository.new_from_path(target_directory.path)
26
+ repo.reset!
27
+ repo.pull
28
+ stash_directory.get_git_index_from(target_directory.path)
29
+ else
30
+ stash_directory.clone_repository
31
+ stash_directory.move_content_to(target_directory.path)
32
+ stash_directory.get_git_index_from(target_directory.path)
33
+ end
34
+
35
+ Reflection.log.info "Apply Command done."
36
+ end
37
+
38
+
39
+ private
40
+
41
+ def get_user_approval_for_cleaning_target(target_directory)
42
+ puts "\nIn order to get a fresh copy of your files, Reflection will have to remove all files under '#{target_directory.path}'."
43
+ puts "If you're sure, hit <enter> to proceed.."
44
+
45
+ unless STDIN.getc == 10
46
+ puts "Aborting.."
47
+ exit
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+ module Reflection
2
+ module Command
3
+ class Base
4
+ attr_accessor :options
5
+
6
+ def self.run!(options)
7
+ command = self.new(options)
8
+ command.validate! if command.respond_to?(:validate!)
9
+ command.run!
10
+ end
11
+
12
+ def initialize(new_options)
13
+ self.options = new_options
14
+ end
15
+
16
+ def validate
17
+ Reflection::Validations
18
+ end
19
+
20
+ def verify_that_target_is_not_a_repository(target_directory)
21
+ if Repository.exists?(target_directory.path)
22
+ Support.exit_with_error "The specified --directory is a repository. Reflection is afraid of breaking something, so it won't touch it. Pleace specify another one.."
23
+ end
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,61 @@
1
+ require 'fileutils'
2
+
3
+ module Reflection
4
+ module Command
5
+ class Stash < Reflection::Command::Base
6
+
7
+ def validate!
8
+ validate.existence_of options.directory
9
+ end
10
+
11
+ def run!
12
+ Reflection.log.info "Stashing '#{options.directory}'.."
13
+
14
+ stash_directory = Directory::Stash.new(Reflection::Repository.new(options.repository), 'stash')
15
+ target_directory = Directory::Base.new(options.directory)
16
+
17
+ verify_that_target_is_not_a_repository(target_directory)
18
+
19
+ prepare_stash_repository(stash_directory)
20
+ stash_directory_into_repository(stash_directory, target_directory)
21
+
22
+ Reflection.log.info "Stash Command done."
23
+ end
24
+
25
+ def prepare_stash_repository(stash_directory)
26
+ Reflection.log.debug "Preparing stash repository.."
27
+
28
+ if stash_directory.exists?
29
+ stash_directory.validate_repository
30
+ else
31
+ stash_directory.clone_repository
32
+ end
33
+ end
34
+
35
+ def stash_directory_into_repository(stash_directory, target_directory)
36
+ copy_stash_repository_git_index_to_target(stash_directory.git_index, target_directory.path)
37
+ commit_and_push_files(target_directory.path, target_directory.name)
38
+ move_stash_repository_git_index_back(target_directory.git_index, stash_directory.path)
39
+ end
40
+
41
+
42
+ private
43
+
44
+ def copy_stash_repository_git_index_to_target(source, target)
45
+ FileUtils.cp_r(source, target)
46
+ end
47
+
48
+ def commit_and_push_files(repository_path, target)
49
+ repository = Repository.new_from_path(repository_path)
50
+ repository.commit_all_new_files
51
+ repository.push
52
+ end
53
+
54
+ def move_stash_repository_git_index_back(source, target)
55
+ FileUtils.rm_r(File.join(target, "/.git"))
56
+ FileUtils.mv(source, target)
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,6 @@
1
+ module Reflection
2
+ module Directory
3
+ autoload :Base, 'reflection/directory/base'
4
+ autoload :Stash, 'reflection/directory/stash'
5
+ end
6
+ end
@@ -0,0 +1,59 @@
1
+ require 'fileutils'
2
+
3
+ module Reflection
4
+ module Directory
5
+ class Base
6
+
7
+ attr_accessor :path
8
+
9
+ def initialize(new_path)
10
+ self.path = new_path
11
+ end
12
+
13
+ def to_s
14
+ self.path
15
+ end
16
+
17
+ def exists?
18
+ File.exist?(self.path)
19
+ end
20
+
21
+ def clean!
22
+ Reflection.log.debug "Cleaning #{self.path}/.."
23
+ %x(rm -r #{self.path}/*)
24
+ end
25
+
26
+ def parent
27
+ Base.new(File.expand_path(self.path.split('/')[0..-2].join('/')))
28
+ end
29
+
30
+ def name
31
+ self.path.split('/').last
32
+ end
33
+
34
+ def git_index
35
+ File.expand_path(File.join(self.path, '.git'))
36
+ end
37
+
38
+ def copy_git_index_to(target_path)
39
+ Reflection.log.debug "Copying git-index '#{self.git_index}' to #{target_path}"
40
+ FileUtils.cp_r(self.git_index, target_path)
41
+ end
42
+
43
+ def get_git_index_from(target_path)
44
+ Reflection.log.debug "Getting git-index from #{target_path}"
45
+
46
+ %x(rm -rf #{self.git_index}) if File.exists?(self.git_index)
47
+ %x(mkdir -p #{self.path})
48
+ %x(mv -f #{File.join(target_path, '/.git')} #{File.join(self.path, "/")})
49
+ end
50
+
51
+ def move_content_to(target_path)
52
+ Reflection.log.debug "Moving content to '#{target_path}'.."
53
+ FileUtils.cp_r(File.join(self.path, '/.'), target_path)
54
+ FileUtils.rm_r(File.join(self.path, '/'))
55
+ end
56
+
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,30 @@
1
+ module Reflection
2
+ module Directory
3
+ class Stash < Directory::Base
4
+
5
+ attr_accessor :repository
6
+
7
+ def initialize(repository, identifier_prefix)
8
+ @repository = repository
9
+ @identifier_prefix = identifier_prefix
10
+ end
11
+
12
+ def path
13
+ @path = File.join(Reflection.home.path, @identifier_prefix, repository.identifier)
14
+ end
15
+
16
+ def validate_repository
17
+ if Reflection::Repository.exists?(self.path) && !@repository.same_in_path?(self.path)
18
+ Reflection::Support.exit_with_error "The stash directory '#{self.path}' is a repository, but not the one you specified (--repository)."
19
+ else
20
+ Reflection.log.debug "Directory '#{self.path}' valid."
21
+ end
22
+ end
23
+
24
+ def clone_repository
25
+ Reflection.log.debug "Cloning repository '#{self.repository.url}' to '#{self.path}'"
26
+ @repository.clone(self.path)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,71 @@
1
+ require 'digest/md5'
2
+ require 'git'
3
+
4
+ module Reflection
5
+ class Repository
6
+
7
+ attr_accessor :url
8
+ attr_accessor :path
9
+
10
+ def self.new_from_path(path)
11
+ unless self.exists?(path)
12
+ raise "'#{path}' is not a valid Git repository"
13
+ end
14
+
15
+ repo = Git.open(path)
16
+ self.new(repo.remote.url, path)
17
+ end
18
+
19
+ def self.exists?(path)
20
+ begin
21
+ Git.open(path)
22
+ rescue ArgumentError
23
+ return false
24
+ end
25
+ end
26
+
27
+ def initialize(new_url, path = nil)
28
+ self.url = new_url
29
+ self.path = path
30
+ end
31
+
32
+ def identifier
33
+ Digest::MD5.hexdigest(self.url)
34
+ end
35
+
36
+ def same_in_path?(path)
37
+ git_repo = Git.open(path)
38
+ (git_repo.remote && git_repo.remote.url == self.url) || false
39
+ end
40
+
41
+ def reset!
42
+ Reflection.log.debug "Resetting target to HEAD"
43
+ repo = Git.open(self.path)
44
+ repo.reset_hard
45
+ end
46
+
47
+ def clone(path)
48
+ Git.clone(self.url, path)
49
+ end
50
+
51
+ def commit_all_new_files
52
+ repo = Git.open(self.path)
53
+ Reflection.log.debug "Committing all changes.."
54
+ Reflection.log.debug(repo.add)
55
+ Reflection.log.debug(repo.commit_all("Updated stash.")) rescue true
56
+ end
57
+
58
+ def push
59
+ repo = Git.open(self.path)
60
+ Reflection.log.debug "Pushing commit.."
61
+ Reflection.log.debug(repo.push)
62
+ end
63
+
64
+ def pull
65
+ repo = Git.open(self.path)
66
+ Reflection.log.debug "Pulling.."
67
+ Reflection.log.debug(repo.pull)
68
+ end
69
+
70
+ end
71
+ end
@@ -0,0 +1,12 @@
1
+ module Reflection
2
+ module Support
3
+
4
+ autoload :Home, 'reflection/support/home'
5
+ autoload :Log, 'reflection/support/log'
6
+
7
+ def self.exit_with_error(message)
8
+ puts message
9
+ exit(1)
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module Reflection
2
+ module Support
3
+ class Home
4
+
5
+ def path
6
+ @path ||= File.expand_path(File.join(ENV['HOME'], '.reflection'))
7
+ end
8
+
9
+ def create
10
+ unless File.exist?(self.path)
11
+ Dir.mkdir(self.path)
12
+ end
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ module Reflection
2
+ module Support
3
+ class Log
4
+
5
+ def debug(message)
6
+ puts "** #{message}" if message && !message.empty?
7
+ end
8
+
9
+ def info(message)
10
+ puts "** #{message}" if message && !message.empty?
11
+ end
12
+
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ module Reflection
2
+ module Validations
3
+ class << self
4
+
5
+ def existence_of(path)
6
+ if File.exist?(path)
7
+ return true
8
+ else
9
+ Reflection::Support.exit_with_error "Option validation failed: #{path} does not exist."
10
+ end
11
+ end
12
+
13
+ # def presense_of(option)
14
+ # if !option.nil? && !option.empty?
15
+ # return true
16
+ # else
17
+ # exit_with_error "Option validation failed: "
18
+ # end
19
+ # end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Reflection::CLI do
4
+ before(:all) do
5
+ @subject = Reflection::CLI
6
+ end
7
+
8
+ describe '#run!' do
9
+ it 'should parse commandline options' do
10
+ Reflection::Command::Stash.stub!(:run!)
11
+ @subject.should_receive(:parse_options).and_return(OpenStruct.new(:command => :stash))
12
+ @subject.run!
13
+ end
14
+
15
+ it 'should fail gracefully displaying a message if parse_options returns false' do
16
+ Reflection::Support.should_receive(:exit_with_error).with(/reflection --help/)
17
+ @subject.stub!(:parse_options).and_return(false)
18
+ @subject.run!
19
+ end
20
+
21
+ context 'successful parsed options' do
22
+ before(:each) do
23
+ @parse_options = OpenStruct.new(:options => "more")
24
+ @subject.stub!(:parse_options).and_return(@parse_options)
25
+ end
26
+
27
+ it 'should call the Stash command if parse_options returned succesfull with command :stash' do
28
+ @parse_options.command = :stash
29
+ Reflection::Command::Stash.should_receive(:run!).with(@parse_options)
30
+ @subject.run!
31
+ end
32
+
33
+ it 'should call the Apply command if parse_options returned succesfull with command :apply' do
34
+ @parse_options.command = :apply
35
+ Reflection::Command::Apply.should_receive(:run!).with(@parse_options)
36
+ @subject.run!
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,96 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Reflection::Command::Stash do
4
+ before(:each) do
5
+ @options = OpenStruct.new({ :directory => '/home/tmp/fu_asset_directory', :command => :stash })
6
+ @subject = Reflection::Command::Stash.new(@options)
7
+ end
8
+
9
+ describe 'validations' do
10
+ it 'should validate the existence of the directory' do
11
+ Reflection::Validations.should_receive(:existence_of).with('/home/tmp/fu_asset_directory')
12
+ @subject.validate!
13
+ end
14
+ end
15
+
16
+ describe '#run!' do
17
+ before(:each) do
18
+ Reflection::Repository.stub!(:exists?).and_return(false)
19
+ @subject.stub!(:prepare_stash_repository)
20
+ @subject.stub!(:stash_directory_into_repository)
21
+ end
22
+
23
+ it 'should fail if the directory is a repository' do
24
+ Reflection::Repository.stub!(:exists?).and_return(true)
25
+ Reflection::Support.should_receive(:exit_with_error)
26
+ @subject.run!
27
+ end
28
+
29
+ it 'should prepare the stash repository' do
30
+ @subject.should_receive(:prepare_stash_repository)
31
+ @subject.run!
32
+ end
33
+
34
+ it 'should stash the directory into the repository' do
35
+ @subject.should_receive(:stash_directory_into_repository)
36
+ @subject.run!
37
+ end
38
+ end
39
+
40
+ describe '#prepare_stash_repository' do
41
+ before(:each) do
42
+ @mock_stash_repository = mock('StashRepository')
43
+ @mock_stash_directory = mock('Directory::Stash', :repository => @mock_stash_repository)
44
+ end
45
+
46
+ context 'stash directory exists' do
47
+ before(:each) do
48
+ @mock_stash_directory.stub!(:exists?).and_return(true)
49
+ end
50
+
51
+ it 'should validate the repository' do
52
+ @mock_stash_directory.should_receive(:validate_repository)
53
+ @subject.prepare_stash_repository(@mock_stash_directory)
54
+ end
55
+ end
56
+
57
+ context 'stash directory does not exist' do
58
+ before(:each) do
59
+ @mock_stash_directory.stub!(:exists?).and_return(false)
60
+ end
61
+
62
+ it 'should clone the --repository into the stash path' do
63
+ @mock_stash_directory.should_receive(:clone_repository)
64
+ @subject.prepare_stash_repository(@mock_stash_directory)
65
+ end
66
+ end
67
+ end
68
+
69
+ describe '#stash_directory_into_repository' do
70
+ before(:each) do
71
+ @mock_stash_repository = mock('StashRepository')
72
+ @mock_stash_directory = mock('Directory::Stash', :git_index => '/home/stash/path/.git', :path => '/home/stash/path')
73
+ @mock_stash_repository.stub!(:repository).and_return(@mock_stash_repository)
74
+ @mock_target_directory = mock('Directory::Base', :name => 'assets', :path => '/home/tmp/assets', :git_index => '/home/tmp/assets/.git')
75
+
76
+ @subject.stub!(:copy_stash_repository_git_index_to_target)
77
+ @subject.stub!(:commit_and_push_files)
78
+ @subject.stub!(:move_stash_repository_git_index_back)
79
+ end
80
+
81
+ it "should move the stash-repository-directory (.git) one level above the asset directory path" do
82
+ @subject.should_receive(:copy_stash_repository_git_index_to_target).with("/home/stash/path/.git", "/home/tmp/assets")
83
+ @subject.stash_directory_into_repository(@mock_stash_directory, @mock_target_directory)
84
+ end
85
+
86
+ it "should add and push the contents of directory to the repository" do
87
+ @subject.should_receive(:commit_and_push_files).with("/home/tmp/assets", "assets")
88
+ @subject.stash_directory_into_repository(@mock_stash_directory, @mock_target_directory)
89
+ end
90
+
91
+ it "should move the directory's .git directory back to stash-directory-repository" do
92
+ @subject.should_receive(:move_stash_repository_git_index_back).with("/home/tmp/assets/.git", "/home/stash/path")
93
+ @subject.stash_directory_into_repository(@mock_stash_directory, @mock_target_directory)
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Reflection::Directory::Base do
4
+ before(:each) do
5
+ @subject = Reflection::Directory::Base.new("/test/home/path")
6
+ end
7
+
8
+ describe '#exists?' do
9
+ it 'should now if the path exists' do
10
+ File.stub!(:exist?).and_return(true)
11
+ @subject.exists?.should be_true
12
+ end
13
+ end
14
+
15
+ describe '#parent' do
16
+ it 'should find the parent of the last directory living in path' do
17
+ @subject.parent.path.should eql('/test/home')
18
+ end
19
+ end
20
+
21
+ describe '#name' do
22
+ it 'should find the name of the directory living at the end of path' do
23
+ @subject.name.should eql('path')
24
+ end
25
+ end
26
+
27
+ describe '#git_index' do
28
+ it 'should join an .git index directory to path' do
29
+ @subject.git_index.should eql('/test/home/path/.git')
30
+ end
31
+ end
32
+
33
+ describe '#to_s' do
34
+ it 'should resolve as path' do
35
+ @subject.to_s.should eql('/test/home/path')
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Reflection::Directory::Stash do
4
+ before(:each) do
5
+ Reflection.home = mock('Home', :path => '/HOME_DIR/.reflection')
6
+ @mock_repository = mock("Repository", :identifier => '_identifier_', :url => 'git.rubyphunk.com')
7
+ @stash_directory = Reflection::Directory::Stash.new(@mock_repository, 'stash')
8
+ end
9
+
10
+ describe '#path' do
11
+ it 'should generate the path to the stash repository-directory ~/.reflection/stash/-md5_hash-' do
12
+ @stash_directory.path.should eql("/HOME_DIR/.reflection/stash/_identifier_")
13
+ end
14
+ end
15
+
16
+ describe '#validate_repository' do
17
+ before(:each) do
18
+ Reflection::Repository.stub!(:exists?).and_return(true)
19
+ end
20
+
21
+ it 'should compare the existing repository with the instance' do
22
+ @mock_repository.should_receive(:same_in_path?).and_return(true)
23
+ @stash_directory.validate_repository
24
+ end
25
+
26
+ it 'should fail if the repository is not the existing one in the path' do
27
+ Reflection::Support.should_receive(:exit_with_error)
28
+ @mock_repository.stub!(:same_in_path?).and_return(false)
29
+ @stash_directory.validate_repository
30
+ end
31
+ end
32
+
33
+ describe '#clone_repository' do
34
+ it 'should call clone on the repository instance' do
35
+ @mock_repository.should_receive(:clone).with(@stash_directory.path)
36
+ @stash_directory.clone_repository
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,71 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper'
2
+
3
+ describe Reflection::Repository do
4
+ before(:all) do
5
+ @test_git_url = 'git.rubyphunk.com:test.git'
6
+ @test_identifier = 'f5c4e386bcf8339e4b6e5c15c22e5b97'
7
+ end
8
+
9
+ before(:each) do
10
+ @repository = Reflection::Repository.new(@test_git_url)
11
+ @mock_git_repo = mock('Git::Base')
12
+ @mock_git_repo.stub!(:remote).and_return(@mock_remote = mock('Git::Remote'))
13
+ end
14
+
15
+ describe 'new_from_path' do
16
+ it 'should create an instance by path' do
17
+ Git.stub!(:open).and_return(@mock_git_repo)
18
+ @mock_remote.stub!(:url).and_return('git@example.com:repo.git')
19
+ instance = Reflection::Repository.new_from_path('/test/repo/path')
20
+ instance.should be_instance_of(Reflection::Repository)
21
+ instance.url.should eql('git@example.com:repo.git')
22
+ end
23
+
24
+ it 'should raise an error if path is not a valid git repository' do
25
+ lambda do
26
+ Reflection::Repository.stub!(:exists?).and_return(false)
27
+ Reflection::Repository.new_from_path('/test/repo/path')
28
+ end.should raise_error(/not a valid/)
29
+ end
30
+ end
31
+
32
+ describe 'exists?' do
33
+ it 'should return true if a repository exists in path' do
34
+ Git.should_receive(:open).with('/test/path').and_return(@mock_git_repo)
35
+ @mock_remote.stub!(:url).and_return(@test_git_url)
36
+ Reflection::Repository.exists?('/test/path').should be_true
37
+ end
38
+
39
+ it 'should return false if the path is not a repository' do
40
+ Git.should_receive(:open).with('/test/path').and_raise(ArgumentError)
41
+ Reflection::Repository.exists?('/test/path').should be_false
42
+ end
43
+ end
44
+
45
+ describe '#identifier' do
46
+ it 'should return an md5 hash of the repository url' do
47
+ @repository.identifier.should eql(@test_identifier)
48
+ end
49
+ end
50
+
51
+ describe '#same_in_path?' do
52
+ it 'should return true if the path is a repository with the repositories url' do
53
+ Git.should_receive(:open).with('/test/path').and_return(@mock_git_repo)
54
+ @mock_remote.stub!(:url).and_return(@test_git_url)
55
+ @repository.same_in_path?('/test/path').should be_true
56
+ end
57
+
58
+ it 'should return false if the path is a repository but has no remote' do
59
+ Git.should_receive(:open).with('/test/path').and_return(@mock_git_repo)
60
+ @mock_git_repo.stub!(:remote).and_return(nil)
61
+ @repository.same_in_path?('/test/path').should be_false
62
+ end
63
+ end
64
+
65
+ describe '#clone' do
66
+ it 'should clone the reposity to a path' do
67
+ Git.should_receive(:clone).with(@test_git_url, '/test/path')
68
+ @repository.clone('/test/path')
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe Reflection::Support::Home do
4
+ before(:all) do
5
+ @original_home_env = ENV['HOME']
6
+ ENV['HOME'] = "/test/home"
7
+ end
8
+
9
+ before(:each) do
10
+ @home = Reflection::Support::Home.new
11
+ end
12
+
13
+ describe '#path' do
14
+ it 'should generate HOME_DIR/.reflection' do
15
+ @home.path.should eql('/test/home/.reflection')
16
+ end
17
+ end
18
+
19
+ describe '#create' do
20
+ it 'should create the directory' do
21
+ File.stub!(:exist?).and_return(false)
22
+ Dir.should_receive(:mkdir).with('/test/home/.reflection')
23
+ @home.create
24
+ end
25
+ end
26
+
27
+ after(:all) do
28
+ ENV['HOME'] = @original_home_env
29
+ end
30
+ end
@@ -0,0 +1,4 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Reflection::Support do
4
+ end
@@ -0,0 +1,21 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe "Reflection" do
4
+
5
+ describe '#boot' do
6
+ before(:each) do
7
+ Reflection::CLI.stub!(:run!)
8
+ end
9
+
10
+ it 'should init a Home instance which represents ~/.reflection' do
11
+ Reflection.boot!([])
12
+ Reflection.home.should be_kind_of(Reflection::Support::Home)
13
+ end
14
+
15
+ it 'should run the CLI processor' do
16
+ Reflection::CLI.should_receive(:run!).with(['args'])
17
+ Reflection.boot!(['args'])
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,14 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
3
+ require 'reflection'
4
+ require 'spec'
5
+ require 'spec/autorun'
6
+
7
+ Spec::Runner.configure do |config|
8
+ config.before(:each) do
9
+ @global_mock_log = mock('Log')
10
+ @global_mock_log.stub!(:debug)
11
+ @global_mock_log.stub!(:info)
12
+ Reflection.stub!(:log).and_return(@global_mock_log)
13
+ end
14
+ end
metadata ADDED
@@ -0,0 +1,115 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: reflection
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Andreas Wolff
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-15 00:00:00 +01:00
13
+ default_executable: reflection
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.2.9
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: git
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.2.5
34
+ version:
35
+ description: "\n Reflection is designed to keep your production assets (database comming soon) in sync with your development system.\n It uses a shared git repository to store these files, which allows you to mirror your production environment without the need of \n direct access to your production servers.\n "
36
+ email: rubyphunk@gmail.com
37
+ executables:
38
+ - reflection
39
+ extensions: []
40
+
41
+ extra_rdoc_files:
42
+ - LICENSE
43
+ - README.rdoc
44
+ files:
45
+ - .document
46
+ - .gitignore
47
+ - LICENSE
48
+ - README.rdoc
49
+ - Rakefile
50
+ - Reflection.gemspec
51
+ - TODO
52
+ - VERSION
53
+ - bin/reflection
54
+ - lib/reflection.rb
55
+ - lib/reflection/cli.rb
56
+ - lib/reflection/command.rb
57
+ - lib/reflection/command/apply.rb
58
+ - lib/reflection/command/base.rb
59
+ - lib/reflection/command/stash.rb
60
+ - lib/reflection/directory.rb
61
+ - lib/reflection/directory/base.rb
62
+ - lib/reflection/directory/stash.rb
63
+ - lib/reflection/repository.rb
64
+ - lib/reflection/support.rb
65
+ - lib/reflection/support/home.rb
66
+ - lib/reflection/support/log.rb
67
+ - lib/reflection/validations.rb
68
+ - spec/reflection/cli_spec.rb
69
+ - spec/reflection/command/stash_spec.rb
70
+ - spec/reflection/directory/base_spec.rb
71
+ - spec/reflection/directory/stash_spec.rb
72
+ - spec/reflection/repository_spec.rb
73
+ - spec/reflection/support/home_spec.rb
74
+ - spec/reflection/support_spec.rb
75
+ - spec/reflection_spec.rb
76
+ - spec/spec.opts
77
+ - spec/spec_helper.rb
78
+ has_rdoc: true
79
+ homepage: http://github.com/rubyphunk/reflection
80
+ licenses: []
81
+
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --charset=UTF-8
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ version:
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ version:
99
+ requirements: []
100
+
101
+ rubyforge_project:
102
+ rubygems_version: 1.3.5
103
+ signing_key:
104
+ specification_version: 3
105
+ summary: Helps you keeping your development machine in sync with production.
106
+ test_files:
107
+ - spec/reflection/cli_spec.rb
108
+ - spec/reflection/command/stash_spec.rb
109
+ - spec/reflection/directory/base_spec.rb
110
+ - spec/reflection/directory/stash_spec.rb
111
+ - spec/reflection/repository_spec.rb
112
+ - spec/reflection/support/home_spec.rb
113
+ - spec/reflection/support_spec.rb
114
+ - spec/reflection_spec.rb
115
+ - spec/spec_helper.rb