savedatasync 0.1.2

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: 98c3e79e601a2a344ead97ff13b53ab16a92d8c7
4
+ data.tar.gz: 6a2a5920b1a018fd665eb674b31480c0327e4372
5
+ SHA512:
6
+ metadata.gz: 877b51981b54009945fabc99f547148b27da6a3c89ba7724fd9aa9628f3c3ab68df2d5366d125f8250fa80bb9f04cc7847c57edcb59ee6ea5fbb8fc3087db1ee
7
+ data.tar.gz: f1060c69611d05449947983d71393c86c31399771d25065fd92775b6d2ab1ce1db377893ea580754aba179acebb3d59d8a83c0b689be332bcf2fad26152be09b
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in savedatasync.gemspec
4
+ gemspec
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Kensuke Sawada
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,13 @@
1
+ # Savedata Synchronizer
2
+
3
+ ## Install
4
+ ```
5
+ $ git clone https://github.com/sawaken/savedatasync.git
6
+ $ cd savedatasync
7
+ $ rake install
8
+ ```
9
+
10
+ ## Usage
11
+ ```
12
+ $ sdsync -h
13
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'savedatasync'
5
+ Version = Savedatasync::VERSION
6
+ Savedatasync::Command.from_argv(ARGV).run
@@ -0,0 +1,189 @@
1
+ require "savedatasync/version"
2
+ require "savedatasync/usage"
3
+ require "fileutils"
4
+ require 'optparse'
5
+
6
+ module Savedatasync
7
+ class Command < Struct.new(
8
+ :sub_command, :force, :title, :remote_dir_path, :local_path, :remote_filename
9
+ )
10
+
11
+ def self.from_argv(argv)
12
+ com = extract_argv(new, argv.map { |a| a.encode("UTF-8") })
13
+ com.title ||= File.basename(File.dirname(com.local_path)).encode("UTF-8")
14
+ com.remote_dir_path ||= File.expand_path(default_remote_dir).encode("UTF-8")
15
+ com.remote_filename ||= File.basename(com.local_path).encode("UTF-8")
16
+ return com
17
+ end
18
+
19
+ def self.default_remote_dir
20
+ ENV['sdsync_remote_dir'].encode("UTF-8") || "#{Dir.home.encode("UTF-8")}/Dropbox/sdsync"
21
+ end
22
+
23
+ def self.extract_argv(com, argv)
24
+ opt_parser = OptionParser.new do |parse|
25
+ parse.banner = Savedatasync::USAGE
26
+ desc = 'force to execute even if there is an existing file'
27
+ parse.on('--force', desc) do
28
+ com.force = true
29
+ end
30
+ desc = 'specify title. basename(dirname(savedata-file)) is used as default'
31
+ parse.on('--title=TITLE', desc) do |title|
32
+ com.title = title
33
+ end
34
+ desc = "specify the path of remote directory. ENV['sdsync_remote_dir'] or ~/Dropbox/sdsync is used as default"
35
+ parse.on('--remote=PATH', desc) do |path|
36
+ com.remote_dir_path = path
37
+ end
38
+ end
39
+ sub_command, *args_without_option = opt_parser.parse(argv)
40
+ unless ['get', 'put', 'cut', 'status'].include?(sub_command)
41
+ STDERR.puts "invalid subcommand #{sub_command}"
42
+ STDERR.puts opt_parser.help
43
+ exit(1)
44
+ end
45
+ unless 1 <= args_without_option.size && args_without_option.size <= 2
46
+ STDERR.puts "invalid length of arguments"
47
+ STDERR.puts opt_parser.help
48
+ print_usage
49
+ exit(1)
50
+ end
51
+ com.sub_command = sub_command
52
+ com.local_path = File.expand_path(args_without_option[0]).encode("UTF-8")
53
+ com.remote_filename = args_without_option[1]
54
+ return com
55
+ rescue OptionParser::InvalidOption => error
56
+ STDERR.puts error.message
57
+ STDERR.puts opt_parser.help
58
+ exit(1)
59
+ end
60
+
61
+ def run
62
+ op = Operator.new(title, force, remote_dir_path)
63
+ case sub_command
64
+ when 'put'
65
+ op.put(local_path, remote_filename)
66
+ when 'get'
67
+ op.get(local_path, remote_filename)
68
+ when 'cut'
69
+ op.cut(local_path, remote_filename)
70
+ when 'status'
71
+ op.status(local_path, remote_filename)
72
+ end
73
+ rescue Operator::Error => err
74
+ STDERR.puts err.message
75
+ exit(1)
76
+ end
77
+ end
78
+
79
+ class Operator
80
+ Error = Class.new(StandardError)
81
+
82
+ def initialize(title, force, remote_dir_path)
83
+ @title = title
84
+ @force = force
85
+ @remote_dir_path = remote_dir_path
86
+ title_dir_path = File.expand_path(@remote_dir_path + '/' + @title).encode("UTF-8")
87
+ unless File.directory?(@remote_dir_path)
88
+ raise Error.new("remote dir #{@remote_dir_path} does not exist")
89
+ end
90
+ FileUtils.mkdir(title_dir_path) unless File.exist?(title_dir_path)
91
+ end
92
+
93
+ def put(local_path, remote_filename)
94
+ remote_path = construct_remote_path(local_path, remote_filename)
95
+ lstatus = local_status(local_path, remote_path)
96
+ rstatus = remote_status(remote_path)
97
+ case lstatus
98
+ when :entity
99
+ if rstatus == :entity
100
+ unless @force
101
+ raise Error.new("remote file '#{remote_path}' exists. use -f to force")
102
+ end
103
+ FileUtils.rm_r(remote_path)
104
+ end
105
+ FileUtils.mv(local_path, remote_path)
106
+ FileUtils.symlink(remote_path, local_path)
107
+ return true
108
+ when :empty
109
+ raise Error.new("local file '#{local_path}' is empty")
110
+ when :valid_link
111
+ if rstatus == :empty
112
+ raise Error.new("local file '#{local_path}' is broken link. remove it to continue")
113
+ end
114
+ return true
115
+ when :invalid_link
116
+ raise Error.new("local file '#{local_path} is broken link. remove it to continue")
117
+ end
118
+ end
119
+
120
+ def get(local_path, remote_filename)
121
+ remote_path = construct_remote_path(local_path, remote_filename)
122
+ lstatus = local_status(local_path, remote_path)
123
+ rstatus = remote_status(remote_path)
124
+ case lstatus
125
+ when :entity
126
+ if rstatus == :empty
127
+ raise Error.new("remote file '#{remote_path}' is empty")
128
+ end
129
+ unless @force
130
+ raise Error.new("local file '#{local_path}' exists. use -f to force")
131
+ end
132
+ FileUtils.rm_rf(local_path)
133
+ FileUtils.symlink(remote_path, local_path)
134
+ return true
135
+ when :empty
136
+ if rstatus == :empty
137
+ raise Error.new("remote file '#{remote_path}' is empty")
138
+ end
139
+ FileUtils.symlink(remote_path, local_path)
140
+ return true
141
+ when :valid_link
142
+ if rstatus == :empty
143
+ raise Error.new("local file '#{local_path}' is broken link. remove it to continue")
144
+ end
145
+ return true
146
+ when :invalid_link
147
+ raise Error.new("local file '#{local_path} is broken link. remove it to continue")
148
+ end
149
+ end
150
+
151
+ def cut(local_path, remote_filename)
152
+ remote_path = construct_remote_path(local_path, remote_filename)
153
+ lstatus = local_status(local_path, remote_path)
154
+ rstatus = remote_status(remote_path)
155
+ unless lstatus == :valid_link && rstatus == :entity
156
+ raise Error.new("cannot cut un-synced file")
157
+ end
158
+ FileUtils.rm_r(local_path)
159
+ FileUtils.cp_r(remote_path, local_path)
160
+ return true
161
+ end
162
+
163
+ def status(local_path, remote_filename)
164
+ remote_path = construct_remote_path(local_path, remote_filename)
165
+ lstatus = local_status(local_path, remote_path)
166
+ rstatus = remote_status(remote_path)
167
+ STDERR.puts "[#{@title}] #{local_path} (#{lstatus}) <==> #{remote_path} (#{rstatus})"
168
+ return true
169
+ end
170
+
171
+ private
172
+
173
+ def local_status(local_path, remote_path)
174
+ if File.symlink?(local_path)
175
+ File.readlink(local_path).encode("UTF-8") == remote_path ? :valid_link : :invalid_link
176
+ else
177
+ File.exist?(local_path) ? :entity : :empty
178
+ end
179
+ end
180
+
181
+ def remote_status(remote_path)
182
+ File.exist?(remote_path) ? :entity : :empty
183
+ end
184
+
185
+ def construct_remote_path(local_path, remote_filename)
186
+ File.expand_path("#{@remote_dir_path}/#{@title}/#{remote_filename}").encode("UTF-8")
187
+ end
188
+ end
189
+ end
@@ -0,0 +1,42 @@
1
+ module Savedatasync
2
+ USAGE = <<-TXT
3
+ usage: sdsync <subcommand> [options] savedata-file [savedata-name]
4
+
5
+ <subcommand>:
6
+ get make a link using the entity in remote
7
+ put make a link using the entity in local
8
+ cut delete the link and copy the entity from remote
9
+ status print status of local and remote
10
+
11
+ <get> behavior:
12
+ | local/remote | entity | empty |
13
+ |---------------|-------------|-----------|
14
+ | invalid_link | error | error |
15
+ | valid_link | do nothing | error |
16
+ | entity | do if -f | error |
17
+ | empty | do | error |
18
+
19
+ <put> behavior:
20
+ | local/remote | entity | empty |
21
+ |---------------|-------------|-----------|
22
+ | invalid_link | error | error |
23
+ | valid_link | do nothing | error |
24
+ | entity | do if -f | do |
25
+ | empty | error | error |
26
+
27
+ <cut> behavior:
28
+ | local/remote | entity | empty |
29
+ |---------------|-------------|-----------|
30
+ | invalid_link | error | error |
31
+ | valid_link | do | error |
32
+ | entity | error | error |
33
+ | empty | error | error |
34
+
35
+ arguments:
36
+ savedata-file path of savedata file or directory to target
37
+ savedata-name name of savedata file or directory to store in remote
38
+ savedata-file's basename is used as default
39
+
40
+ [options]:
41
+ TXT
42
+ end
@@ -0,0 +1,3 @@
1
+ module Savedatasync
2
+ VERSION = "0.1.2"
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'savedatasync/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "savedatasync"
8
+ spec.version = Savedatasync::VERSION
9
+ spec.authors = ["Kensuke Sawada"]
10
+ spec.email = ["sasasawada@gmail.com"]
11
+
12
+ spec.summary = %q{Savedata Synchronizer}
13
+ spec.homepage = "https://github.com/sawaken/savedatasync"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
17
+ f.match(%r{^(test|spec|features)/})
18
+ end
19
+ spec.bindir = "exe"
20
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
21
+ spec.require_paths = ["lib"]
22
+
23
+ spec.add_development_dependency "bundler", "~> 1.13"
24
+ spec.add_development_dependency "rake", "~> 10.0"
25
+ spec.add_development_dependency "rspec", "~> 3.0"
26
+ end
metadata ADDED
@@ -0,0 +1,97 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: savedatasync
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.2
5
+ platform: ruby
6
+ authors:
7
+ - Kensuke Sawada
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-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.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
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
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ description:
56
+ email:
57
+ - sasasawada@gmail.com
58
+ executables:
59
+ - sdsync
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - Gemfile
65
+ - LICENSE.txt
66
+ - README.md
67
+ - Rakefile
68
+ - exe/sdsync
69
+ - lib/savedatasync.rb
70
+ - lib/savedatasync/usage.rb
71
+ - lib/savedatasync/version.rb
72
+ - savedatasync.gemspec
73
+ homepage: https://github.com/sawaken/savedatasync
74
+ licenses:
75
+ - MIT
76
+ metadata: {}
77
+ post_install_message:
78
+ rdoc_options: []
79
+ require_paths:
80
+ - lib
81
+ required_ruby_version: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ version: '0'
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ requirements: []
92
+ rubyforge_project:
93
+ rubygems_version: 2.6.10
94
+ signing_key:
95
+ specification_version: 4
96
+ summary: Savedata Synchronizer
97
+ test_files: []