reflection 0.0.2

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