silo 0.1.0
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.
- 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
|