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.
@@ -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
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in backto.gemspec
4
+ gemspec
5
+
6
+ gem 'minitest', '~> 5.5.0'
7
+ gem 'single_test'
@@ -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.
@@ -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
+
@@ -0,0 +1,9 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+ require 'single_test/tasks'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs.push "lib"
7
+ t.test_files = FileList['test/*_test.rb']
8
+ t.verbose = true
9
+ end
@@ -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
@@ -0,0 +1,9 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require "backto"
4
+
5
+ if ARGV[0]
6
+ Backto.run(ARGV[0])
7
+ else
8
+ puts 'Usage: backto <CONFIG>'
9
+ end
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ module Backto
2
+ VERSION = "0.1.0"
3
+ end
@@ -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
@@ -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
@@ -0,0 +1,5 @@
1
+ {
2
+ "from": "./foo",
3
+ "to": "./bar",
4
+ "verbose": false
5
+ }
@@ -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