Permalink
Browse files

Adding the initial code.

  • Loading branch information...
1 parent 7aadd9c commit 4115408e8e18bdff6c8e0cf510d7bc892fbeed8b @brycethornton committed May 17, 2010
Showing with 216 additions and 22 deletions.
  1. +1 −1 LICENSE
  2. +91 −0 README.md
  3. +0 −17 README.rdoc
  4. +3 −4 Rakefile
  5. +6 −0 lib/gitback.rb
  6. +115 −0 lib/gitback/repository.rb
View
2 LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2009 Bryce Thornton
+Copyright (c) 2010 Bryce Thornton
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
View
91 README.md
@@ -0,0 +1,91 @@
+Gitback
+====
+
+Gitback allows you to version arbitrary files and/or directories in a git
+repository. You just need to include the gem and write a brief ruby script
+that indicates the files/directories you'd like to backup. Then, run the
+script via cron. Gitback will take care of a adding/commiting/pushing whenever
+your files are modified.
+
+The typical usage for this is backing up config files.
+
+
+## Requirements ###############################################################
+
+* git (http://git-scm.com) tested with 1.6.0.4
+* grit (http://github.com/mojombo/grit) 2.0.0 or higher
+
+
+## Install ####################################################################
+
+ $ gem install gitback -s http://gemcutter.org
+
+## Usage ######################################################################
+
+Here's a basic example of a script using gitback:
+
+ require 'rubygems'
+ require 'gitback'
+
+ Gitback::Repository.new '/var/config-backup/' do |repo|
+ repo.backup '/opt/nginx/conf/nginx.conf'
+ end
+
+This will check /opt/nginx/conf/nginx.conf for changes. If the file has
+changed, gitback will commit a new version.
+
+This nginx config file would be saved to the following location:
+
+ /var/config-backup/opt/nginx/conf/nginx.conf
+
+Everything starts with instantiating a new `Gitback::Repository` object. The
+first parameter is the path to the git repository you'd like to backup to. The
+second parameter is a block indicating the files/directories you'd like to
+backup.
+
+
+### Directory support
+
+In addition to basic files, directory paths can also be backed up:
+
+ Gitback::Repository.new '/var/config-backup/' do |repo|
+ repo.backup '/opt/nginx/conf/nginx.conf'
+ repo.backup '/etc/mysql/'
+ end
+
+Notice that '/etc/mysql' is a directory. Gitback will copy everything within
+that directory into the git repository.
+
+
+### Namespaces
+
+Namespaces are also supported. If you'd like to use the same repository for
+multiple servers you can specify a namespace like this:
+
+ Gitback::Repository.new '/var/config-backup/' do |repo|
+ repo.namespace 'server1.domain.com' do
+ repo.backup '/opt/nginx/conf/nginx.conf'
+ end
+ end
+
+This will save the file to the following location:
+
+ /var/config-backup/server1.domain.com/opt/nginx/conf/nginx.conf
+
+
+### Remote Git Repositories
+
+Gitback is intended to be used with remote git repositories. If your git
+repository is tracking a remote branch, gitback will push changes to
+the remote after each commit.
+
+
+### Running Via Cron
+
+There's nothing special about a gitback script. In order for it to backup
+your files you'll need to run it via the command line. I suggest setting up
+a cron job to do this for you at regular intervals.
+
+## Copyright ###################################################################
+
+Copyright (c) 2010 Bryce Thornton. See LICENSE for details.
View
17 README.rdoc
@@ -1,17 +0,0 @@
-= gitback
-
-Description goes here.
-
-== Note on Patches/Pull Requests
-
-* Fork the project.
-* Make your feature addition or bug fix.
-* Add tests for it. This is important so I don't break it in a
- future version unintentionally.
-* Commit, do not mess with rakefile, version, or history.
- (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
-* Send me a pull request. Bonus points for topic branches.
-
-== Copyright
-
-Copyright (c) 2010 Bryce Thornton. See LICENSE for details.
View
7 Rakefile
@@ -5,13 +5,12 @@ begin
require 'jeweler'
Jeweler::Tasks.new do |gem|
gem.name = "gitback"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{A simple ruby library for backing up files to git}
+ gem.description = %Q{Provide a list of files and/or directories and gitback will copy them to your git repo, commit and push when there are changes.}
gem.email = "brycethornton@gmail.com"
gem.homepage = "http://github.com/brycethornton/gitback"
gem.authors = ["Bryce Thornton"]
- gem.add_development_dependency "thoughtbot-shoulda", ">= 0"
- # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
+ gem.add_dependency "grit", ">= 2.0.0"
end
Jeweler::GemcutterTasks.new
rescue LoadError
View
6 lib/gitback.rb
@@ -0,0 +1,6 @@
+require 'fileutils'
+require 'ftools'
+require 'grit'
+include Grit
+
+require 'gitback/repository'
View
115 lib/gitback/repository.rb
@@ -0,0 +1,115 @@
+module Gitback
+ class Repository
+ attr_accessor :remote
+ attr_accessor :branch
+
+ def initialize(repository_path, &block)
+ @repository_path = clean_path(repository_path)
+
+ if File.exists?(@repository_path)
+ prepare_git_repository
+
+ if @repo
+ yield self
+ commit_git_changes
+ end
+ else
+ puts "ERROR: it doesn't look like '#{@repository_path}' exists."
+ end
+ end
+
+ # Creates a namespace for files to be stored under
+ # Allows a single repository to be used for many different backups
+ def namespace(name, &block)
+ @namespace = clean_path(name)
+ yield self
+ end
+
+ # Sets up the paths and copies the files into the git repo
+ def backup(file_path)
+ file_path = clean_path(file_path)
+
+ begin
+ dest_path = file_path
+ dest_path = '/' + @namespace + file_path if @namespace
+ dest_path = @repository_path + dest_path
+
+ dirname = File.dirname(dest_path)
+
+ # Make sure the path exists in the repo
+ if !File.exists?(dirname)
+ FileUtils.mkpath(dirname)
+ end
+
+ # Copy the file(s) to the repo
+ if File.exists?(file_path)
+ # We pass remove_destination to avoid issues with symlinks
+ FileUtils.cp_r file_path, dest_path, :remove_destination => true
+ else
+ puts "ERROR: '#{file_path}' doesn't seem to exist."
+ end
+ rescue Errno::EACCES
+ puts "ERROR: '#{file_path}' doesn't seem to be readable and/or writable by this user."
+ end
+ end
+
+ private
+ # Creates the Grit::Repo object for use throughout the class
+ def prepare_git_repository
+ # Allow one minute for slow repositories
+ Grit::Git.git_timeout = 60.0
+
+ Dir.chdir(@repository_path) do
+ begin
+ @repo = Grit::Repo.new('.')
+
+ # Figure out the remote branch
+ @remote = @repo.git.list_remotes.first
+ @branch = @repo.head.name
+
+ # Do a git-pull to make sure we have the newest changes from the repo
+ if @remote
+ puts "Pulling any changes from the remote git repository..."
+ @repo.git.pull({}, @remote, @branch)
+ end
+ rescue Grit::InvalidGitRepositoryError
+ puts "ERROR: #{@repository_path} doesn't seem to be a git repository."
+ end
+ end
+ end
+
+ # Use the repo object to commit and push the changes
+ def commit_git_changes
+ Dir.chdir(@repository_path) do
+ status = @repo.status
+
+ # Only add if we have untracked files
+ if status.untracked.size > 0
+ puts "Adding new files to the repository..."
+ @repo.add(@repository_path + '/*')
+ end
+
+ commit_result = @repo.commit_all("Updating files")
+
+ # Attempt to push if anything was committed and we have a remote repo
+ if commit_result !~ /working directory clean/
+ if @remote
+ puts "Pushing repository changes..."
+ @repo.git.push({}, @remote, @branch)
+ end
+ else
+ puts "No changes committed."
+ end
+ end
+ end
+
+ # This just normalizes file/directory paths
+ def clean_path(file_path)
+ if File.directory?(file_path)
+ file_path = File.expand_path(file_path)
+ end
+
+ file_path
+ end
+ end
+end

0 comments on commit 4115408

Please sign in to comment.