guard-symlink 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 9ea5457f511c559688612b1034b2399005a2240b
4
+ data.tar.gz: c226047ebc4e6bd9a4ecbf797fca3fca3d74b842
5
+ SHA512:
6
+ metadata.gz: fd91baae1dd834fcca5d7ff4580e6634b47a3d011f037b18f7baadbf4d4411159d93f9d6f8bb51e6595c4c645b89a80d86f429ee43deb3fd9d93e33f06fc9dae
7
+ data.tar.gz: 4f39727426d0904aab129120f29778e4508180d720972ac36e07619488404f007f46a951ab47a984eda8271b4facf22e4101e8c5970adff7b10885d3dfe6f661
@@ -0,0 +1,40 @@
1
+ # https://github.com/guard/listen/issues/426
2
+ require 'listen'
3
+ require 'listen/record'
4
+
5
+ module Listen
6
+ class Record
7
+ def dir_entries(rel_path)
8
+ subtree =
9
+ if [nil, '', '.'].include? rel_path.to_s
10
+ tree
11
+ else
12
+ sub_dir_entries(rel_path)
13
+ end
14
+
15
+ result = {}
16
+ subtree.each do |key, values|
17
+ # only get data for file entries
18
+ result[key] = values.key?(:mtime) ? values : {}
19
+ end
20
+ result
21
+ end
22
+
23
+ private
24
+
25
+ def sub_dir_entries(rel_path)
26
+ result = {}
27
+ tree.each do |path, meta|
28
+ next unless path.start_with?(rel_path)
29
+
30
+ if path == rel_path
31
+ result.merge!(meta)
32
+ else
33
+ sub_path = path.sub(%r{\A#{rel_path}/?}, '')
34
+ result[sub_path] = meta
35
+ end
36
+ end
37
+ result
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ require 'guard/jobs/pry_wrapper'
2
+
3
+ Pry::Commands.create_command 'unlink_all' do
4
+ group 'Guard'
5
+ description 'Unlink all symlinks of watched directories.'
6
+
7
+ banner <<-BANNER
8
+ Usage: unlink_all <scope>
9
+ Run the Guard plugin `unlink_all` action.
10
+ You may want to specify an optional scope to the action,
11
+ either the name of a Guard plugin or a plugin group.
12
+ BANNER
13
+
14
+ def process(*entries)
15
+ scopes, unknown = ::Guard.state.session.convert_scope(entries)
16
+
17
+ unless unknown.empty?
18
+ output.puts "Unknown scopes: #{unknown.join(', ')}"
19
+ return
20
+ end
21
+
22
+ ::Guard::Runner.new.run(:unlink_all, scopes)
23
+ end
24
+ end
@@ -0,0 +1,3 @@
1
+ guard :symlink, ignore: [] do
2
+ watch(/.*/)
3
+ end
@@ -0,0 +1,7 @@
1
+ require 'guard/compat/plugin'
2
+
3
+ module Guard
4
+ class Symlink < Guard::Plugin
5
+ VERSION = '0.1.0'.freeze
6
+ end
7
+ end
@@ -0,0 +1,189 @@
1
+ require 'guard/compat/plugin'
2
+ require 'guard/symlink/version'
3
+ require 'guard/symlink/bugfix'
4
+ require 'guard/symlink/pry'
5
+
6
+ module Guard
7
+ class Symlink < Guard::Plugin
8
+ def initialize(options = {})
9
+ opts = options.dup
10
+ @ignore = opts.delete(:ignore)
11
+ super(opts)
12
+ end
13
+
14
+ # Called once when Guard starts. Please override initialize method to init stuff.
15
+ #
16
+ # @raise [:task_has_failed] when start has failed
17
+ # @return [Object] the task result
18
+ #
19
+ def start
20
+ watchdirs.each do |directory|
21
+ files = package_files(directory)
22
+ link(files)
23
+ end
24
+ end
25
+
26
+ # Called on file(s) additions that the Guard plugin watches.
27
+ #
28
+ # @param [Array<String>] paths the changes files or paths
29
+ # @raise [:task_has_failed] when run_on_additions has failed
30
+ # @return [Object] the task result
31
+ #
32
+ def run_on_additions(paths)
33
+ link(paths)
34
+ end
35
+
36
+ # Called on file(s) removals that the Guard plugin watches.
37
+ #
38
+ # @param [Array<String>] paths the changes files or paths
39
+ # @raise [:task_has_failed] when run_on_removals has failed
40
+ # @return [Object] the task result
41
+ #
42
+ def run_on_removals(paths)
43
+ unlink(paths)
44
+ end
45
+
46
+ def unlink_all
47
+ watchdirs.each do |directory|
48
+ files = package_files(directory)
49
+ unlink(files)
50
+ end
51
+ end
52
+
53
+ def link(paths)
54
+ paths.each do |entry|
55
+ source_path = ::File.expand_path(entry)
56
+ relative_sub_path = relative_sub_path(source_path)
57
+
58
+ next if @ignore.include?(relative_sub_path)
59
+
60
+ target_path = "#{::Dir.pwd}/#{relative_sub_path}"
61
+ target_directory = ::File.dirname(target_path)
62
+ ensure_directory(target_directory)
63
+
64
+ next if link_exists?(source_path, target_path)
65
+ backup(target_path)
66
+
67
+ create_symlink(source_path, target_path)
68
+ end
69
+ end
70
+
71
+ def unlink(paths)
72
+ target_folders = []
73
+ paths.each do |entry|
74
+ source_path = ::File.expand_path(entry)
75
+ relative_sub_path = relative_sub_path(source_path)
76
+ target_path = "#{::Dir.pwd}/#{relative_sub_path}"
77
+
78
+ next unless link_exists?(source_path, target_path)
79
+ next unless file_removed?(target_path)
80
+
81
+ target_directory = ::File.dirname(target_path)
82
+ next if target_folders.include?(target_directory)
83
+ target_folders.push(target_directory)
84
+ end
85
+
86
+ remove_empty(target_folders)
87
+ end
88
+
89
+ private
90
+
91
+ def remove_empty(directories)
92
+ return if directories.empty?
93
+
94
+ parent_directories = []
95
+ directories.uniq.each do |directory|
96
+ next unless ::File.directory?(directory)
97
+ next unless directory_empty?(directory)
98
+ ::Dir.rmdir(directory)
99
+ ::Guard::Compat::UI.info "Removed empty directory #{directory}"
100
+
101
+ parent_directory = ::File.dirname(directory)
102
+
103
+ next if parent_directories.include?(parent_directory)
104
+ parent_directories.push(parent_directory)
105
+ end
106
+ remove_empty(parent_directories)
107
+ end
108
+
109
+ def file_removed?(path)
110
+ return true if backup_restored?(path)
111
+ ::File.delete(path)
112
+ # p caller
113
+ ::Guard::Compat::UI.info "Removed link #{path}"
114
+ true
115
+ end
116
+
117
+ def package_files(directory)
118
+ ::Dir.glob(directory + '/**/*').reject { |fn| ::File.directory?(fn) }
119
+ end
120
+
121
+ def relative_sub_path(path_org)
122
+ path = path_org.dup
123
+ watchdirs.each do |directory|
124
+ directory += '/'
125
+ next unless path.start_with?(directory)
126
+ path.slice!(directory)
127
+ break
128
+ end
129
+ path
130
+ end
131
+
132
+ def directory_empty?(directory)
133
+ (::Dir.entries(directory) - %w(. ..)).empty?
134
+ end
135
+
136
+ def ensure_directory(dir)
137
+ return if ::File.directory?(dir)
138
+ ::FileUtils.mkdir_p(dir)
139
+ end
140
+
141
+ def create_symlink(source, target)
142
+ if link_exists?(source, target)
143
+ ::File.delete(target)
144
+ return false
145
+ end
146
+ ::File.symlink(source, target)
147
+ ::Guard::Compat::UI.info "Created symlink #{source} -> #{target}"
148
+ end
149
+
150
+ def link_exists?(source, target)
151
+ return false unless ::File.symlink?(target)
152
+ ::File.readlink(target) == source
153
+ end
154
+
155
+ def backup(path)
156
+ return unless ::File.file?(path)
157
+
158
+ backup_file = backup_name(path)
159
+
160
+ if ::File.exist?(backup_file)
161
+ raise "Can't link #{path}, destination and #{backup_suffix} already exist!"
162
+ end
163
+
164
+ ::File.rename(path, backup_file)
165
+ ::Guard::Compat::UI.info "Created backup #{path} -> #{backup_file}"
166
+ end
167
+
168
+ def backup_restored?(path)
169
+ backup_file = backup_name(path)
170
+ return false unless ::File.exist?(backup_file)
171
+ ::File.delete(path)
172
+ ::File.rename(backup_file, path)
173
+ ::Guard::Compat::UI.info "Removed link by restoring backup #{backup_file} -> #{path}"
174
+ true
175
+ end
176
+
177
+ def backup_name(path)
178
+ "#{path}#{backup_suffix}"
179
+ end
180
+
181
+ def backup_suffix
182
+ '.link_backup'
183
+ end
184
+
185
+ def watchdirs
186
+ @watchdirs ||= ::Guard.state.session.watchdirs
187
+ end
188
+ end
189
+ end
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: guard-symlink
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Thorsten Eckel
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-03-14 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: guard-compat
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.1'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.1'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.14'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.14'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description: Guard to symlink a watched folder recursivly into the current.
84
+ email:
85
+ - te@znuny.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - lib/guard/symlink.rb
91
+ - lib/guard/symlink/bugfix.rb
92
+ - lib/guard/symlink/pry.rb
93
+ - lib/guard/symlink/templates/Guardfile
94
+ - lib/guard/symlink/version.rb
95
+ homepage: https://github.com/thorsteneckel/guard-symlink
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.6.8
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: Guard to symlink a watched folder recursivly into the current.
119
+ test_files: []