backto 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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +39 -0
- data/Rakefile +9 -0
- data/backto.gemspec +23 -0
- data/bin/backto +9 -0
- data/lib/backto.rb +26 -0
- data/lib/backto/config.rb +67 -0
- data/lib/backto/path.rb +63 -0
- data/lib/backto/scanner.rb +61 -0
- data/lib/backto/version.rb +3 -0
- data/test/backto_test.rb +113 -0
- data/test/config_test.rb +47 -0
- data/test/fixtures/test_file_config.json +5 -0
- data/test/helper.rb +52 -0
- data/test/scanner_test.rb +77 -0
- metadata +95 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 9ef31769f44a8b071bdc6ee8db36bfde374e288b
|
4
|
+
data.tar.gz: 2318eeb3c27a0fbac31671855efbbabb742ad8a9
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 357f0c721f93387c089c0222df5da629ff405d45fb6e1040c6e09e614d3cb87926d8d37270bd3051f0f0fe2b28603a2bb3dda4ca2876f18fba246feb1c6ee49b
|
7
|
+
data.tar.gz: aaa26de0169f85437d9024376fe6bf4164d4ae3e3a6a11151d4594dffb6c5d71b01a16acab0f66978a62423e868283c751ac3207a0a3008dc2ec8d27446900ad
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 john1king
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# Backto
|
2
|
+
|
3
|
+
A simple command line tool for backup files to one location.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
$ gem install backto
|
8
|
+
|
9
|
+
## Usage
|
10
|
+
|
11
|
+
Example of backup Sublime Text 3 config to your Dropbox. You may have some files like below in `~/Dropbox/SublimeText3`
|
12
|
+
|
13
|
+
```
|
14
|
+
├── Installed\ Packages
|
15
|
+
│ ├── 0_package_control_loader.sublime-package
|
16
|
+
│ └── Package\ Control.sublime-package
|
17
|
+
└── Packages
|
18
|
+
└── User
|
19
|
+
├── Default\ (OSX).sublime-keymap
|
20
|
+
├── Package\ Control.sublime-settings
|
21
|
+
└── Preferences.sublime-settings
|
22
|
+
```
|
23
|
+
|
24
|
+
Just wirte a json config file in `~/Dropbox/sublimetext3.json` like
|
25
|
+
|
26
|
+
```json
|
27
|
+
{
|
28
|
+
"form": "./SublimeText3",
|
29
|
+
"to": "~/Library/Application Support/Sublime Text 3"
|
30
|
+
}
|
31
|
+
|
32
|
+
```
|
33
|
+
|
34
|
+
And then execute
|
35
|
+
|
36
|
+
```
|
37
|
+
$ backto ~/Dropbox/sublimetext3.json
|
38
|
+
```
|
39
|
+
|
data/Rakefile
ADDED
data/backto.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'backto/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "backto"
|
8
|
+
spec.version = Backto::VERSION
|
9
|
+
spec.authors = ["john1king"]
|
10
|
+
spec.email = ["uifantasy@gmail.com"]
|
11
|
+
spec.summary = %q{Link files easier}
|
12
|
+
spec.description = %q{A simple command line tool for backup files to one location}
|
13
|
+
spec.homepage = "https://github.com/john1king/backto"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
+
end
|
data/bin/backto
ADDED
data/lib/backto.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require "backto/version"
|
2
|
+
require "backto/config"
|
3
|
+
require "backto/scanner"
|
4
|
+
require "backto/path"
|
5
|
+
|
6
|
+
module Backto
|
7
|
+
|
8
|
+
module_function
|
9
|
+
|
10
|
+
def run(config)
|
11
|
+
config = Config.create(config)
|
12
|
+
link_options = {verbose: config[:verbose], force: config[:force]}
|
13
|
+
scanner = Scanner.new(config[:from], config[:exclude_patterns], config[:link_directory])
|
14
|
+
scanner.each do |path, is_recursive|
|
15
|
+
target = path.chdir(config[:to])
|
16
|
+
if path.directory? && is_recursive
|
17
|
+
path.mkdirs target, verbose: config[:verbose]
|
18
|
+
elsif config[:hardlink] && ! path.directory?
|
19
|
+
path.hardlink target, link_options
|
20
|
+
else
|
21
|
+
path.softlink target, link_options
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module Backto
|
4
|
+
|
5
|
+
class Config
|
6
|
+
|
7
|
+
EXCLUDE_PATTERNS = [
|
8
|
+
'.git',
|
9
|
+
'.svn',
|
10
|
+
'.DS_Store',
|
11
|
+
'*.swp',
|
12
|
+
].freeze
|
13
|
+
|
14
|
+
DEFAULT = {
|
15
|
+
verbose: true,
|
16
|
+
force: false,
|
17
|
+
hardlink: false,
|
18
|
+
link_directory: false,
|
19
|
+
exclude_patterns: EXCLUDE_PATTERNS,
|
20
|
+
clean_link: false,
|
21
|
+
}.freeze
|
22
|
+
|
23
|
+
def self.create(config)
|
24
|
+
config.is_a?(self) ? config : new(config)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(config = {})
|
28
|
+
if config.is_a? String
|
29
|
+
@config = JSON.parse(File.read(config), symbolize_names: true)
|
30
|
+
@base_path = File.expand_path(File.dirname(config))
|
31
|
+
else
|
32
|
+
@config = config
|
33
|
+
@base_path = Dir.pwd
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def from
|
38
|
+
@from ||= expand_path fetch(:from)
|
39
|
+
end
|
40
|
+
|
41
|
+
def to
|
42
|
+
@to ||= expand_path fetch(:to)
|
43
|
+
end
|
44
|
+
|
45
|
+
def [](name)
|
46
|
+
method = name.to_sym
|
47
|
+
if respond_to? method
|
48
|
+
send method
|
49
|
+
elsif @config.key? method
|
50
|
+
@config[method]
|
51
|
+
else
|
52
|
+
DEFAULT[method]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def expand_path(path)
|
59
|
+
File.expand_path path, @base_path
|
60
|
+
end
|
61
|
+
|
62
|
+
def fetch(name)
|
63
|
+
@config.fetch(name)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/lib/backto/path.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
module Backto
|
4
|
+
|
5
|
+
class Path
|
6
|
+
attr_reader :relative
|
7
|
+
|
8
|
+
def initialize(path_name, relative = nil)
|
9
|
+
@path_name = path_name
|
10
|
+
@relative = relative
|
11
|
+
end
|
12
|
+
|
13
|
+
def absolute
|
14
|
+
@absolute ||= File.join(@path_name, relative || '')
|
15
|
+
end
|
16
|
+
|
17
|
+
alias :source :absolute
|
18
|
+
|
19
|
+
def join(file)
|
20
|
+
self.class.new(@path_name, relative ? File.join(relative, file) : file)
|
21
|
+
end
|
22
|
+
|
23
|
+
def chdir(path_name)
|
24
|
+
File.join(path_name, relative)
|
25
|
+
end
|
26
|
+
|
27
|
+
def mkdirs(target, options = {})
|
28
|
+
FileUtils.mkdir_p target, options unless File.exist? target
|
29
|
+
end
|
30
|
+
|
31
|
+
def hardlink(target, options)
|
32
|
+
FileUtils.ln source, target, options
|
33
|
+
rescue Errno::EEXIST
|
34
|
+
raise unless hardlink? target
|
35
|
+
end
|
36
|
+
|
37
|
+
def softlink(target, options = {})
|
38
|
+
return if softlink? target
|
39
|
+
if File.directory?(target) && directory?
|
40
|
+
FileUtils.rm_r target, options if options[:force]
|
41
|
+
FileUtils.ln_s source, File.dirname(target), options
|
42
|
+
else
|
43
|
+
FileUtils.ln_s source, target, options
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def softlink?(target)
|
48
|
+
File.symlink?(target) && File.readlink(target) == source
|
49
|
+
end
|
50
|
+
|
51
|
+
def hardlink?(target)
|
52
|
+
File.stat(target).ino == File.stat(source).ino
|
53
|
+
rescue Errno::ENOENT
|
54
|
+
false
|
55
|
+
end
|
56
|
+
|
57
|
+
def directory?
|
58
|
+
@is_directory ||= File.directory?(absolute)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require "backto/path"
|
2
|
+
|
3
|
+
module Backto
|
4
|
+
|
5
|
+
class Scanner
|
6
|
+
attr_reader :exclude_patterns
|
7
|
+
|
8
|
+
def self.normalize_patterns(patterns)
|
9
|
+
patterns.map do |pattern|
|
10
|
+
normalized = pattern.dup
|
11
|
+
match_dir = normalized.chomp!('/') != nil
|
12
|
+
normalized = '/**/' + normalized unless normalized.start_with?('/')
|
13
|
+
[normalized, match_dir]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(entry, exclude_patterns = [], skip_recursive = false)
|
18
|
+
@entry = entry
|
19
|
+
@skip_recursive = skip_recursive
|
20
|
+
@exclude_patterns = self.class.normalize_patterns(exclude_patterns)
|
21
|
+
end
|
22
|
+
|
23
|
+
def each(&block)
|
24
|
+
scan Path.new(@entry), &block
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def scan(parent, &block)
|
30
|
+
Dir.foreach(parent.absolute) do |name|
|
31
|
+
next if name == '.' || name == '..'
|
32
|
+
path = parent.join(name)
|
33
|
+
next if exclude? path
|
34
|
+
is_recursive = recursive?(path)
|
35
|
+
block.call(path, is_recursive)
|
36
|
+
scan(path, &block) if is_recursive
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def exclude?(path)
|
41
|
+
test_path = File.join('/', path.relative)
|
42
|
+
exclude_patterns.any? do |pattern, match_dir|
|
43
|
+
fnmatch?(pattern, test_path) && (match_dir ? path.directory? : true)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def recursive?(path)
|
48
|
+
return false unless path.directory?
|
49
|
+
if @skip_recursive.is_a? Array
|
50
|
+
!@skip_recursive.include? path.relative
|
51
|
+
else
|
52
|
+
!@skip_recursive
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def fnmatch?(pattern, path_name)
|
57
|
+
File.fnmatch? pattern, path_name, File::FNM_PATHNAME | File::FNM_DOTMATCH
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/test/backto_test.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'backto'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require_relative './helper'
|
4
|
+
|
5
|
+
|
6
|
+
class BacktoTest < Minitest::Test
|
7
|
+
|
8
|
+
def test_softlink
|
9
|
+
from = TempTree.new do |t|
|
10
|
+
t.file 'a/b/c'
|
11
|
+
t.mkdir 'a/d'
|
12
|
+
end
|
13
|
+
|
14
|
+
to = TempTree.new
|
15
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false})
|
16
|
+
|
17
|
+
assert to.symlink? 'a/b/c'
|
18
|
+
assert to.directory? 'a/d'
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_hardlink
|
22
|
+
from = TempTree.new do |t|
|
23
|
+
t.file 'a/b/c'
|
24
|
+
t.mkdir 'a/d'
|
25
|
+
end
|
26
|
+
|
27
|
+
to = TempTree.new
|
28
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, hardlink: true})
|
29
|
+
|
30
|
+
assert_equal from.inode('a/b/c'), to.inode('a/b/c')
|
31
|
+
assert to.directory? 'a/d'
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_target_exist
|
35
|
+
from = TempTree.new do |t|
|
36
|
+
t.file 'a/b/c'
|
37
|
+
end
|
38
|
+
|
39
|
+
to = TempTree.new do |t|
|
40
|
+
t.file 'a/b/c'
|
41
|
+
end
|
42
|
+
assert_raises Errno::EEXIST do
|
43
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false})
|
44
|
+
end
|
45
|
+
assert to.file? 'a/b/c'
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_force
|
49
|
+
from = TempTree.new do |t|
|
50
|
+
t.file 'a/b/c'
|
51
|
+
end
|
52
|
+
|
53
|
+
to = TempTree.new do |t|
|
54
|
+
t.file 'a/b/c'
|
55
|
+
end
|
56
|
+
|
57
|
+
refute to.symlink? 'a/b/c'
|
58
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, force: true})
|
59
|
+
assert to.symlink? 'a/b/c'
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_link_directory
|
63
|
+
from = TempTree.new do |t|
|
64
|
+
t.file 'a/b/c'
|
65
|
+
end
|
66
|
+
to = TempTree.new
|
67
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, link_directory: true})
|
68
|
+
assert to.symlink? 'a'
|
69
|
+
refute to.symlink? 'a/b/c'
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_link_directory_when_target_exist
|
73
|
+
from = TempTree.new do |t|
|
74
|
+
t.mkdir 'a'
|
75
|
+
end
|
76
|
+
|
77
|
+
to = TempTree.new do |t|
|
78
|
+
t.mkdir 'a'
|
79
|
+
end
|
80
|
+
assert_raises Errno::EEXIST do
|
81
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, link_directory: true})
|
82
|
+
end
|
83
|
+
assert to.directory? 'a'
|
84
|
+
refute to.exist? 'a/a'
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_force_link_directory_when_target_exist
|
88
|
+
from = TempTree.new do |t|
|
89
|
+
t.mkdir 'a'
|
90
|
+
end
|
91
|
+
|
92
|
+
to = TempTree.new do |t|
|
93
|
+
t.file 'a/b'
|
94
|
+
end
|
95
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, force: true, link_directory: true})
|
96
|
+
assert to.symlink? 'a'
|
97
|
+
refute to.exist? 'a/b'
|
98
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, force: true, link_directory: true})
|
99
|
+
refute to.exist? 'a/a'
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_exclude_patterns
|
103
|
+
from = TempTree.new do |t|
|
104
|
+
t.file 'a/b/c'
|
105
|
+
t.file 'foo'
|
106
|
+
end
|
107
|
+
to = TempTree.new
|
108
|
+
Backto.run({from: from.dir, to: to.dir, verbose: false, exclude_patterns: ['f*']})
|
109
|
+
assert to.symlink? 'a/b/c'
|
110
|
+
refute to.exist? 'foo'
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
data/test/config_test.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'backto/config'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
|
4
|
+
class ConfigTest < Minitest::Test
|
5
|
+
|
6
|
+
def test_default_config
|
7
|
+
config = Backto::Config.new({})
|
8
|
+
assert_equal config[:verbose], true
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_necessary_config
|
12
|
+
config = Backto::Config.new({})
|
13
|
+
%i(from to).each do |key|
|
14
|
+
assert_raises KeyError do
|
15
|
+
config[key]
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_absoute_path
|
21
|
+
config = Backto::Config.new({from: '/foo', to: '/bar'})
|
22
|
+
assert_equal config[:from], '/foo'
|
23
|
+
assert_equal config[:to], '/bar'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_expand_user_path
|
27
|
+
config = Backto::Config.new({from: '~/foo', to: '~root/foo'})
|
28
|
+
assert_equal config[:from], File.expand_path('~/foo')
|
29
|
+
assert_equal config[:to], File.expand_path('~root/foo')
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_expand_relative_path
|
33
|
+
config = Backto::Config.new({from: './foo', to: 'bar'})
|
34
|
+
assert_equal config[:from], File.expand_path(File.join(Dir.pwd, 'foo'))
|
35
|
+
assert_equal config[:to], File.expand_path(File.join(Dir.pwd, 'bar'))
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_file_config
|
39
|
+
fixtures_dir = File.expand_path('../fixtures', __FILE__)
|
40
|
+
file = File.join(fixtures_dir, 'test_file_config.json')
|
41
|
+
config = Backto::Config.new(file)
|
42
|
+
assert_equal config[:from], File.join(fixtures_dir, 'foo')
|
43
|
+
assert_equal config[:to], File.join(fixtures_dir, 'bar')
|
44
|
+
assert_equal config[:verbose], false
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
require "fileutils"
|
2
|
+
|
3
|
+
class TempTree
|
4
|
+
attr_reader :dir
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@dir = Dir.mktmpdir
|
8
|
+
yield self if block_given?
|
9
|
+
end
|
10
|
+
|
11
|
+
def mkdir(path)
|
12
|
+
FileUtils.mkdir_p join(path)
|
13
|
+
end
|
14
|
+
|
15
|
+
def file(path, data='')
|
16
|
+
mkdir File.dirname(path)
|
17
|
+
File.write join(path), data
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove(path)
|
21
|
+
FileUtils.rm_rf join(path)
|
22
|
+
end
|
23
|
+
|
24
|
+
def exist?(path)
|
25
|
+
File.exist? join(path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def directory?(path)
|
29
|
+
File.directory? join(path)
|
30
|
+
end
|
31
|
+
|
32
|
+
def symlink?(path)
|
33
|
+
File.symlink? join(path)
|
34
|
+
end
|
35
|
+
|
36
|
+
def file?(path)
|
37
|
+
File.file? join(path)
|
38
|
+
end
|
39
|
+
|
40
|
+
def inode(path)
|
41
|
+
File.stat(join path).ino
|
42
|
+
end
|
43
|
+
|
44
|
+
def join(path)
|
45
|
+
File.join(@dir, path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def destroy
|
49
|
+
FileUtils.rm_rf(@dir, noop: true, verbse: true)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'backto/scanner'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require_relative './helper'
|
4
|
+
|
5
|
+
class ScannerTest < Minitest::Test
|
6
|
+
|
7
|
+
|
8
|
+
def scan_result(*args)
|
9
|
+
Backto::Scanner.new(*args).to_enum.to_a.map(&:first).map(&:relative)
|
10
|
+
end
|
11
|
+
|
12
|
+
def assert_equal_set(expected, actual)
|
13
|
+
assert_equal expected.sort, actual.sort
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_exclude_dir_patterns
|
17
|
+
tree = TempTree.new do |t|
|
18
|
+
t.mkdir 'foo'
|
19
|
+
t.mkdir 'foobar'
|
20
|
+
t.file 'bar'
|
21
|
+
end
|
22
|
+
|
23
|
+
assert_equal_set ['foobar', 'bar'], scan_result(tree.dir, ['foo/'])
|
24
|
+
assert_equal_set ['foo', 'foobar', 'bar'], scan_result(tree.dir, ['bar/'])
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_exclude_recursive_patterns
|
28
|
+
tree = TempTree.new do |t|
|
29
|
+
t.file 'foo'
|
30
|
+
t.file '1/foo'
|
31
|
+
t.file '1/2/foo'
|
32
|
+
end
|
33
|
+
|
34
|
+
# test without exclude_pattern
|
35
|
+
assert_equal_set ['foo', '1', '1/foo', '1/2', '1/2/foo'], scan_result(tree.dir, [])
|
36
|
+
assert_equal_set ['1', '1/2'], scan_result(tree.dir, ['foo'])
|
37
|
+
assert_equal_set ['1', '1/foo', '1/2', '1/2/foo'], scan_result(tree.dir, ['/foo'])
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
def test_exclude_subdirectory_files
|
42
|
+
tree = TempTree.new do |t|
|
43
|
+
t.file 'foo/bar/a'
|
44
|
+
end
|
45
|
+
|
46
|
+
assert_equal_set ['foo'], scan_result(tree.dir, ['bar'])
|
47
|
+
assert_equal_set [], scan_result(tree.dir, ['foo'])
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_exclude_match_patterns
|
51
|
+
tree = TempTree.new do |t|
|
52
|
+
t.file 'foo1'
|
53
|
+
t.file 'foo2'
|
54
|
+
t.file 'foo3/bar3'
|
55
|
+
t.file 'foo4/bar4/4'
|
56
|
+
t.file 'foo5/bar5/foobar5/5'
|
57
|
+
end
|
58
|
+
|
59
|
+
assert_equal_set [], scan_result(tree.dir, ['foo*'])
|
60
|
+
assert_equal_set ['foo1', 'foo2'], scan_result(tree.dir, ['foo*/'])
|
61
|
+
assert_equal_set ['foo1', 'foo2', 'foo3', 'foo3/bar3', 'foo4', 'foo5'], scan_result(tree.dir, ['foo*/*/'])
|
62
|
+
assert_equal_set ['foo1', 'foo2', 'foo3', 'foo3/bar3', 'foo4', "foo4/bar4", "foo5", "foo5/bar5", "foo5/bar5/foobar5"], scan_result(tree.dir, ['foo*/**/?'])
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
def test_skip_recursive_all
|
67
|
+
tree = TempTree.new do |t|
|
68
|
+
t.file 'foo1'
|
69
|
+
t.file 'foo2/bar2'
|
70
|
+
t.file 'foo3/bar3/3'
|
71
|
+
end
|
72
|
+
|
73
|
+
assert_equal_set ['foo1', 'foo2', 'foo3'], scan_result(tree.dir, [], true)
|
74
|
+
assert_equal_set ['foo1', 'foo2', 'foo2/bar2', 'foo3'], scan_result(tree.dir, [], ['foo3'])
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
metadata
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: backto
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- john1king
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-03-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.7'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.7'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: A simple command line tool for backup files to one location
|
42
|
+
email:
|
43
|
+
- uifantasy@gmail.com
|
44
|
+
executables:
|
45
|
+
- backto
|
46
|
+
extensions: []
|
47
|
+
extra_rdoc_files: []
|
48
|
+
files:
|
49
|
+
- ".gitignore"
|
50
|
+
- Gemfile
|
51
|
+
- LICENSE.txt
|
52
|
+
- README.md
|
53
|
+
- Rakefile
|
54
|
+
- backto.gemspec
|
55
|
+
- bin/backto
|
56
|
+
- lib/backto.rb
|
57
|
+
- lib/backto/config.rb
|
58
|
+
- lib/backto/path.rb
|
59
|
+
- lib/backto/scanner.rb
|
60
|
+
- lib/backto/version.rb
|
61
|
+
- test/backto_test.rb
|
62
|
+
- test/config_test.rb
|
63
|
+
- test/fixtures/test_file_config.json
|
64
|
+
- test/helper.rb
|
65
|
+
- test/scanner_test.rb
|
66
|
+
homepage: https://github.com/john1king/backto
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
version: '0'
|
79
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
requirements: []
|
85
|
+
rubyforge_project:
|
86
|
+
rubygems_version: 2.2.2
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Link files easier
|
90
|
+
test_files:
|
91
|
+
- test/backto_test.rb
|
92
|
+
- test/config_test.rb
|
93
|
+
- test/fixtures/test_file_config.json
|
94
|
+
- test/helper.rb
|
95
|
+
- test/scanner_test.rb
|