guard-autoupload 0.3.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 6e16faa42eba0a9ffb386ddb02c5139554cba0ad
4
+ data.tar.gz: 89652a63835b3d2869b979423c512e0248bfcecd
5
+ SHA512:
6
+ metadata.gz: a8206ff9cddcb9bc16e0651362d11aa95ff8501eaf8a06a7319b330e0a9f320c77923596967a45c9dbeebbcd0e392360fce7c74968d9576f6b9f869d88844afa
7
+ data.tar.gz: 71655bc8a80248a5fafe4aa7011e14de66d88c01f7fad686d0635a5b4d54c32364d7e4b38911795defcdbb5f0361bda9bbe682ae25cea769a91f12f313b2b0ae
data/.gitattributes ADDED
@@ -0,0 +1,22 @@
1
+ # Auto detect text files and perform LF normalization
2
+ * text=auto
3
+
4
+ # Custom for Visual Studio
5
+ *.cs diff=csharp
6
+ *.sln merge=union
7
+ *.csproj merge=union
8
+ *.vbproj merge=union
9
+ *.fsproj merge=union
10
+ *.dbproj merge=union
11
+
12
+ # Standard to msysgit
13
+ *.doc diff=astextplain
14
+ *.DOC diff=astextplain
15
+ *.docx diff=astextplain
16
+ *.DOCX diff=astextplain
17
+ *.dot diff=astextplain
18
+ *.DOT diff=astextplain
19
+ *.pdf diff=astextplain
20
+ *.PDF diff=astextplain
21
+ *.rtf diff=astextplain
22
+ *.RTF diff=astextplain
data/.gitignore ADDED
@@ -0,0 +1,166 @@
1
+ #################
2
+ ## Eclipse
3
+ #################
4
+
5
+ *.pydevproject
6
+ .project
7
+ .metadata
8
+ bin/
9
+ tmp/
10
+ *.tmp
11
+ *.bak
12
+ *.swp
13
+ *~.nib
14
+ local.properties
15
+ .classpath
16
+ .settings/
17
+ .loadpath
18
+
19
+ # External tool builders
20
+ .externalToolBuilders/
21
+
22
+ # Locally stored "Eclipse launch configurations"
23
+ *.launch
24
+
25
+ # CDT-specific
26
+ .cproject
27
+
28
+ # PDT-specific
29
+ .buildpath
30
+
31
+
32
+ #################
33
+ ## Visual Studio
34
+ #################
35
+
36
+ ## Ignore Visual Studio temporary files, build results, and
37
+ ## files generated by popular Visual Studio add-ons.
38
+
39
+ # User-specific files
40
+ *.suo
41
+ *.user
42
+ *.sln.docstates
43
+
44
+ # Build results
45
+ [Dd]ebug/
46
+ [Rr]elease/
47
+ *_i.c
48
+ *_p.c
49
+ *.ilk
50
+ *.meta
51
+ *.obj
52
+ *.pch
53
+ *.pdb
54
+ *.pgc
55
+ *.pgd
56
+ *.rsp
57
+ *.sbr
58
+ *.tlb
59
+ *.tli
60
+ *.tlh
61
+ *.tmp
62
+ *.vspscc
63
+ .builds
64
+ *.dotCover
65
+
66
+ ## TODO: If you have NuGet Package Restore enabled, uncomment this
67
+ #packages/
68
+
69
+ # Visual C++ cache files
70
+ ipch/
71
+ *.aps
72
+ *.ncb
73
+ *.opensdf
74
+ *.sdf
75
+
76
+ # Visual Studio profiler
77
+ *.psess
78
+ *.vsp
79
+
80
+ # ReSharper is a .NET coding add-in
81
+ _ReSharper*
82
+
83
+ # Installshield output folder
84
+ [Ee]xpress
85
+
86
+ # DocProject is a documentation generator add-in
87
+ DocProject/buildhelp/
88
+ DocProject/Help/*.HxT
89
+ DocProject/Help/*.HxC
90
+ DocProject/Help/*.hhc
91
+ DocProject/Help/*.hhk
92
+ DocProject/Help/*.hhp
93
+ DocProject/Help/Html2
94
+ DocProject/Help/html
95
+
96
+ # Click-Once directory
97
+ publish
98
+
99
+ # Others
100
+ [Bb]in
101
+ [Oo]bj
102
+ sql
103
+ TestResults
104
+ *.Cache
105
+ ClientBin
106
+ stylecop.*
107
+ ~$*
108
+ *.dbmdl
109
+ Generated_Code #added for RIA/Silverlight projects
110
+
111
+ # Backup & report files from converting an old project file to a newer
112
+ # Visual Studio version. Backup files are not needed, because we have git ;-)
113
+ _UpgradeReport_Files/
114
+ Backup*/
115
+ UpgradeLog*.XML
116
+
117
+
118
+
119
+ ############
120
+ ## Windows
121
+ ############
122
+
123
+ # Windows image file caches
124
+ Thumbs.db
125
+
126
+ # Folder config file
127
+ Desktop.ini
128
+
129
+
130
+ #############
131
+ ## Python
132
+ #############
133
+
134
+ *.py[co]
135
+
136
+ # Packages
137
+ *.egg
138
+ *.egg-info
139
+ dist
140
+ build
141
+ eggs
142
+ parts
143
+ bin
144
+ var
145
+ sdist
146
+ develop-eggs
147
+ .installed.cfg
148
+
149
+ # Installer logs
150
+ pip-log.txt
151
+
152
+ # Unit test / coverage reports
153
+ .coverage
154
+ .tox
155
+
156
+ #Translations
157
+ *.mo
158
+
159
+ #Mr Developer
160
+ .mr.developer.cfg
161
+
162
+ # Mac crap
163
+ .DS_Store
164
+
165
+ # Ignore built gems
166
+ *.gem
data/Gemfile ADDED
File without changes
data/README.md ADDED
@@ -0,0 +1,56 @@
1
+ guard-autoupload
2
+ ================
3
+
4
+ Autoupload plugin used for uploading all local changes to remote host.
5
+ Uses either SFTP or FTP.
6
+
7
+ Usage
8
+ -----
9
+
10
+ Sample guardfile:
11
+
12
+ opts = {
13
+ :protocol => :scp, # Protocol used to connect to remote host.
14
+ # Possible values are :scp, :sftp and :ftp.
15
+ # Of these :scp is the preferred one for
16
+ # its stability.
17
+ :host => "remote_host",
18
+ :user => "username",
19
+ :password => "password",
20
+ :remote => "remote_path",
21
+ :verbose => false, # if true you get all outputs
22
+ :quiet => false # if true outputs only on exceptions.
23
+ }
24
+
25
+ guard :autoupload, opts do
26
+ watch(/^((?!Guardfile$).)*$/)
27
+ # Matches every other file but Guardfile. This way we don't
28
+ # accidentally upload the credentials.
29
+ end
30
+
31
+ Dependencies
32
+ ------------
33
+
34
+ - guard
35
+ - Net::SFTP
36
+ - Net::SSH::Simple
37
+
38
+ Installation
39
+ ------------
40
+
41
+ For now you need to install `guard-autoupload` by building the gem manually
42
+ and installing from that:
43
+
44
+ gem build guard-autoupload.gemspec
45
+ gem install guard-autoupload-0.3.4.gem
46
+
47
+ Author
48
+ ------
49
+
50
+ This guard plugin was written by Jyrki Lilja and is used at FocusFlow.
51
+ The code is hevily based on [vincenthu's guard-flopbox][gsftp] and
52
+ [bgarret's guard-ftpsync][gftp].
53
+
54
+ [gsftp]: https://github.com/vincentchu/guard-flopbox
55
+ [gftp]: https://github.com/bgarret/guard-ftpsync
56
+
data/Rakefile ADDED
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "guard-autoupload"
6
+ s.version = "0.3.4"
7
+ s.authors = ["Jyrki Lilja"]
8
+ s.email = ["jyrki dot lilja at outlook dot com"]
9
+ s.homepage = "https://github.com/jyrkij/guard-autosync"
10
+ s.summary = %q{Autoupload plugin - uploads local changes to remote host.}
11
+ s.description = %q{Uses either SFTP or FTP.}
12
+
13
+ s.rubyforge_project = "guard-autoupload"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_dependency('guard')
21
+ s.add_dependency('net-sftp')
22
+ s.add_dependency('net-ssh-simple')
23
+ end
@@ -0,0 +1,45 @@
1
+ require 'net/ftp'
2
+
3
+ class FTPSession
4
+ RESPAWN_INTERVAL = 60 # in seconds
5
+
6
+ def initialize(host, user, password)
7
+ @session = Net::FTP.new
8
+ @host = host
9
+ @user = user
10
+ @password = password
11
+ @last_timestamp = Time.new(0)
12
+ @session.connect(@host)
13
+ @session.login(@user, @password)
14
+ end
15
+
16
+ def upload!(local, remote)
17
+ remote { @session.putbinaryfile(local, remote) }
18
+ end
19
+
20
+ def mkdir!(dir)
21
+ remote { @session.mkdir(dir) }
22
+ end
23
+
24
+ def remove!(remote)
25
+ remote { @session.delete(remote) }
26
+ end
27
+
28
+ def rmdir!(dir)
29
+ remote { @session.rmdir(dir) }
30
+ end
31
+
32
+ private
33
+
34
+ def remote
35
+ command_start_timestamp = Time.now
36
+ if (command_start_timestamp - @last_timestamp > RESPAWN_INTERVAL)
37
+ @session.close unless @session.last_response == nil
38
+ @session.connect(@host)
39
+ @session.login(@user, @password)
40
+ end
41
+ ret = yield
42
+ @last_timestamp = Time.now
43
+ ret
44
+ end
45
+ end
@@ -0,0 +1,108 @@
1
+ require 'net/ssh/simple'
2
+
3
+ class SCPSession
4
+ def initialize(host, user, password, caller_ref)
5
+ @host = host
6
+ @user = user
7
+ @password = password.clone
8
+ @caller = caller_ref
9
+ @retry_count = 0
10
+ @max_retries = 1
11
+ end
12
+
13
+ def ss
14
+ Thread.current[:simplessh] ||= Net::SSH::Simple.new({:user => @user, :password => @password.clone})
15
+ end
16
+
17
+ def upload!(local, remote)
18
+ begin
19
+ ss.scp_put "#{@host}", "#{local}", "#{remote}"
20
+ # This shouldn't be run if we get an exception
21
+ @retry_count = 0
22
+ rescue Net::SSH::Simple::Error => e
23
+ case e.wrapped
24
+ when Errno::ECONNRESET, Net::SSH::Disconnect
25
+ raise e if @retry_count >= @max_retries
26
+ @retry_count += 1
27
+ @caller.log "Failed uploading and will try again."
28
+ @caller.log "The reason was #{e}" unless @caller.quiet?
29
+ close
30
+ retry
31
+ else
32
+ raise e
33
+ end
34
+ end
35
+ end
36
+
37
+ def mkdir!(dir)
38
+ begin
39
+ check_exists = ss.ssh "#{@host}", "ls -ld #{dir}"
40
+ ss.ssh "#{@host}", "mkdir #{dir}" if check_exists.exit_code
41
+ # This shouldn't be run if we get an exception
42
+ @retry_count = 0
43
+ rescue Net::SSH::Simple::Error => e
44
+ case e.wrapped
45
+ when Errno::ECONNRESET, Net::SSH::Disconnect
46
+ raise e if @retry_count >= @max_retries
47
+ @retry_count += 1
48
+ @caller.log "Failed making directory and will try again."
49
+ @caller.log "The reason was #{e}" unless @caller.quiet?
50
+ close
51
+ retry
52
+ else
53
+ raise e
54
+ end
55
+ end
56
+ end
57
+
58
+ def remove!(remote)
59
+ begin
60
+ ss.ssh @host, "rm #{remote}"
61
+ # This shouldn't be run if we get an exception
62
+ @retry_count = 0
63
+ rescue Net::SSH::Simple::Error => e
64
+ case e.wrapped
65
+ when Errno::ECONNRESET, Net::SSH::Disconnect
66
+ raise e if @retry_count >= @max_retries
67
+ @retry_count += 1
68
+ @caller.log "Failed removing file and will try again."
69
+ @caller.log "The reason was #{e}" unless @caller.quiet?
70
+ close
71
+ retry
72
+ else
73
+ raise e
74
+ end
75
+ end
76
+ end
77
+
78
+ def rmdir!(dir)
79
+ throw NotImplementedError
80
+ end
81
+
82
+ def ls!(dir)
83
+ begin
84
+ ss.ssh @host, "ls #{dir}"
85
+ # This shouldn't be run if we get an exception
86
+ @retry_count = 0
87
+ rescue Net::SSH::Simple::Error => e
88
+ case e.wrapped
89
+ when Errno::ECONNRESET, Net::SSH::Disconnect
90
+ raise e if @retry_count >= @max_retries
91
+ puts @password
92
+ exit
93
+ @retry_count += 1
94
+ @caller.log "Failed listing directory contents and will try again."
95
+ @caller.log "The reason was #{e}" unless @caller.quiet?
96
+ close
97
+ retry
98
+ else
99
+ raise e
100
+ end
101
+ end
102
+ end
103
+
104
+ def close
105
+ ss.close
106
+ Thread.current[:simplessh] = nil
107
+ end
108
+ end
@@ -0,0 +1,61 @@
1
+ require 'net/sftp'
2
+
3
+ class SFTPSession
4
+ def initialize(host, user, password, caller_ref)
5
+ @host = host
6
+ @user = user
7
+ @password = password
8
+ @session = Net::SFTP.start(
9
+ @host,
10
+ @user,
11
+ :password => @password
12
+ )
13
+ @caller = caller_ref
14
+ end
15
+
16
+ def upload!(local, remote)
17
+ remote { @session.upload!(local, remote) }
18
+ end
19
+
20
+ def mkdir!(dir)
21
+ begin
22
+ remote { @session.lstat!(dir) }
23
+ exists = true
24
+ rescue Net::SFTP::StatusException
25
+ exists = false
26
+ end
27
+ remote { @session.mkdir!(dir) } unless exists
28
+ end
29
+
30
+ def remove!(remote)
31
+ stat = remote { @session.lstat!(remote) }
32
+ remote { @session.remove!(remote) } if stat.file?
33
+ remote { @session.rmdir!(remote) } if stat.directory?
34
+ end
35
+
36
+ def rmdir!(dir)
37
+ remote { @session.rmdir!(dir) }
38
+ end
39
+
40
+ private
41
+
42
+ def remote
43
+ begin
44
+ ret = yield
45
+ rescue => e
46
+ case e
47
+ when Errno::ECONNRESET
48
+ @caller.log "Connection resetted by remote. Reconnecting." unless @caller.quiet?
49
+ @session = Net::SFTP.start(
50
+ @host,
51
+ @user,
52
+ :password => @password
53
+ )
54
+ ret = yield
55
+ else
56
+ raise
57
+ end
58
+ end
59
+ ret
60
+ end
61
+ end
@@ -0,0 +1,20 @@
1
+ # Configuartion Options for guard-autoupload
2
+
3
+ opts = {
4
+ :protocol => :scp, # Protocol used to connect to remote host.
5
+ # Possible values are :scp, :sftp and :ftp.
6
+ # Of these :scp is the preferred one for
7
+ # its stability.
8
+ :host => "remote_host",
9
+ :user => "username",
10
+ :password => "password",
11
+ :remote => "remote_path",
12
+ :verbose => false, # if true you get all outputs
13
+ :quiet => false # if true outputs only on exceptions.
14
+ }
15
+
16
+ guard :autoupload, opts do
17
+ watch(/^((?!Guardfile$).)*$/)
18
+ # Matches every other file but Guardfile. This way we don't
19
+ # accidentally upload the credentials.
20
+ end
@@ -0,0 +1,133 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ require 'guard'
4
+ require 'guard/guard'
5
+ require 'autoupload/scpsession.rb'
6
+ require 'autoupload/sftpsession.rb'
7
+ require 'autoupload/ftpsession.rb'
8
+
9
+ module Guard
10
+ class Autoupload < Guard
11
+ def initialize(watchers = [], options = {})
12
+ super
13
+
14
+ @instance = self
15
+ if options[:protocol] == :scp
16
+ @session = SCPSession.new(
17
+ options[:host],
18
+ options[:user],
19
+ options[:password],
20
+ self
21
+ )
22
+ elsif options[:protocol] == :sftp
23
+ @session = SFTPSession.new(
24
+ options[:host],
25
+ options[:user],
26
+ options[:password],
27
+ @instance
28
+ )
29
+ elsif options[:protocol] == :ftp
30
+ @session = FTPSession.new(
31
+ options[:host],
32
+ options[:user],
33
+ options[:password]
34
+ )
35
+ else
36
+ throw :task_has_failed
37
+ end
38
+
39
+ @remote = options[:remote]
40
+ @local = Dir.pwd
41
+ @verbose = options[:verbose]
42
+ @quiet = options[:quiet] unless verbose?
43
+
44
+ options[:password].gsub!(/./, '*') if options.include? :password
45
+ log "Initialized with watchers #{watchers.inspect}" if verbose?
46
+ log "Initialized with options #{options.inspect}" unless quiet?
47
+ end
48
+
49
+ def run_on_change(paths)
50
+ paths.each do |path|
51
+ local_file = File.join(@local, path)
52
+ remote_file = File.join(@remote, path)
53
+
54
+ attempts = 0
55
+
56
+ begin
57
+ log "Upload #{local_file} => #{remote_file}" if verbose?
58
+ @session.upload!(local_file, remote_file)
59
+ log "Uploaded #{path}" unless quiet?
60
+ rescue => ex
61
+ log "Exception on uploading #{path}\n#{ex.inspect}"
62
+ log ex.backtrace.join("\n") if verbose?
63
+ attempts += 1
64
+ remote_dir = File.dirname(remote_file)
65
+ recursively_create_dirs(remote_dir)
66
+ retry if attempts < 3
67
+ log "Exceeded 3 attempts to upload #{path}"
68
+ throw :task_has_failed
69
+ end
70
+ end
71
+
72
+ msg = "Uploaded:\n#{paths.join("\n")}"
73
+ ::Guard::Notifier.notify msg, :title => "Uploaded"
74
+ end
75
+
76
+ def run_on_removals(paths)
77
+ paths.each do |path|
78
+ remote_file = File.join(@remote, path)
79
+
80
+ begin
81
+ log "Delete #{remote_file}" if verbose?
82
+ @session.remove!(remote_file)
83
+ rescue => ex
84
+ log "Exception on deleting #{path}\n#{ex.inspect}"
85
+ log ex.backtrace.join("\n") if verbose?
86
+ end
87
+
88
+ log "Deleted #{path}" unless quiet?
89
+ end
90
+
91
+ msg = "Deleted:\n#{paths.join("\n")}"
92
+ ::Guard::Notifier.notify msg, :title => "Deleted"
93
+ end
94
+
95
+ def verbose?
96
+ @verbose || false
97
+ end
98
+
99
+ def quiet?
100
+ @quiet || false
101
+ end
102
+
103
+ def log(message)
104
+ puts "[#{Time.now}] #{message}"
105
+ end
106
+
107
+ def stop
108
+ log "Tearing down connections" unless quiet?
109
+ if @session.is_a? SCPSession
110
+ @session.close
111
+ end
112
+ end
113
+
114
+ private
115
+
116
+ def recursively_create_dirs(remote_dir)
117
+ new_dir = @remote
118
+ remote_dir.gsub(@remote, "").split("/").each do |dir|
119
+ new_dir = File.join(new_dir, dir)
120
+
121
+ begin
122
+ log "Creating #{new_dir}" if verbose?
123
+ @session.mkdir!(new_dir)
124
+ rescue => ex
125
+ log "Cannot create directory #{new_dir}\n#{ex.inspect}"
126
+ log ex.backtrace.join("\n") if verbose?
127
+ end
128
+ end
129
+
130
+ log "Created directory #{remote_dir}" unless quiet?
131
+ end
132
+ end
133
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: guard-autoupload
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.4
5
+ platform: ruby
6
+ authors:
7
+ - Jyrki Lilja
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-04-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: guard
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: net-sftp
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-ssh-simple
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Uses either SFTP or FTP.
56
+ email:
57
+ - jyrki dot lilja at outlook dot com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - .gitattributes
63
+ - .gitignore
64
+ - Gemfile
65
+ - README.md
66
+ - Rakefile
67
+ - guard-autoupload.gemspec
68
+ - lib/guard/autoupload.rb
69
+ - lib/guard/autoupload/ftpsession.rb
70
+ - lib/guard/autoupload/scpsession.rb
71
+ - lib/guard/autoupload/sftpsession.rb
72
+ - lib/guard/autoupload/templates/Guardfile
73
+ homepage: https://github.com/jyrkij/guard-autosync
74
+ licenses: []
75
+ metadata: {}
76
+ post_install_message:
77
+ rdoc_options: []
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
85
+ required_rubygems_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ requirements: []
91
+ rubyforge_project: guard-autoupload
92
+ rubygems_version: 2.0.3
93
+ signing_key:
94
+ specification_version: 4
95
+ summary: Autoupload plugin - uploads local changes to remote host.
96
+ test_files: []