silo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +1 -0
- data/Changelog.md +13 -0
- data/LICENSE +25 -0
- data/README.md +153 -0
- data/Rakefile +45 -0
- data/bin/silo +9 -0
- data/gemspec.yml +29 -0
- data/lib/core_ext/pathname.rb +20 -0
- data/lib/silo.rb +20 -0
- data/lib/silo/cli.rb +167 -0
- data/lib/silo/errors.rb +58 -0
- data/lib/silo/remote/base.rb +33 -0
- data/lib/silo/remote/git.rb +50 -0
- data/lib/silo/repository.rb +366 -0
- data/lib/silo/version.rb +11 -0
- data/test/data/file1 +0 -0
- data/test/data/file2 +0 -0
- data/test/data/subdir1/file1 +0 -0
- data/test/data/subdir2/file2 +0 -0
- data/test/helper.rb +13 -0
- data/test/test_repository.rb +204 -0
- metadata +167 -0
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--files Changelog.md,LICENSE
|
data/Changelog.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## Version 0.1.0
|
4
|
+
|
5
|
+
**January 30<sup>th</sup>, 2011**
|
6
|
+
|
7
|
+
* First release
|
8
|
+
* Simple saving and restoring
|
9
|
+
* Mirroring using Git's built-in remotes
|
10
|
+
* Getting simple information from the repository
|
11
|
+
|
12
|
+
See the [Git history](https://github.com/koraktor/silo/commits/0.1.0) for
|
13
|
+
version 0.1.0
|
data/LICENSE
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
Copyright (c) 2010-2011, Sebastian Staudt
|
2
|
+
All rights reserved.
|
3
|
+
|
4
|
+
Redistribution and use in source and binary forms, with or without modification,
|
5
|
+
are permitted provided that the following conditions are met:
|
6
|
+
|
7
|
+
* Redistributions of source code must retain the above copyright notice,
|
8
|
+
this list of conditions and the following disclaimer.
|
9
|
+
* Redistributions in binary form must reproduce the above copyright notice,
|
10
|
+
this list of conditions and the following disclaimer in the documentation
|
11
|
+
and/or other materials provided with the distribution.
|
12
|
+
* Neither the name of the author nor the names of its contributors
|
13
|
+
may be used to endorse or promote products derived from this software
|
14
|
+
without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
17
|
+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
19
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
20
|
+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
21
|
+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
22
|
+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
23
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
24
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
25
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
data/README.md
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
Silo
|
2
|
+
====
|
3
|
+
|
4
|
+
Silo is command-line utility and Ruby API for Git-based backups. With Silo you
|
5
|
+
can backup arbitrary files into one or more Git repositories and take advantage
|
6
|
+
of Git's compression, speed and other features. No Git knowledge needed.
|
7
|
+
|
8
|
+
## Concept
|
9
|
+
|
10
|
+
To backup files into a repository Silo uses the well-known and established
|
11
|
+
version control system (VCS) Git. Instead of using Git's frontend commands for
|
12
|
+
the end-user, so called *"porcelain"* commands, Silo makes use of the more
|
13
|
+
low-level *"plumbing"* commands. These can be used to write directly to the Git
|
14
|
+
repository, bypassing the automatisms tailored for source code histories.
|
15
|
+
|
16
|
+
## Requirements
|
17
|
+
|
18
|
+
* Grit – a Ruby API for Git
|
19
|
+
* Rubikon – a Ruby framework for console applications
|
20
|
+
* Git >= 1.6
|
21
|
+
|
22
|
+
## Installation
|
23
|
+
|
24
|
+
You can install Silo using RubyGems. This is the easiest way of installing
|
25
|
+
and recommended for most users.
|
26
|
+
|
27
|
+
$ gem install silo
|
28
|
+
|
29
|
+
If you want to use the development code you should clone the Git repository:
|
30
|
+
|
31
|
+
$ git clone git://github.com/koraktor/silo.git
|
32
|
+
$ cd silo
|
33
|
+
$ rake install
|
34
|
+
|
35
|
+
## Basic usage
|
36
|
+
|
37
|
+
### Configuration files
|
38
|
+
|
39
|
+
Silo searches for configuration files (`.silo`) in the current working
|
40
|
+
directory, your home directory and your systems global configuration directory
|
41
|
+
(i.e. /etc on Unix).
|
42
|
+
|
43
|
+
They can be used to set Silo-specific options globally or for single
|
44
|
+
directories. That way you may have one general Silo repository for common
|
45
|
+
backups and another Silo repository for e.g. work-related files.
|
46
|
+
|
47
|
+
Configuration files are expected in a Git-like format and
|
48
|
+
may contain the following sections and variables:
|
49
|
+
|
50
|
+
* repository
|
51
|
+
|
52
|
+
* path – The path of the default repository to use
|
53
|
+
* prefix – The path inside the repository to store files to per default
|
54
|
+
|
55
|
+
#### Sample
|
56
|
+
|
57
|
+
[repository]
|
58
|
+
path = /Users/jondoe/backup.git
|
59
|
+
prefix = work
|
60
|
+
|
61
|
+
This would usually save and restore files to and from
|
62
|
+
`/Users/jondoe/backup.git` and save files into the directory `work` inside the
|
63
|
+
repository.
|
64
|
+
|
65
|
+
### Initialize a repository
|
66
|
+
|
67
|
+
$ silo init [repository path]
|
68
|
+
|
69
|
+
### Add files or directories to the repository
|
70
|
+
|
71
|
+
$ silo add file [file ...] [--prefix <prefix>]
|
72
|
+
|
73
|
+
The prefix allows to organize the files inside the repository.
|
74
|
+
|
75
|
+
### Restore files or directories from the repository
|
76
|
+
|
77
|
+
$ silo restore file [file ...] [--prefix <prefix>]
|
78
|
+
|
79
|
+
The prefix is the directory inside your file system where the restored files
|
80
|
+
will be saved.
|
81
|
+
|
82
|
+
### Remove files or directories from the repository
|
83
|
+
|
84
|
+
$ silo remove file [file ...]
|
85
|
+
$ silo rm file [file ...]
|
86
|
+
|
87
|
+
### Completely purge files or directories from the repository
|
88
|
+
|
89
|
+
$ silo purge file [file ...] [--no-clean]
|
90
|
+
|
91
|
+
This will completely remove the specified files from the repository and thus
|
92
|
+
reduce the required disk space.
|
93
|
+
|
94
|
+
**WARNING**: There's no method built-in to Silo or Git to recover files after
|
95
|
+
purging.
|
96
|
+
|
97
|
+
The `--no-clean` flag will cause Git commits to persist even after their
|
98
|
+
contents have been purged.
|
99
|
+
|
100
|
+
### Manage remote repositories for mirrored backups
|
101
|
+
|
102
|
+
$ silo remote [-v]
|
103
|
+
$ silo remote add name url
|
104
|
+
$ silo remote rm name
|
105
|
+
|
106
|
+
Add or remove a remote repository with the specified name. When adding a remote
|
107
|
+
repository the specified location may be given as any location Git understands
|
108
|
+
– including file system paths.
|
109
|
+
|
110
|
+
### Distribute the state of your repository to all mirror repositories
|
111
|
+
|
112
|
+
$ silo distribute
|
113
|
+
|
114
|
+
### List repository contents
|
115
|
+
|
116
|
+
$ silo list [file ...] [-l] [-r]
|
117
|
+
|
118
|
+
The `-l` flag will list each directory and file in a separate line, `-r` will
|
119
|
+
reverse the listing.
|
120
|
+
|
121
|
+
### Display info about repository contents
|
122
|
+
|
123
|
+
$ silo info [file ...] [-v]
|
124
|
+
|
125
|
+
## Using the Ruby API
|
126
|
+
|
127
|
+
The documentation of the Ruby API can be seen at [RubyDoc.info][1]. The API
|
128
|
+
documentation of the current development version is also available [there][5].
|
129
|
+
|
130
|
+
## License
|
131
|
+
|
132
|
+
This code is free software; you can redistribute it and/or modify it under the
|
133
|
+
terms of the new BSD License. A copy of this license can be found in the
|
134
|
+
LICENSE file.
|
135
|
+
|
136
|
+
## Credits
|
137
|
+
|
138
|
+
* Sebastian Staudt – koraktor(at)gmail.com
|
139
|
+
|
140
|
+
## See Also
|
141
|
+
|
142
|
+
* [API documentation][1]
|
143
|
+
* [Silo's homepage][2]
|
144
|
+
* [GitHub project page][3]
|
145
|
+
* [GitHub issue tracker][4]
|
146
|
+
|
147
|
+
Follow Silo on Twitter [@silorb](http://twitter.com/silorb).
|
148
|
+
|
149
|
+
[1]: http://rubydoc.info/gems/silo/frames
|
150
|
+
[2]: http://koraktor.github.com/silo
|
151
|
+
[3]: http://github.com/koraktor/silo
|
152
|
+
[4]: http://github.com/koraktor/silo/issues
|
153
|
+
[5]: http://rubydoc.info/github/koraktor/silo/master/frames
|
data/Rakefile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'rake/testtask'
|
7
|
+
|
8
|
+
task :default => :test
|
9
|
+
|
10
|
+
# Test task
|
11
|
+
Rake::TestTask.new do |t|
|
12
|
+
t.libs << 'lib' << 'test'
|
13
|
+
t.pattern = 'test/**/test_*.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
begin
|
18
|
+
require 'ore/tasks'
|
19
|
+
Ore::Tasks.new
|
20
|
+
rescue LoadError
|
21
|
+
$stderr.puts 'You need ore-tasks to build the gem. Install it using `gem install ore-tasks`.'
|
22
|
+
end
|
23
|
+
|
24
|
+
begin
|
25
|
+
require 'yard'
|
26
|
+
|
27
|
+
# Create a rake task +:doc+ to build the documentation using YARD
|
28
|
+
YARD::Rake::YardocTask.new do |yardoc|
|
29
|
+
yardoc.name = 'doc'
|
30
|
+
yardoc.files = ['lib/**/*.rb', 'LICENSE', 'README.md']
|
31
|
+
yardoc.options = ['--private', '--title', 'Silo — API Documentation']
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
desc 'Generate YARD Documentation (not available)'
|
35
|
+
task :doc do
|
36
|
+
$stderr.puts 'You need YARD to build the documentation. Install it using `gem install yard`.'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Task for cleaning documentation and package directories
|
41
|
+
desc 'Clean documentation and package directories'
|
42
|
+
task :clean do
|
43
|
+
FileUtils.rm_rf 'doc'
|
44
|
+
FileUtils.rm_rf 'pkg'
|
45
|
+
end
|
data/bin/silo
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# This code is free software; you can redistribute it and/or modify it under
|
4
|
+
# the terms of the new BSD License.
|
5
|
+
#
|
6
|
+
# Copyright (c) 2010, Sebastian Staudt
|
7
|
+
|
8
|
+
require File.join(File.dirname(__FILE__), '..', 'lib', 'silo.rb')
|
9
|
+
require 'silo/cli.rb'
|
data/gemspec.yml
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
name: silo
|
2
|
+
summary: A command-line utility and API for Git-based backups
|
3
|
+
description: With Silo you can backup arbitrary files into one or more Git
|
4
|
+
repositories and take advantage of Git's compression, speed and
|
5
|
+
other features. No Git knowledge needed.
|
6
|
+
|
7
|
+
license: BSD
|
8
|
+
authors: Sebastian Staudt
|
9
|
+
email: koraktor@gmail.com
|
10
|
+
homepage: http://koraktor.de/silo
|
11
|
+
has_yard: true
|
12
|
+
|
13
|
+
extra_doc_files:
|
14
|
+
- Changelog.md
|
15
|
+
- LICENSE
|
16
|
+
require_paths: lib
|
17
|
+
test_files: test/**/test_*.rb
|
18
|
+
|
19
|
+
dependencies:
|
20
|
+
grit: ~> 2.4.1
|
21
|
+
rubikon: ~> 0.6.0
|
22
|
+
|
23
|
+
development_dependencies:
|
24
|
+
ore-tasks: ~> 0.3.0
|
25
|
+
shoulda: ~> 2.11.3
|
26
|
+
yard: ~> 0.6.4
|
27
|
+
|
28
|
+
requirements:
|
29
|
+
- git >= 1.6
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2011, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'pathname'
|
7
|
+
|
8
|
+
# Provides extensions to the Pathname class provided by Ruby's standard
|
9
|
+
# Library
|
10
|
+
class Pathname
|
11
|
+
|
12
|
+
# Appends a path to this path and expands it
|
13
|
+
#
|
14
|
+
# @param [#to_s] path The path to append
|
15
|
+
# @return [Pathname] The generated path
|
16
|
+
def /(path)
|
17
|
+
(self + path).expand_path
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/lib/silo.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010, Sebastian Staudt
|
5
|
+
|
6
|
+
libdir = File.dirname(__FILE__)
|
7
|
+
$LOAD_PATH.unshift(libdir) unless $LOAD_PATH.include?(libdir)
|
8
|
+
|
9
|
+
require 'silo/errors'
|
10
|
+
require 'silo/repository'
|
11
|
+
require 'silo/remote/git'
|
12
|
+
require 'silo/version'
|
13
|
+
|
14
|
+
# A command-line utility and API for Git-based backups
|
15
|
+
#
|
16
|
+
# With Silo you can backup arbitrary files into one or more Git repositories
|
17
|
+
# and take advantage of Git's compression, speed and other features. No Git
|
18
|
+
# knowledge needed.
|
19
|
+
module Silo
|
20
|
+
end
|
data/lib/silo/cli.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# This code is free software; you can redistribute it and/or modify it under
|
2
|
+
# the terms of the new BSD License.
|
3
|
+
#
|
4
|
+
# Copyright (c) 2010-2011, Sebastian Staudt
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'rubikon'
|
8
|
+
|
9
|
+
module Silo
|
10
|
+
|
11
|
+
# This class is a Rubikon application that implements the command-line
|
12
|
+
# interface for Silo
|
13
|
+
#
|
14
|
+
# @author Sebastian Staudt
|
15
|
+
# @since 0.1.0
|
16
|
+
class CLI < Rubikon::Application::Base
|
17
|
+
|
18
|
+
# Changes the current repository
|
19
|
+
#
|
20
|
+
# @see #repo
|
21
|
+
attr_writer :repo
|
22
|
+
|
23
|
+
set :config_file, '.silo'
|
24
|
+
set :config_format, :ini
|
25
|
+
set :help_banner, 'Usage: silo'
|
26
|
+
|
27
|
+
global_option :repository, :repo_path do
|
28
|
+
self.repo = Repository.new repo_path
|
29
|
+
end
|
30
|
+
|
31
|
+
pre_execute do
|
32
|
+
if config.empty?
|
33
|
+
puts "y{Warning:} Configuration file(s) could not be loaded.\n\n"
|
34
|
+
else
|
35
|
+
@prefix = config['repository']['prefix']
|
36
|
+
self.repo = Repository.new config['repository']['path']
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
default '<hidden>' do
|
41
|
+
puts "This is Silo. A Git-based backup utility.\n\n"
|
42
|
+
call :help
|
43
|
+
end
|
44
|
+
|
45
|
+
option :prefix, 'The prefix path inside the repository to store the files to', :path
|
46
|
+
command :add, 'Store one or more files in the repository', :files => :remainder do
|
47
|
+
files.uniq.each do |file|
|
48
|
+
repo.add file, prefix.path || @prefix
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
command :distribute, 'Push repository contents to remote repositories' do
|
53
|
+
repo.distribute
|
54
|
+
end
|
55
|
+
|
56
|
+
command :info, 'Get information about repository contents', :files => :remainder do
|
57
|
+
files.uniq.each do |path|
|
58
|
+
info = repo.info path
|
59
|
+
puts '' unless path == args.first
|
60
|
+
puts "#{info[:type] == :blob ? 'File' : 'Directory'}: #{info[:path]}"
|
61
|
+
if info[:type] == :blob
|
62
|
+
puts " Size: #{info[:size].to_s.
|
63
|
+
gsub(/(\d)(?=(\d\d\d)+(?!\d))/, "\\1,")} bytes"
|
64
|
+
puts " MIME-Type: #{info[:mime]}"
|
65
|
+
end
|
66
|
+
puts " Created at: #{info[:created]}"
|
67
|
+
puts " Last modified at: #{info[:modified]}"
|
68
|
+
|
69
|
+
if $VERBOSE
|
70
|
+
puts " Initial commit: #{info[:history].last.id}"
|
71
|
+
puts " Last commit: #{info[:history].first.id}"
|
72
|
+
puts " Mode: #{info[:mode]}"
|
73
|
+
puts " #{info[:type].to_s.capitalize}-ID: #{info[:sha]}"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
command :init, 'Initialize a Silo repository', :path => :optional do
|
79
|
+
path = File.expand_path(path || '.')
|
80
|
+
puts "Initializing Silo repository in #{path}..."
|
81
|
+
Repository.new path
|
82
|
+
end
|
83
|
+
|
84
|
+
flag :l, 'List each object in a separate line'
|
85
|
+
flag :r, 'Reverse list order'
|
86
|
+
command :list, 'List the contents of a repository', :paths => [ :remainder, :optional ] do
|
87
|
+
paths = self.paths || [nil]
|
88
|
+
contents = []
|
89
|
+
paths.each do |path|
|
90
|
+
new_contents = repo.contents path
|
91
|
+
puts "y{Warning:} File '#{path}' does not exist in the repository." if new_contents.empty?
|
92
|
+
contents |= new_contents
|
93
|
+
end
|
94
|
+
|
95
|
+
contents.reverse! if r.given?
|
96
|
+
|
97
|
+
unless l.given?
|
98
|
+
col_size = contents.max_by { |path| path.size }.size + 1
|
99
|
+
contents.each { |path| put path.ljust(col_size) }
|
100
|
+
puts ''
|
101
|
+
else
|
102
|
+
contents.each { |path| puts path }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
command :remote, 'Add or remove remote repositories', { :action => ['add', 'rm', :optional], :name => :optional, :url => :optional } do
|
107
|
+
usage = lambda do
|
108
|
+
puts 'usage: silo remote add <name> <url>'
|
109
|
+
puts ' or: silo remote rm <name>'
|
110
|
+
end
|
111
|
+
case action
|
112
|
+
when nil
|
113
|
+
repo.remotes.each_value do |remote|
|
114
|
+
info = remote.name
|
115
|
+
info += " #{remote.url}" if $VERBOSE
|
116
|
+
puts info
|
117
|
+
end
|
118
|
+
when 'add'
|
119
|
+
if url.nil?
|
120
|
+
repo.add_remote name, url
|
121
|
+
else
|
122
|
+
usage.call
|
123
|
+
end
|
124
|
+
when 'rm'
|
125
|
+
unless url.nil?
|
126
|
+
repo.remove_remote name
|
127
|
+
else
|
128
|
+
usage.call
|
129
|
+
end
|
130
|
+
else
|
131
|
+
usage.call
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
option :prefix, 'The prefix path to store the files to', :path
|
136
|
+
command :restore, 'Restore one or more files or directories from the repository', :files => :remainder do
|
137
|
+
files.uniq.each do |file|
|
138
|
+
repo.restore file, prefix.path || '.'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
flag :'no-clean', "Don't remove empty commits from the Git history"
|
143
|
+
command :purge, 'Permanently remove one or more files or directories from the repository', :files => :remainder do
|
144
|
+
files.uniq.each do |file|
|
145
|
+
repo.purge file, !given?(:'no-clean')
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
command :rm => :remove
|
150
|
+
command :remove, 'Remove one or more files or directories from the repository', :files => :remainder do
|
151
|
+
files.uniq.each do |file|
|
152
|
+
repo.remove file
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Returns the current repository
|
157
|
+
#
|
158
|
+
# @return [Repository] The currently configured Silo repository
|
159
|
+
# @raise [RuntimeError] if no repository is configured
|
160
|
+
def repo
|
161
|
+
raise 'No repository configured.' if @repo.nil?
|
162
|
+
@repo
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
end
|